diff --git a/data/dukeData.txt b/data/dukeData.txt new file mode 100644 index 000000000..a6ec94b0f --- /dev/null +++ b/data/dukeData.txt @@ -0,0 +1,7 @@ +[T] [ ] list +[T] [ ] bathe +[T] [ ] bathe list +[T] [ ] math +[T] [ ] math test +[T] [ ] english test +[D] [ ] testing diff --git a/docs/README.md b/docs/README.md index 8077118eb..e014e76f2 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,29 +1,156 @@ -# User Guide - +# Duke User Guide +Welcome to Duke, your very own command line task scheduler! In this user guide, you can find out how to use Duke. ## Features -### Feature-ABC +### Track your tasks! +- Add your tasks to our database +- Check tasks off when you've completed them +- Never miss another task ever! + +### 3 different types of tasks +- Todo: Simple description, no deadline/ time +- Deadlines: Description with deadline to be completed by +- Events: Description with the date and time of the event + +## List of commands + +### 1. `todo` - Adds a Todo task to the database + +- Briefly describe the Todo task after typing `todo` + +#### Example of usage: + +`todo clean kitchen` + +#### Expected outcome: +``` +Got it. I've added this task: + [T][ ] clean kitchen +Now you have 1 tasks in your list. +``` +#### Description of the outcome. +- The first box shows that the task is of the Todo type, represented by a 'T' +- The next box is empty, showing that the task has not been completed yet + - If there is a cross 'X' in it, the task has been completed + + -Description of the feature. +### 2. `deadline` - Adds a Deadline task to the database +- Briefly describe the Deadline task after typing `deadline` +- Then type `/by`, followed by the deadline of the Deadline task -### Feature-XYZ +#### Example of usage: -Description of the feature. +`deadline finish assignment /by tonight` + +#### Expected outcome: +``` +Got it. I've added this task: + [D][ ] finish assignment by: tonight +Now you have 2 tasks in your list. +``` +#### Description of the outcome. +- The first box shows that the task is of the Deadline type, represented by a 'D' +- The next box is empty, showing that the task has not been completed yet + - If there is a cross 'X' in it, that would mean that the task has been completed +- After the Deadline description, the deadline of the task will be displayed + - In this case, the deadline is tonight -## Usage -### `Keyword` - Describe action +### 3. `event` - Adds an Event task to the database +- Briefly describe the Event task after typing `event` +- Then type `/at`, followed by the date and time of the Event task -Describe the action and its outcome. +#### Example of usage: + +`event CS2113T exam /at 31 Feb 2021` + +#### Expected outcome: +``` +Got it. I've added this task: + [E][ ] CS2113T exam at: 31 Feb 2021 +Now you have 3 tasks in your list. +``` +#### Description of the outcome. +- The first box shows that the task is of the Event type, represented by an 'E' +- The next box is empty, showing that the task has not been completed yet + - If there is a cross 'X' in it, that would mean that the task has been completed +- After the Event description, the date and time of the task will be displayed + - In this case, the date and time is 31 Feb 2021 -Example of usage: -`keyword (optional arguments)` +### 4. `list` - Prints a list of all tasks that have been added -Expected outcome: +#### Example of usage: -Description of the outcome. +`list` +#### Expected outcome: +``` +Here are the tasks in your list: +1. [T][ ] clean kitchen +2. [D][ ] finish assignment by: tonight +3. [E][ ] CS2113T exam at: 31 Feb 2021 ``` -expected output +#### Description of the outcome. +- The tasks that have been added are numbered sequentially + + +### 5. `done` - Indicate to Duke that you have completed a task +- After typing `done`, type the index of the task you have completed + +#### Example of usage: + +`done 1` + +#### Expected outcome: +``` +Nice! I've marked this task as done: +[T][X] clean kitchen +``` +#### Description of the outcome. +- The second box will have an 'X' to indicate that it is checked + + + +### 6. `find` - Prints all the tasks that match the keyword you give it +- After typing `find`, type the keyword of the tasks you are searching for +#### Example of usage: + +`find finish` + +#### Expected outcome: +``` +Here are the matching tasks in your list: +1. [D][ ] finish assignment by: tonight +``` +#### Description of the outcome. +- Since the word 'finish' appears in the above task, it will be displayed + + + +### 7. `delete` - Removes a task from the database +- After typing `delete`, type the index of the task you want to delete +#### Example of usage: + +`delete 1` + +#### Expected outcome: +``` +Noted. I've removed this task: + [T][X] clean kitchen +Now you have 2 tasks in the list. +``` + + + +### 8. `bye` - Exits Duke + +#### Example of usage: + +`bye` + +#### Expected outcome: ``` +Byebye! Hope to see you again soon! +``` \ No newline at end of file diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 000000000..c50ff38da --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-merlot \ No newline at end of file diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java new file mode 100644 index 000000000..0436d04bc --- /dev/null +++ b/src/main/java/Deadline.java @@ -0,0 +1,21 @@ +/** + * Class inheriting from Task that has a description and deadline attribute + */ +public class Deadline extends Task{ + protected String by; + + public Deadline(String description, String by) { + super(description); + this.by = by.substring(by.indexOf(" ") + 1); + } + + @Override + public String getDescription() { + return description + "(by: " + by + ")"; + } + + @Override + public String getSymbol() { + return "D"; // mark Deadlines with a "D" + } +} diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 5d313334c..10d4befd5 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,10 +1,16 @@ +/** + *

