diff --git a/README.md b/README.md index 8715d4d91..17aa12446 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,149 @@ -# Duke project template - -This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it. - -## Setting up in Intellij - -Prerequisites: JDK 11, update Intellij to the most recent version. - -1. Open Intellij (if you are not in the welcome screen, click `File` > `Close Project` to close the existing project first) -1. Open the project into Intellij as follows: - 1. Click `Open`. - 1. Select the project directory, and click `OK`. - 1. If there are any further prompts, accept the defaults. -1. Configure the project to use **JDK 11** (not other versions) as explained in [here](https://www.jetbrains.com/help/idea/sdk.html#set-up-jdk).
- In the same dialog, set the **Project language level** field to the `SDK default` option. -3. After that, locate the `src/main/java/Duke.java` file, right-click it, and choose `Run Duke.main()` (if the code editor is showing compile errors, try restarting the IDE). If the setup is correct, you should see something like the below as the output: - ``` - Hello from - ____ _ - | _ \ _ _| | _____ - | | | | | | | |/ / _ \ - | |_| | |_| | < __/ - |____/ \__,_|_|\_\___| - ``` +# Anna + +Anna is a chatbot that helps you to organise your tasks. It can add, +delete and mark done tasks you've listed. It can also help you keep track of deadlines +and calender events. + +Anna runs on a simple CLI interface that is lightweight and cross-platform friendly. +Anna is also designed to be friendly to first time users by being capable of handling missing inputs + +## Setting up + +Prerequisites: JDK 11 +1. Download the ip.jar under 'Releases' +2. Extract the file into a folder you wish to keep it (e.g. `C:\Users\\Desktop\AnnaBot`) +3. Open a terminal (e.g Command Prompt for Windows) and navigate to the previous directory
+4. Run the jar file using command `java -jar ip.jar`
+#### Example (Windows Command Prompt): +``` +C:\Users\user> cd Desktop\AnnaBot +C:\Users\user\Desktop\AnnaBot> java -jar ip.jar +Hi it's Anna! +What do you need to do? +You may load existing data using the load command +``` + +## Commands +To interact with Anna, please use the following commands + +### exit the program: `bye` +This command exits the running instance. +``` +bye +Go away Anna +O-kay bye...... +``` +### view the current tasklist: `list` +`list` will show the current tasklist in order of addition (oldest task first) +``` +todo task1 +Okay! I've added: [T] task1 +event task2 /from today /to tomorrow +Okay! I've added: [E] task2 +list +Here's what we've gotta do: +1. [T][ ] task1 +2. [E][ ] task2 + Start: from today + End: to tomorrow +We currently have 2 tasks +``` + +### Mark task as done: `mark ` +Sets a given task as completed. Yay! +``` +mark 1 +Okay I've marked item 1 as done: +1. [T][X] task1 +``` + +### Mark task as not done: `unmark ` +Sets a given task as not done +``` +unmark 1 +Oh we aren't done with item 1? +1. [T][ ] task1 +``` + +### Create a simple todo task: `todo ` +Creates a standard todo task and adds it into the tasklist +``` +todo task1 +Okay! I've added: [T] task1 +``` +Anna will prompt you if you forget to input the name of the task +``` +todo +What are you referring to? +task1 +Okay! I've added: [T] task1 +``` +### Create a task with a deadline: `deadline /by ` +Creates a task with a deadline and adds it into the tasklist +``` +deadline task2 /by 5 jan +Okay! I've added: [D] task2 +``` +Anna will prompt you for the deadline if it is missing +``` +deadline task2 +When is this due by? +5 jan +Okay! I've added: [D] task2 +``` +### Create a task with start and end dates:
`event /from /to ` +Creates a task with start and end times and adds it into the tasklist +``` +event task3 /from today /to tomorrow +Okay! I've added: [E] task3 +``` +Similarly to `deadline`, Anna will prompt you if you are missing date details +``` +event task3 /to tomorrow +When does this event start? +today +Okay! I've added: [E] task3 +``` +### Remove a task: `delete ` +The given task will be deleted from the tasklist +``` +delete 1 +Okay! I've deleted task: 1 +``` +### Loading and Saving of tasklist +Anna also supports import/export of your tasklist in the form of a .txt file. This can be helpful if you want to refer to the tasklist in a future date! + +`save` exports the current tasklist into a tasklist.txt file +``` +save +Successfully exported TaskList! +Written to: C:\Users\lhyao\Desktop\TaskList.txt +``` +`load` imports a previous tasklist into the program's tasklist
+Anna looks for a `TaskList.txt` file in the same directory to import from +``` +load +Okay! I've added: [D] task2 +Okay! I've added: [D] task2 +Okay! I've added: [E] task3 +Okay! I've added: [E] task3 +Okay! I've added: [T] task1 +``` +## Usage Example + +#### Input Example 1 +`deadline ip /by tonight` + +#### Expected Output 1 +`Okay! I've added: [D] ip` + +#### Input Example 2 +`list` + +#### Expected Output 2 +``` +Here's what we've gotta do: +1. [D][ ] ip + Deadline: tonight +We currently have 1 tasks +``` \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 8077118eb..2bf0ce7b7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,29 +1,149 @@ -# User Guide +# Anna -## Features +Anna is a chatbot that helps you to organise your tasks. It can add, +delete and mark done tasks you've listed. It can also help you keep track of deadlines +and calender events. -### Feature-ABC +Anna runs on a simple CLI interface that is lightweight and cross-platform friendly. +Anna is also designed to be friendly to first time users by being capable of handling missing inputs -Description of the feature. +## Setting up -### Feature-XYZ +Prerequisites: JDK 11 +1. Download the ip.jar under 'Releases' +2. Extract the file into a folder you wish to keep it (e.g. `C:\Users\\Desktop\AnnaBot`) +3. Open a terminal (e.g Command Prompt for Windows) and navigate to the previous directory
+4. Run the jar file using command `java -jar ip.jar`
+#### Example (Windows Command Prompt): +``` +C:\Users\user> cd Desktop\AnnaBot +C:\Users\user\Desktop\AnnaBot> java -jar ip.jar +Hi it's Anna! +What do you need to do? +You may load existing data using the load command +``` -Description of the feature. +## Commands +To interact with Anna, please use the following commands -## Usage +### exit the program: `bye` +This command exits the running instance. +``` +bye +Go away Anna +O-kay bye...... +``` +### view the current tasklist: `list` +`list` will show the current tasklist in order of addition (oldest task first) +``` +todo task1 +Okay! I've added: [T] task1 +event task2 /from today /to tomorrow +Okay! I've added: [E] task2 +list +Here's what we've gotta do: +1. [T][ ] task1 +2. [E][ ] task2 + Start: from today + End: to tomorrow +We currently have 2 tasks +``` -### `Keyword` - Describe action +### Mark task as done: `mark ` +Sets a given task as completed. Yay! +``` +mark 1 +Okay I've marked item 1 as done: +1. [T][X] task1 +``` -Describe the action and its outcome. +### Mark task as not done: `unmark ` +Sets a given task as not done +``` +unmark 1 +Oh we aren't done with item 1? +1. [T][ ] task1 +``` + +### Create a simple todo task: `todo ` +Creates a standard todo task and adds it into the tasklist +``` +todo task1 +Okay! I've added: [T] task1 +``` +Anna will prompt you if you forget to input the name of the task +``` +todo +What are you referring to? +task1 +Okay! I've added: [T] task1 +``` +### Create a task with a deadline: `deadline /by ` +Creates a task with a deadline and adds it into the tasklist +``` +deadline task2 /by 5 jan +Okay! I've added: [D] task2 +``` +Anna will prompt you for the deadline if it is missing +``` +deadline task2 +When is this due by? +5 jan +Okay! I've added: [D] task2 +``` +### Create a task with start and end dates:
`event /from /to ` +Creates a task with start and end times and adds it into the tasklist +``` +event task3 /from today /to tomorrow +Okay! I've added: [E] task3 +``` +Similarly to `deadline`, Anna will prompt you if you are missing date details +``` +event task3 /to tomorrow +When does this event start? +today +Okay! I've added: [E] task3 +``` +### Remove a task: `delete ` +The given task will be deleted from the tasklist +``` +delete 1 +Okay! I've deleted task: 1 +``` +### Loading and Saving of tasklist +Anna also supports import/export of your tasklist in the form of a .txt file. This can be helpful if you want to refer to the tasklist in a future date! -Example of usage: +`save` exports the current tasklist into a tasklist.txt file +``` +save +Successfully exported TaskList! +Written to: C:\Users\lhyao\Desktop\TaskList.txt +``` +`load` imports a previous tasklist into the program's tasklist
+Anna looks for a `TaskList.txt` file in the same directory to import from +``` +load +Okay! I've added: [D] task2 +Okay! I've added: [D] task2 +Okay! I've added: [E] task3 +Okay! I've added: [E] task3 +Okay! I've added: [T] task1 +``` +## Usage Example -`keyword (optional arguments)` +#### Input Example 1 +`deadline ip /by tonight` -Expected outcome: +#### Expected Output 1 +`Okay! I've added: [D] ip` -Description of the outcome. +#### Input Example 2 +`list` +#### Expected Output 2 ``` -expected output -``` +Here's what we've gotta do: +1. [D][ ] ip + Deadline: tonight +We currently have 1 tasks +``` \ No newline at end of file diff --git a/src/main/java/Commands.java b/src/main/java/Commands.java new file mode 100644 index 000000000..f0ce889f1 --- /dev/null +++ b/src/main/java/Commands.java @@ -0,0 +1,178 @@ +import tasktypes.Todo; +import tasktypes.*; + +import java.util.ArrayList; +import java.util.Scanner; + +public class Commands { + + public static final int DEADLINE_PARAM_INDEX = 1; + static final String TASK_NO_EXIST = "Task does not exist!"; + static final String DELETE_TASK_MESSAGE = "Okay! I've deleted task: "; + public static final String DEADLINE_USERINPUT_PREFIX = "/by"; + public static final boolean STATUSTYPE_DONE = true; + static final int STARTDATE_INDEX = 0; + static final int ENDDATE_INDEX = 1; + public static final String SHOWLIST_HEADER = "Here's what we've gotta do:"; + public static final String SEARCH_NO_RESULT = "We don't have that in the list!"; + public static final String INVALID_COMMAND_MESSAGE = "I didn't get that!"; + public static final String EMPTY_TASKLIST_MESSAGE = "We are free! Let's go play!"; + public static final int USERINPUT_DUEDATE_INDEX = 1; + public static final int USERINPUT_DESCRIPTION_INDEX = 0; + public static final int INVALID_INDEX = -99; + + /** + * Prints out a message stating that the input command is not a valid command + */ + public static void invalidCommand() { + System.out.println(INVALID_COMMAND_MESSAGE); + } + + /** + * Shows the current tasklist contents + * Prints out a unique message if the tasklist is empty + */ + public static void showList() { + if (TaskList.getNumTasks() == USERINPUT_DESCRIPTION_INDEX) { + System.out.println(EMPTY_TASKLIST_MESSAGE); + } else { + String showList_footer = "We currently have " + TaskList.getNumTasks() + " tasks"; + Ui.printList(TaskList.getList(), SHOWLIST_HEADER, showList_footer); + } + } + + /** + * Marks a given task in the tasklist as done or not done depending on parameter statusType + * + * @param userInput the input from the user + * @param statusType input true for done, false for notDone + */ + public static void markTask(String userInput, boolean statusType) { + int itemNum = INVALID_INDEX; + try { + itemNum = Ui.getItemNumber(userInput); + } catch (DukeException d) { + System.out.println(d.getMessage()); + } + if (itemNum == INVALID_INDEX) { + return; + } else if (itemNum > USERINPUT_DESCRIPTION_INDEX && itemNum <= TaskList.getNumTasks()) { + if (statusType == STATUSTYPE_DONE) { + TaskList.markDone(itemNum - USERINPUT_DUEDATE_INDEX); + System.out.println("Okay I've marked item " + itemNum + " as done:"); + TaskList.printItem(itemNum - USERINPUT_DUEDATE_INDEX); + } else { + TaskList.markNotDone(itemNum - USERINPUT_DUEDATE_INDEX); + System.out.println("Oh we aren't done with item " + itemNum + "?"); + TaskList.printItem(itemNum - USERINPUT_DUEDATE_INDEX); + } + } else { + System.out.println(TASK_NO_EXIST); + } + } + + /** + * Removes a given task from the tasklist based on the input message + * + * @param userInput user's input + */ + public static void deleteTask(String userInput) { + int itemIndex; + try { + itemIndex = Ui.getItemIndex(userInput); + } catch (DukeException d) { + System.out.println(d.getMessage()); + return; + } + if (itemIndex <= TaskList.getNumTasks() - USERINPUT_DUEDATE_INDEX) { + TaskList.deleteTask(itemIndex); + System.out.println(DELETE_TASK_MESSAGE + (itemIndex + USERINPUT_DUEDATE_INDEX)); + } else { + System.out.println(TASK_NO_EXIST); + } + } + + /** + * takes in user's description and adds a Todo task to the tasklist + * + * @param userInput description of the todo + */ + public static void addTodoTask(String userInput) { + String itemDescription = Ui.getItemDescription(userInput); + Todo newTask = new Todo(itemDescription); + TaskList.addItem(newTask); + } + + /** + * takes in user's description and adds a deadline task to the tasklist + * if the user has not supplied a deadline, method will request for the deadline + * + * @param userInput description of the deadline task + */ + public static void addDeadlineTask(String userInput) { + String itemDescription, dueDate; + if (userInput.contains(DEADLINE_USERINPUT_PREFIX)) { + itemDescription = userInput.split(" ", 2)[DEADLINE_PARAM_INDEX]; + itemDescription = itemDescription.split(DEADLINE_USERINPUT_PREFIX, 2)[USERINPUT_DESCRIPTION_INDEX]; + dueDate = userInput.split(DEADLINE_USERINPUT_PREFIX, 2)[USERINPUT_DUEDATE_INDEX]; + } else { + itemDescription = Ui.getItemDescription(userInput); + dueDate = Ui.getDueDate(userInput); + } + Deadline newTask = new Deadline(itemDescription, dueDate); + TaskList.addItem(newTask); + } + + /** + * takes in user's input and adds an event task to the tasklist + * if the user has not supplied start and/or end dates, method will request for the dates + * + * @param userInput description of the event task + */ + public static void addEventTask(String userInput) { + String itemDescription = Ui.getItemDescription(userInput); + String[] StartEndDates = Ui.getStartEndDates(userInput); + String startDate = StartEndDates[STARTDATE_INDEX]; + String endDate = StartEndDates[ENDDATE_INDEX]; + Event newTask = new Event(itemDescription, startDate, endDate); + TaskList.addItem(newTask); + } + + /** + * Checks if searchTerm can be found inside taskDescription. + * + * @param searchTerm String to be found in the taskDescription + * @param taskDescription String where searchTerm is to be found in + * @return true if taskDescription contains searchTerm + */ + public static boolean containsSearchTerm(String searchTerm, String taskDescription) { + return taskDescription.contains(searchTerm); + } + + /** + * Searches the current tasklist for a user-supplied String + * Will print out the list of items that match the user input if exists. + * Else will print out a no items found message + * + * @param userInput the String to be searched for + */ + public static void searchTask(String userInput) { + String searchTerm = Ui.getItemDescription(userInput); + ArrayList resultsList = new ArrayList<>(); + int searchResults = USERINPUT_DESCRIPTION_INDEX; + for (int i = USERINPUT_DUEDATE_INDEX; i <= TaskList.getNumTasks(); ++i) { + String taskDescription = TaskList.getItem(i - USERINPUT_DUEDATE_INDEX).getDescription(); + if (containsSearchTerm(searchTerm, taskDescription)) { + resultsList.add(TaskList.getItem(i - USERINPUT_DUEDATE_INDEX)); + searchResults += USERINPUT_DUEDATE_INDEX; + } + } + if (searchResults == USERINPUT_DESCRIPTION_INDEX) { + System.out.println(SEARCH_NO_RESULT); + } else { + String resultsList_header = "We have " + searchResults + " results!"; + Ui.printList(resultsList, resultsList_header, ""); + } + } + +} diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 5d313334c..564fbcb88 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,10 +1,30 @@ +import java.util.Scanner; + public class Duke { + public static final String EXIT_CMD = "exit"; + public static final String BYE_CMD = "bye"; public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); + Ui.welcome(); + Scanner in = new Scanner(System.in); + + boolean isExit = false; + while (!isExit) { + String userInput = in.nextLine().trim(); + String inputCommand = Parser.ParseInputCommand(userInput); + switch (inputCommand) { + case EXIT_CMD: + case BYE_CMD: + isExit = true; + Ui.endSavePrompt(); + break; + default: + Parser.ParseCommand(inputCommand,userInput); + break; + } + } } } + + + + diff --git a/src/main/java/DukeException.java b/src/main/java/DukeException.java new file mode 100644 index 000000000..b1ea276ef --- /dev/null +++ b/src/main/java/DukeException.java @@ -0,0 +1,5 @@ +public class DukeException extends Exception { + DukeException(String errorMessage) { + System.out.println(errorMessage); + } +} diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java new file mode 100644 index 000000000..1e2c6daa5 --- /dev/null +++ b/src/main/java/Storage.java @@ -0,0 +1,97 @@ +import tasktypes.Deadline; +import tasktypes.Event; +import tasktypes.Todo; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Scanner; + +public class Storage { + public static final String TASKLIST_EXPORT_PATH = "TaskList.txt"; + public static final String WRITTEN_TO_PATH_PREFIX = "Written to: "; + public static final String SUCCESS_EXPORT = "Successfully exported TaskList!"; + public static final String EXPORT_ERROR_PREFIX = "Error occurred while writing to "; + public static final String TASKTYPE_READ_ERROR = "Error reading TaskType"; + public static final int DESCRIPTION_INDEX = 9; + public static final int DEADLINE_INDEX = 9; + public static final int STARTDATE_INDEX = 6; + public static final int ENDDATE_INDEX = 4; + public static final String EXISTING_DATA_NOT_FOUND = "Existing data not found!"; + + /** + * creates a file in a specified export path + * @return a File object pertaining to the created file + */ + public static File createFile() { + return new File(TASKLIST_EXPORT_PATH); + } + + /** + * finds an existing tasklist.txt file and reads from it to populate the current instance's tasklist + * returns an error message if the existing file does not exist + */ + public static void readFromExistingData() { + File existingData = new File(TASKLIST_EXPORT_PATH); + try { + Scanner s = new Scanner(existingData); + String itemDescription; + while (s.hasNext()) { + String newLine = s.nextLine(); + String TaskType = String.valueOf(newLine.charAt(3)); + + switch (TaskType) { + case (Todo.TYPE_ICON): + itemDescription = newLine.substring(DESCRIPTION_INDEX); + Todo task = new Todo(itemDescription); + TaskList.addItem(task); + break; + case (Deadline.TYPE_ICON): + itemDescription = newLine.substring(DESCRIPTION_INDEX); + String dueDate = s.nextLine().trim(); + dueDate = dueDate.substring(DEADLINE_INDEX); + Deadline deadline = new Deadline(itemDescription, dueDate); + TaskList.addItem(deadline); + break; + case (Event.TYPE_ICON): + itemDescription = newLine.substring(DESCRIPTION_INDEX); + String startDate = s.nextLine().trim(); + startDate = startDate.substring(STARTDATE_INDEX); + String endDate = s.nextLine().trim(); + endDate = endDate.substring(ENDDATE_INDEX); + Event event = new Event(itemDescription,startDate, endDate); + TaskList.addItem(event); + break; + default: + System.out.println(TASKTYPE_READ_ERROR); + return; + } + } + } catch (FileNotFoundException f) { + System.out.println(EXISTING_DATA_NOT_FOUND); + } + } + + /** + * exports the current tasklist into a text file at the specified export path + * + */ + public static void writeToTaskList() { + File exportTaskList = createFile(); + try { + FileWriter writeTaskList = new FileWriter(TASKLIST_EXPORT_PATH); + int numTasks = TaskList.getNumTasks(); + for (int i = 0; i < numTasks; ++i) { + writeTaskList.write(i + 1 + "."); + writeTaskList.write(TaskList.getItem(i).getTask()); + writeTaskList.write(System.lineSeparator()); + } + writeTaskList.close(); + System.out.println(SUCCESS_EXPORT); + System.out.println(WRITTEN_TO_PATH_PREFIX + exportTaskList.getCanonicalPath()); + } catch (IOException e) { + System.out.println(EXPORT_ERROR_PREFIX + exportTaskList.getAbsolutePath()); + } + } +} diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java new file mode 100644 index 000000000..35b11e6e3 --- /dev/null +++ b/src/main/java/TaskList.java @@ -0,0 +1,83 @@ +import tasktypes.Task; + +import java.util.ArrayList; + +public class TaskList { + private static final ArrayList TaskList = new ArrayList<>(10); + private static int NumTasks = 0; + + /** + * Returns the current tasklist + * @return TaskList currently stored in the method + */ + public static ArrayList getList() { + return TaskList; + } + + /** + * Adds a Task to the tasklist, increments the number of tasks in the list then echos the task added + * @param newTask Task to be added to the list + */ + public static void addItem (Task newTask) { + TaskList.add(newTask); + NumTasks += 1; + System.out.println("Okay! I've added: [" + newTask.getTypeIcon() +"] " + newTask.getDescription()); + } + + /** + * gets the number of tasks in the list + * @return the number of tasks in the list currently + */ + public static int getNumTasks() { + return NumTasks; + } + + /** + * marks a task's status as done + * @param index index of the task in the tasklist + */ + public static void markDone (int index) { + if (TaskList.get(index).getStatusIcon().equals(" ")) { + TaskList.get(index).markDone(); + } + } + + /** + * marks a task's status as not done + * @param index index of the task in the tasklist + */ + public static void markNotDone (int index) { + if (TaskList.get(index).getStatusIcon().equals("X")) { + TaskList.get(index).markNotDone(); + } + } + + /** + * get a task item from the tasklist + * @param index index of the task in the tasklist + * @return returns a Task object from the tasklist according to the index + */ + public static Task getItem (int index) { + return TaskList.get(index); + } + + /** + * prints out a task in a pre-set format + * @param index index of the task in the tasklist + */ + public static void printItem (int index) { + System.out.print(index+1 + ". "); + System.out.println(TaskList.get(index).getTask()); + } + + /** + * removes a task from the tasklist and decrements the counter for number of tasks + * @param index index of the task in the tasklist + */ + public static void deleteTask(int index) { + TaskList.remove(index); + NumTasks -= 1; + } + + +} diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java new file mode 100644 index 000000000..96d8ef535 --- /dev/null +++ b/src/main/java/Ui.java @@ -0,0 +1,229 @@ +import tasktypes.Task; +import java.util.ArrayList; +import java.util.InputMismatchException; +import java.util.Scanner; + +public class Ui { + public static final String EXIT_MESSAGE = "Go away Anna\nO-kay bye......"; + static final int DESCRIPTION_INDEX = 1; + public static final String STARTDATE_USERINPUT_PREFIX = "/from"; + public static final String ENDDATE_USERINPUT_PREFIX = "/to"; + public static final String DEADLINE_USERINPUT_PREFIX = "/by"; + static final int STARTDATE_INDEX = 0; + static final int ENDDATE_INDEX = 1; + private static final String WELCOME_MESSAGE = "Hi it's Anna!\nWhat do you need to do?"; + public static final String WELCOME_LOAD_PROMPT = "You may load existing data using the load command"; + public static final String ITEM_NUMBER_PROMPT = "What is the number of the item in the list?"; + public static final String REJECTED_NON_NUMBER_INPUT = "Please enter a number"; + public static final String DUEDATE_PROMPT = "When is this due by?"; + public static final String EVENT_START_PROMPT = "When does this event start?"; + public static final String EVENT_END_PROMPT = "When does this event end?"; + public static final String ITEM_DESCRIPTION_PROMPT = "What are you referring to?"; + public static final int EVENT_STARTMARKER_LENGTH = 5; + public static final int EVENT_ENDMARKER_LENGTH = 3; + public static final int INVALID_INDEX = -99; + public static final String END_SAVE_PROMPT = "Wait, do you want to save the current list?\n Type yes if so"; + + /** + * prints a welcome message on startup. + * Also prompts user if they would like to load an existing file + */ + public static void welcome() { + System.out.println(WELCOME_MESSAGE); + System.out.println(WELCOME_LOAD_PROMPT); + } + + /** + * gets the description from the user for a new task object + * will prompt the user if additional information is required + * @param userInput input string from the user + * @return returns the description of the task + */ + public static String getItemDescription(String userInput) { + Scanner in = new Scanner(System.in); + String description; + try { + description = userInput.split(" ", 2)[DESCRIPTION_INDEX]; + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println(ITEM_DESCRIPTION_PROMPT); + description = in.nextLine().trim(); + } + if (description.contains("/")) { + description = description.split("/",2)[0]; + description = description.trim(); + } + return description; + } + + /** + * gets the item number for the user supplied command to act on + * @param userInput command input from the user + * @return returns number of the item in the tasklist (1-based) + * @throws DukeException if user's input is not valid or out of bounds + */ + public static int getItemNumber(String userInput) throws DukeException { + Scanner in = new Scanner(System.in); + int itemNumber = INVALID_INDEX; + try { + itemNumber = Integer.parseInt(userInput.split(" ", 2)[1]); + } catch (ArrayIndexOutOfBoundsException e) { + Ui.printList(TaskList.getList(),"",""); + System.out.println(ITEM_NUMBER_PROMPT); + try { + itemNumber = in.nextInt(); + } catch (InputMismatchException i) { + throw new DukeException(REJECTED_NON_NUMBER_INPUT); + } + } catch (NumberFormatException n) { + throw new DukeException(REJECTED_NON_NUMBER_INPUT); + } + return itemNumber; + } + + /** + * gets the item index for the user supplied command to act on + * @param userInput command input from the user + * @return returns index of the item in the tasklist (0-based) + * @throws DukeException if user's input is not valid or out of bounds + */ + public static int getItemIndex(String userInput) throws DukeException{ + int itemIndex = INVALID_INDEX; + while (itemIndex <= 0) { + itemIndex = getItemNumber(userInput); + } + return itemIndex - 1; + } + + /** + * gets a duedate for the creation of a new deadline object + * will prompt the user if additional information is required + * @param userInput command input from the user + * @return duedate of the deadline object + */ + public static String getDueDate(String userInput) { + Scanner in = new Scanner(System.in); + String dueDate; + if (userInput.contains(DEADLINE_USERINPUT_PREFIX)) { + dueDate = userInput.substring(userInput.indexOf(DEADLINE_USERINPUT_PREFIX)).trim(); + } else { + System.out.println(DUEDATE_PROMPT); + dueDate = in.nextLine().trim(); + } + return dueDate; + } + + /** + * gets the index of the startdate marker in the user supplied input + * @param userInput user supplied input + * @return index of the startdate marker, else -99 if not found + */ + public static int getStartMarkerIndex(String userInput) { + if (userInput.contains(STARTDATE_USERINPUT_PREFIX)) { + return userInput.indexOf(STARTDATE_USERINPUT_PREFIX); + } else { + return INVALID_INDEX; + } + } + + /** + * gets the index of the enddate marker in the user supplied input + * @param userInput user supplied input + * @return index of the enddate marker, else -99 if not found + */ + public static int getEndMarkerIndex(String userInput) { + if (userInput.contains(ENDDATE_USERINPUT_PREFIX)) { + return userInput.indexOf(ENDDATE_USERINPUT_PREFIX); + } else { + return INVALID_INDEX; + } + } + /** + * gets the startdate from the user supplied input + * will prompt the user to enter the startdate if not found + * @param userInput user supplied command input + * @return startdate of the event + */ + public static String getStartDate(String userInput) { + Scanner in = new Scanner (System.in); + int startMarkerIndex = getStartMarkerIndex(userInput); + int endMarkerIndex = getEndMarkerIndex(userInput); + if (startMarkerIndex == INVALID_INDEX) { + System.out.println(EVENT_START_PROMPT); + return in.nextLine().trim(); + } else { + if (endMarkerIndex == INVALID_INDEX) { + return userInput.substring(startMarkerIndex + EVENT_STARTMARKER_LENGTH).trim(); + } else { + return userInput.substring(startMarkerIndex + EVENT_STARTMARKER_LENGTH,endMarkerIndex).trim(); + } + } + } + + /** + * gets the enddate from the user supplied input + * will prompt the user to enter the enddate if not found + * @param userInput user supplied command input + * @return enddate of the event + */ + public static String getEndDate(String userInput) { + Scanner in = new Scanner (System.in); + int startMarkerIndex = getStartMarkerIndex(userInput); + int endMarkerIndex = getEndMarkerIndex(userInput); + if (endMarkerIndex == INVALID_INDEX) { + System.out.println(EVENT_END_PROMPT); + return in.nextLine().trim(); + } else { + if (startMarkerIndex > endMarkerIndex) { + return userInput.substring(endMarkerIndex + EVENT_ENDMARKER_LENGTH,startMarkerIndex).trim(); + } else { + return userInput.substring(endMarkerIndex + EVENT_ENDMARKER_LENGTH).trim(); + } + } + } + /** + * gets the start and end dates for the creation of a new event object + * will prompt the user if additional information is required + * @param userInput command input from the user + * @return a string array containing the start and end dates respectively + */ + public static String[] getStartEndDates(String userInput) { + String[] StartEndDates = new String[2]; + StartEndDates[STARTDATE_INDEX] = getStartDate(userInput); + StartEndDates[ENDDATE_INDEX] = getEndDate(userInput); + return StartEndDates; + } + + /** + * prints a given arrayList of Tasks with a header and footer if required + * @param itemList arrayList of Task objects + * @param header line to print before the arrayList. input empty string if not required + * @param footer line to print after the arrayList. input empty string if not required + */ + public static void printList(ArrayList itemList, String header, String footer) { + if (!header.isBlank()) { + System.out.println(header); + } + for (int i = 0 ; i < itemList.size(); ++i) { + System.out.print((i+1)+ ". "); + System.out.println(itemList.get(i).getTask()); + } + if (!footer.isBlank()) { + System.out.println(footer); + } + } + /** + * Checks with the user if the data should be saved before shutdown of the program + * prints the exit message afterwards + */ + public static void endSavePrompt() { + Scanner in = new Scanner(System.in); + if (!TaskList.getList().isEmpty()) { + System.out.println(END_SAVE_PROMPT); + String saveDecision = in.nextLine().trim().toLowerCase(); + if (saveDecision.equals("yes")) { + Storage.writeToTaskList(); + } + } + System.out.println(EXIT_MESSAGE); + } +} diff --git a/src/main/java/tasktypes/Deadline.java b/src/main/java/tasktypes/Deadline.java new file mode 100644 index 000000000..7e1ac5f76 --- /dev/null +++ b/src/main/java/tasktypes/Deadline.java @@ -0,0 +1,26 @@ +package tasktypes; + +public class Deadline extends Task { + public static final String TYPE_ICON = "D"; + protected String dueDate; + + public Deadline(String description, String dueDate) { + super(description); + this.dueDate = dueDate; + } + + @Override + public String getTypeIcon() { + return TYPE_ICON; + } + + public String getDueDate() { + return dueDate; + } + + @Override + public String getTask() { + return taskTypeIcon() + isDoneIcon() + " " + getDescription() + + System.lineSeparator() + " Deadline: " + getDueDate(); + } +} diff --git a/src/main/java/tasktypes/Event.java b/src/main/java/tasktypes/Event.java new file mode 100644 index 000000000..cee15ef3c --- /dev/null +++ b/src/main/java/tasktypes/Event.java @@ -0,0 +1,31 @@ +package tasktypes; + +public class Event extends Task{ + public static final String TYPE_ICON = "E"; + String startDate, endDate; + public Event(String description, String startDate, String endDate) { + super(description); + this.startDate = startDate; + this.endDate = endDate; + } + + @Override + public String getTypeIcon() { + return TYPE_ICON; + } + + public String getStartDate() { + return startDate; + } + + public String getEndDate() { + return endDate; + } + + @Override + public String getTask() { + return taskTypeIcon() + isDoneIcon() + " " + getDescription() + System.lineSeparator() + + " Start: " + getStartDate() + System.lineSeparator() + + " End: " + getEndDate(); + } +} diff --git a/src/main/java/tasktypes/Task.java b/src/main/java/tasktypes/Task.java new file mode 100644 index 000000000..cb1feeea5 --- /dev/null +++ b/src/main/java/tasktypes/Task.java @@ -0,0 +1,45 @@ +package tasktypes; + +public class Task { + protected String description; + protected boolean isDone; + protected int listIndex; + + public Task(String description) { //ok to leave as public? + this.description = description; + this.isDone = false; + } + + public String getStatusIcon() { + return (isDone ? "X" : " "); // mark done task with X + } + + public String getTypeIcon() { + return "NULL"; + } + + public String taskTypeIcon() { return "[" + getTypeIcon() + "]";} + + public void setDescription(String description) { + this.description = description; + } + + public void markDone() { + isDone = true; + } + + public void markNotDone() { + isDone = false; + } + + public String isDoneIcon() { return "[" + getStatusIcon() + "]";} + + public String getDescription() { + return description; + } + + public String getTask() { + return taskTypeIcon() + isDoneIcon() + " " + getDescription(); + } + +} diff --git a/src/main/java/tasktypes/Todo.java b/src/main/java/tasktypes/Todo.java new file mode 100644 index 000000000..0869172a1 --- /dev/null +++ b/src/main/java/tasktypes/Todo.java @@ -0,0 +1,15 @@ +package tasktypes; + +public class Todo extends Task { + + public static final String TYPE_ICON = "T"; + + public Todo(String description) { + super(description); + } + + @Override + public String getTypeIcon() { + return TYPE_ICON; + } +}