Track Your Tasks!

+ * * The Duke program keeps track of your tasks by categorising them + * * into ToDos, Deadlines and Events and giving you the tools to + * * organise them + * *

+ * * + * * @author Edly Irsyad + * * @version 0.2 + */ public class Duke { public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); + Ui.welcome(); + Parser.parse(); } } diff --git a/src/main/java/DukeException.java b/src/main/java/DukeException.java new file mode 100644 index 000000000..f65e5fe4f --- /dev/null +++ b/src/main/java/DukeException.java @@ -0,0 +1,5 @@ +/** + * Class representing the DukeException + */ +public class DukeException extends Exception{ +} diff --git a/src/main/java/Event.java b/src/main/java/Event.java new file mode 100644 index 000000000..4dea6d16d --- /dev/null +++ b/src/main/java/Event.java @@ -0,0 +1,21 @@ +/** + * Class inheriting from Task that has a description and date/time attribute + */ +public class Event extends Task{ + protected String eventDateTime; + + public Event(String description, String eventDateTime) { + super(description); + this.eventDateTime = eventDateTime.substring(eventDateTime.indexOf(" ") + 1); + } + + @Override + public String getDescription() { + return description + "(at: " + eventDateTime + ")"; + } + + @Override + public String getSymbol() { + return "E"; // mark Events with an "E" + } +} diff --git a/src/main/java/Parser.java b/src/main/java/Parser.java new file mode 100644 index 000000000..6bbe4d64a --- /dev/null +++ b/src/main/java/Parser.java @@ -0,0 +1,77 @@ +import java.io.IOException; +import java.util.Scanner; + +/** + * Continually parses through the user's commands then determines the next course of action by calling the appropriate class + */ +public class Parser { + public static void parse() { + String toBeWritten = null; + String dukeDataPath = "C:\\Users\\edly1\\Documents\\ip\\data\\dukeData.txt"; + Scanner in = new Scanner(System.in); + boolean isContinueLoop = true; + + while(isContinueLoop){ + String userIn = in.nextLine(); + String userCommand = userIn.contains(" ") ? userIn.substring(0, userIn.indexOf(" ")): userIn; + String userCommandDetails = userIn.contains(" ") ? userIn.substring(userIn.indexOf(" ") + 1): "invalid"; + + switch (userCommand) { + case "todo": + toBeWritten = TaskList.addToDo(userCommandDetails, toBeWritten); + try { + if (toBeWritten != null) { + Storage.writeToFile(dukeDataPath, toBeWritten + System.lineSeparator()); + } + } catch (IOException e) { + System.out.println("Something went wrong: " + e.getMessage()); + } + break; + case "deadline": + toBeWritten = TaskList.addDeadline(userCommandDetails, toBeWritten); + try { + if (toBeWritten != null) { + Storage.writeToFile(dukeDataPath, toBeWritten + System.lineSeparator()); + } + } catch (IOException e) { + System.out.println("Something went wrong: " + e.getMessage()); + } + break; + case "event": + toBeWritten = TaskList.addEvent(userCommandDetails, toBeWritten); + try { + if (toBeWritten != null) { + Storage.writeToFile(dukeDataPath, toBeWritten + System.lineSeparator()); + } + } catch (IOException e) { + System.out.println("Something went wrong: " + e.getMessage()); + } + break; + + case "list": + TaskList.list(); + break; + + case "done": + TaskList.done(userIn); + break; + + case "find": + TaskList.find(userCommandDetails); + break; + + case "delete": + TaskList.delete(userIn); + break; + + case "bye": + Ui.farewell(); + isContinueLoop = false; + break; + default: + Ui.invalidCommand(userIn); + break; + } + } + } +} diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java new file mode 100644 index 000000000..868024431 --- /dev/null +++ b/src/main/java/Storage.java @@ -0,0 +1,19 @@ +import java.io.FileWriter; +import java.io.IOException; + +/** + * Saves tasks in the target file + */ +public class Storage { + /** + * Writes Task description and details into the file + * + * @param filePath Location of the target file to be written to with respect to the C-drive + * @param textToAdd Message to be written to the target file + */ + public static void writeToFile(String filePath, String textToAdd) throws IOException { + FileWriter fw = new FileWriter(filePath, true); + fw.write(textToAdd); + fw.close(); + } +} diff --git a/src/main/java/Task.java b/src/main/java/Task.java new file mode 100644 index 000000000..beabb027f --- /dev/null +++ b/src/main/java/Task.java @@ -0,0 +1,24 @@ +/** + * Abstract class representing the general structure of a Task + */ +public class Task { + protected String description; + protected boolean isDone; + + public Task(String description) { + this.description = description; + this.isDone = false; + } + + public String getDescription() { + return description; + } + + public String getSymbol() { + return " "; // mark Tasks with a " " + } + + public String getStatusIcon() { + return (isDone ? "X" : " "); // mark done task with X + } +} diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java new file mode 100644 index 000000000..1e8fdda0c --- /dev/null +++ b/src/main/java/TaskList.java @@ -0,0 +1,165 @@ +import java.util.ArrayList; + +/** + * Taking over from Parser, this class contains the operations to modify tasks + */ +public class TaskList { + public static ArrayList entries = new ArrayList<>(); + + public static int entriesCount = 0; + + /** + * Returns the message to be written to the file + * Adds a ToDo Task into the entries ArrayList + * If the user input is invalid, the DukeException is thrown + * + * @param userCommandDetails Details of the user's command + * @param toBeWritten Message to be written to the file + * @return toBeWritten Message to be written to the file + * @throws DukeException If the userCommandDetails is empty or is invalid + */ + public static String addToDo(String userCommandDetails, String toBeWritten) { + try { + if (userCommandDetails.isEmpty() || userCommandDetails.equals("invalid")) { + throw new DukeException(); + } + entries.add(entriesCount, new ToDo(userCommandDetails)); + toBeWritten = Ui.taskAdded(entries, entriesCount); + entriesCount++; + Ui.entriesCount(entriesCount); + } catch (DukeException e) { + Ui.missingDetails(); + } + return toBeWritten; + } + + /** + * Returns the message to be written to the file + * Adds a Deadline Task into the entries ArrayList + * If the user input is invalid, the DukeException is thrown + * + * @param userCommandDetails Details of the user's command + * @param toBeWritten Message to be written to the file + * @return toBeWritten Message to be written to the file + * @throws DukeException If the userCommandDetails is empty or is invalid + */ + public static String addDeadline(String userCommandDetails, String toBeWritten) { + try { + int deadlineIndex = userCommandDetails.indexOf("/by"); + String taskDescription = userCommandDetails.substring(0, deadlineIndex - 1); + String taskDeadline = userCommandDetails.substring(deadlineIndex); + if (userCommandDetails.equals("invalid") || taskDescription.isEmpty() || taskDeadline.isEmpty()) { + throw new DukeException(); + } + entries.add(entriesCount, new Deadline(taskDescription, taskDeadline)); + toBeWritten = Ui.taskAdded(entries, entriesCount); + entriesCount++; + Ui.entriesCount(entriesCount); + } catch (DukeException e) { + Ui.missingDetails(); + } + return toBeWritten; + } + + /** + * Returns the message to be written to the file + * Adds an Event Task into the entries ArrayList + * If the user input is invalid, the DukeException is thrown + * + * @param userCommandDetails Details of the user's command + * @param toBeWritten Message to be written to the file + * @return toBeWritten Message to be written to the file + * @throws DukeException If the userCommandDetails is empty or is invalid + */ + public static String addEvent(String userCommandDetails, String toBeWritten) { + try { + int eventDateTimeIndex = userCommandDetails.indexOf("/at"); + String eventDescription = userCommandDetails.substring(0, eventDateTimeIndex - 1); + String eventDateTime = userCommandDetails.substring(eventDateTimeIndex); + if (userCommandDetails.equals("invalid") || eventDescription.isEmpty() || eventDateTime.isEmpty()) { + throw new DukeException(); + } + entries.add(entriesCount, new Event(eventDescription, eventDateTime)); + toBeWritten = Ui.taskAdded(entries, entriesCount); + entriesCount++; + Ui.entriesCount(entriesCount); + } catch (DukeException e) { + Ui.missingDetails(); + } + return toBeWritten; + } + + /** + * Prints every element in the entries ArrayList sequentially to give the user a list of all their tasks + */ + public static void list() { + Ui.printLongLine(); + System.out.println("Here are the tasks in your list:"); + int i = 0; + for(Task entry : entries){ + System.out.println((i+1) + ". " + "[" + entry.getSymbol() + "] [" + entry.getStatusIcon() + "] " + entry.getDescription()); + i++; + } + Ui.printLongLine(); + } + + /** + * Marks an X in the isDone checkbox of the completed task to show the user that the task is complete + * + * @param userIn User's input + */ + public static void done(String userIn) { + Ui.printLongLine(); + String stringTaskIndex = userIn.substring(userIn.indexOf(" ") + 1); + int intTaskIndex = Integer.parseInt(stringTaskIndex) - 1; + entries.get(intTaskIndex).isDone = true; + System.out.println("Nice! I've marked this task as done:\n" + + " [" + entries.get(intTaskIndex).getSymbol() + + "] [" + entries.get(intTaskIndex).getStatusIcon() + "] " + entries.get(intTaskIndex).description); + Ui.printLongLine(); + } + + /** + * Removes a particular task from the entries ArrayList + * + * @param userIn User's input + */ + public static void delete(String userIn) { + Ui.printLongLine(); + String stringTaskIndex = userIn.substring(userIn.indexOf(" ") + 1); + int intTaskIndex = Integer.parseInt(stringTaskIndex) - 1; + System.out.println("Noted. I've removed this task:\n" + + " [" + entries.get(intTaskIndex).getSymbol() + + "] [" + entries.get(intTaskIndex).getStatusIcon() + "] " + entries.get(intTaskIndex).description); + System.out.println("Now you have " + (entriesCount - 1) + " tasks in the list."); + for (int i = intTaskIndex; i < entriesCount - 1; i++) { + entries.set(i, entries.get(i + 1)); + } + entries.remove(entriesCount - 1); + entriesCount -= 1; + Ui.printLongLine(); + } + + /** + * Parses through every element of the entries ArrayList to find a match with the user's input + * + * @param userCommandDetails Details of the user's command + */ + public static void find(String userCommandDetails) { + Ui.printLongLine(); + int i = 0; + for(Task entry : entries){ + if (entry.getDescription().contains(userCommandDetails)) { + if (i == 0) { + System.out.println("Here are the matching tasks in your list:\n"); + } + System.out.println((i+1) + ". " + "[" + entry.getSymbol() + "] [" + entry.getStatusIcon() + "] " + entry.getDescription()); + i++; + } + } + if (i == 0) { + System.out.println("Sorry, keyword couldn't be found..."); + } + Ui.printLongLine(); + } +} \ No newline at end of file diff --git a/src/main/java/ToDo.java b/src/main/java/ToDo.java new file mode 100644 index 000000000..495943c50 --- /dev/null +++ b/src/main/java/ToDo.java @@ -0,0 +1,13 @@ +/** + * Class inheriting from Task that has a description attribute + */ +public class ToDo extends Task{ + public ToDo(String description) { + super(description); + } + + @Override + public String getSymbol() { + return "T"; // mark ToDos with a "T" + } +} diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java new file mode 100644 index 000000000..49c489d2c --- /dev/null +++ b/src/main/java/Ui.java @@ -0,0 +1,82 @@ +import java.util.ArrayList; + +/** + * Handles interactions with the user by printing the appropriate response to the user's input + */ +public class Ui { + public static final String longLine = "____________________________________________________________"; + + /** + * Prints a long line across the screen as a visual indicator to the user of a new section + */ + public static void printLongLine() { + System.out.println(longLine); + } + + /** + * Prints a friendly introductory message to the user to make them comfortable with using the app + */ + public static void welcome() { + printLongLine(); + System.out.println("Hello! I'm Duke"); + System.out.println("What can I do for you?"); + printLongLine(); + } + + /** + * Prints a goodbye message to the user to make them comfortable with using the app + */ + public static void farewell() { + printLongLine(); + System.out.println("Byebye! Hope to see you again soon!"); + printLongLine(); + } + + /** + * Indicates to the user that the command they typed is not recognised + * + * @param userCommand User's command + */ + public static void invalidCommand(String userCommand) { + printLongLine(); + System.out.println("Hey! That's an invalid command, try again"); + printLongLine(); + } + + /** + * Indicates to the user that their task input is incomplete and requires more details e.g. deadline, description + */ + public static void missingDetails() { + printLongLine(); + System.out.println("You missed out some details of your task!"); + printLongLine(); + } + + /** + * Indicates to the user that their task has been added as an element in the entries ArrayList + * Returns the message to be written to the target file + * + * @param entries ArrayList of Task entries + * @param entriesCount Number of elements in the entries ArrayList + * @return toBeWritten Message to be written to the target file + */ + public static String taskAdded(ArrayList entries, int entriesCount) { + printLongLine(); + System.out.println("Got it. I've added this task:"); + String toBeWritten = "[" + entries.get(entriesCount).getSymbol() + "] [" + + entries.get(entriesCount).getStatusIcon() + "] " + entries.get(entriesCount).description; + System.out.println(" " + toBeWritten); + return toBeWritten; + } + + /** + * Indicates to the user the number of elements are in the entries ArrayList + * + * @param entriesCount Number of elements in the entries ArrayList + */ + public static void entriesCount(int entriesCount) { + System.out.println("Now you have " + entriesCount + " tasks in the list."); + printLongLine(); + } +} + diff --git a/src/main/testpackage/TestClass b/src/main/testpackage/TestClass new file mode 100644 index 000000000..e69de29bb