From b44b350ebc19d8e8f6ccda6c72fc80e8038f16e8 Mon Sep 17 00:00:00 2001 From: kaboomzxc Date: Thu, 5 Sep 2024 01:10:12 +0800 Subject: [PATCH 01/28] Refractor Duke to Quinn and implement Level-0 --- README.md | 4 ++-- docs/README.md | 2 +- src/main/java/Duke.java | 10 --------- src/main/java/Quinn.java | 45 ++++++++++++++++++++++++++++++++++++++++ text-ui-test/runtest.bat | 2 +- 5 files changed, 49 insertions(+), 14 deletions(-) delete mode 100644 src/main/java/Duke.java create mode 100644 src/main/java/Quinn.java diff --git a/README.md b/README.md index 90aa7f092..d27d14052 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Duke project template +# Quinn 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. @@ -13,7 +13,7 @@ Prerequisites: JDK 17, update Intellij to the most recent version. 1. If there are any further prompts, accept the defaults. 1. Configure the project to use **JDK 17** (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: +3. After that, locate the `src/main/java/Quinn.java` file, right-click it, and choose `Run Quinn.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 ____ _ diff --git a/docs/README.md b/docs/README.md index 47b9f984f..1ed55ceea 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,4 +1,4 @@ -# Duke User Guide +# Quinn User Guide // Update the title above to match the actual product name diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java deleted file mode 100644 index 5d313334c..000000000 --- a/src/main/java/Duke.java +++ /dev/null @@ -1,10 +0,0 @@ -public class Duke { - public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); - } -} diff --git a/src/main/java/Quinn.java b/src/main/java/Quinn.java new file mode 100644 index 000000000..ce3afbba6 --- /dev/null +++ b/src/main/java/Quinn.java @@ -0,0 +1,45 @@ +public class Quinn { + public static void main(String[] args) { + new Quinn().run(); + } + + public void run() { + greet(); + exit(); + } + + public void greet() { + String logo = "\t" + " QQQ U U III N N N N " + System.lineSeparator() + + "\t" + " Q Q U U I NN N NN N " + System.lineSeparator() + + "\t" + " Q Q U U I N N N N N N " + System.lineSeparator() + + "\t" + " Q Q U U I N NN N NN " + System.lineSeparator() + + "\t" + " QQQ UUU III N N N N " + System.lineSeparator() + + "\t" + " Q " + System.lineSeparator() + + "\t" + " QQ " + System.lineSeparator(); + + String welcomeMessage = "\t" + "Hello! I'm Quinn, your Personal Assistant ChatBot." + + System.lineSeparator() + + System.lineSeparator() + + logo + + System.lineSeparator() + + "\t" + "What can I do for you?"; + + printResponse(welcomeMessage); + } + + public void exit() { + String exitMessage = "\t" + "Bye. Hope to see you again soon!"; + printResponse(exitMessage); + } + + public void printResponse(String message) { + printLine(); + System.out.println(message); + printLine(); + } + + public void printLine() { + String horizontalLine = "\t" + "________________________________________________________"; + System.out.println(horizontalLine); + } +} diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat index 087374464..43ebe9053 100644 --- a/text-ui-test/runtest.bat +++ b/text-ui-test/runtest.bat @@ -15,7 +15,7 @@ IF ERRORLEVEL 1 ( REM no error here, errorlevel == 0 REM run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT -java -classpath ..\bin Duke < input.txt > ACTUAL.TXT +java -classpath ..\bin Quinn < input.txt > ACTUAL.TXT REM compare the output to the expected output FC ACTUAL.TXT EXPECTED.TXT From 1a384e74724feac78b8765675f837e501dce5afb Mon Sep 17 00:00:00 2001 From: kaboomzxc Date: Thu, 5 Sep 2024 01:26:32 +0800 Subject: [PATCH 02/28] Implement Level-1 --- src/main/java/Quinn.java | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/main/java/Quinn.java b/src/main/java/Quinn.java index ce3afbba6..db0a8a25c 100644 --- a/src/main/java/Quinn.java +++ b/src/main/java/Quinn.java @@ -1,3 +1,5 @@ +import java.util.Scanner; + public class Quinn { public static void main(String[] args) { new Quinn().run(); @@ -5,7 +7,20 @@ public static void main(String[] args) { public void run() { greet(); - exit(); + + Scanner sc = new Scanner(System.in); + String commandLine = ""; + + while (!commandLine.equals("bye")) { + System.out.print("Enter command: \t"); + commandLine = sc.nextLine().trim(); + + if ("bye".equals(commandLine)) { + exit(); + } else { + echo("\t" + commandLine); + } + } } public void greet() { @@ -32,6 +47,10 @@ public void exit() { printResponse(exitMessage); } + public void echo(String message) { + printResponse(message); + } + public void printResponse(String message) { printLine(); System.out.println(message); From 80154db3bdb59aedbcdc86fb1f472643f4ada920 Mon Sep 17 00:00:00 2001 From: kaboomzxc Date: Thu, 5 Sep 2024 01:47:01 +0800 Subject: [PATCH 03/28] Implement Level-2 --- src/main/java/Quinn.java | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/src/main/java/Quinn.java b/src/main/java/Quinn.java index db0a8a25c..4bef4b447 100644 --- a/src/main/java/Quinn.java +++ b/src/main/java/Quinn.java @@ -1,6 +1,10 @@ +import java.util.ArrayList; +import java.util.List; import java.util.Scanner; public class Quinn { + private static final List tasks = new ArrayList<>(); + public static void main(String[] args) { new Quinn().run(); } @@ -15,10 +19,16 @@ public void run() { System.out.print("Enter command: \t"); commandLine = sc.nextLine().trim(); - if ("bye".equals(commandLine)) { - exit(); - } else { - echo("\t" + commandLine); + switch (commandLine.toLowerCase()) { + case "bye": + exit(); + break; + case "list": + listTasks(); + break; + default: + addTask(commandLine); + break; } } } @@ -61,4 +71,23 @@ public void printLine() { String horizontalLine = "\t" + "________________________________________________________"; System.out.println(horizontalLine); } + + public void addTask(String commandLine) { + tasks.add(commandLine); + echo("\t" + "added: " + commandLine); + } + + public void listTasks() { + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < tasks.size(); i++) { + if (i != 0) { + sb.append(System.lineSeparator()); + } + + sb.append("\t").append(i + 1).append(". ").append(tasks.get(i)); + } + + echo(sb.toString()); + } } From 83bc054a104c6a26a5e0267db849a41c29193fdd Mon Sep 17 00:00:00 2001 From: kaboomzxc Date: Thu, 5 Sep 2024 02:25:42 +0800 Subject: [PATCH 04/28] Implement Level-3 and adhere to coding standard --- src/main/java/Quinn.java | 43 ++++++++++++++++++++++++++++++++++------ src/main/java/Task.java | 34 +++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 6 deletions(-) create mode 100644 src/main/java/Task.java diff --git a/src/main/java/Quinn.java b/src/main/java/Quinn.java index 4bef4b447..cec1a5dde 100644 --- a/src/main/java/Quinn.java +++ b/src/main/java/Quinn.java @@ -3,7 +3,7 @@ import java.util.Scanner; public class Quinn { - private static final List tasks = new ArrayList<>(); + private static final List tasks = new ArrayList<>(); public static void main(String[] args) { new Quinn().run(); @@ -19,15 +19,29 @@ public void run() { System.out.print("Enter command: \t"); commandLine = sc.nextLine().trim(); - switch (commandLine.toLowerCase()) { + String[] commandLineParts = commandLine.split(" ", 2); + + int taskNum; + Task task; + + switch (commandLineParts[0].toLowerCase()) { case "bye": exit(); break; case "list": listTasks(); break; + case "mark": + taskNum = Integer.parseInt(commandLineParts[1]); + markTask(taskNum); + break; + case "unmark": + taskNum = Integer.parseInt(commandLineParts[1]); + unmarkTask(taskNum); + break; default: - addTask(commandLine); + task = new Task(commandLine); + addTask(task); break; } } @@ -72,9 +86,9 @@ public void printLine() { System.out.println(horizontalLine); } - public void addTask(String commandLine) { - tasks.add(commandLine); - echo("\t" + "added: " + commandLine); + public void addTask(Task task) { + tasks.add(task); + echo("\t" + "added: " + task.getDescription()); } public void listTasks() { @@ -90,4 +104,21 @@ public void listTasks() { echo(sb.toString()); } + public void markTask(int taskNum) { + Task task = tasks.get(taskNum - 1); + task.setDone(); + + String message = "\t" + "Nice! I've marked this task as done:" + + System.lineSeparator() + "\t\t" + task; + echo(message); + } + + public void unmarkTask(int taskNum) { + Task task = tasks.get(taskNum - 1); + task.setNotDone(); + + String message = "\t" + "OK, I've marked this task as not done yet:" + + System.lineSeparator() + "\t\t" + task; + echo(message); + } } diff --git a/src/main/java/Task.java b/src/main/java/Task.java new file mode 100644 index 000000000..d64b90090 --- /dev/null +++ b/src/main/java/Task.java @@ -0,0 +1,34 @@ +public class Task { + private String description; + private boolean isDone; + + public Task(String description) { + this.description = description; + this.isDone = false; + } + + public String getStatusIcon() { + if (isDone) { + return "[X]"; + } else { + return "[ ]"; + } + } + + public String getDescription() { + return description; + } + + public void setDone() { + this.isDone = true; + } + + public void setNotDone() { + this.isDone = false; + } + + @Override + public String toString() { + return getStatusIcon() + " " + description; + } +} From 9cdfdcdbd49d3e49189f8a7dc373ff3102efc71d Mon Sep 17 00:00:00 2001 From: kaboomzxc Date: Fri, 6 Sep 2024 04:14:22 +0800 Subject: [PATCH 05/28] Implement Level-4 --- src/main/java/Deadline.java | 17 +++++++++++++++ src/main/java/Event.java | 19 +++++++++++++++++ src/main/java/Quinn.java | 42 +++++++++++++++++++++++++++++++++---- src/main/java/Task.java | 23 +++++++++++--------- src/main/java/TaskType.java | 15 +++++++++++++ src/main/java/ToDo.java | 9 ++++++++ 6 files changed, 111 insertions(+), 14 deletions(-) create mode 100644 src/main/java/Deadline.java create mode 100644 src/main/java/Event.java create mode 100644 src/main/java/TaskType.java create mode 100644 src/main/java/ToDo.java diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java new file mode 100644 index 000000000..b41eb06bc --- /dev/null +++ b/src/main/java/Deadline.java @@ -0,0 +1,17 @@ +public class Deadline extends Task { + private final String byDateTimeInput; + + public Deadline(String description, String byDateTimeInput) { + this(description, byDateTimeInput, false); + } + + public Deadline(String description, String byDateTimeInput, boolean isDone) { + super(TaskType.DEADLINE, description, isDone); + this.byDateTimeInput = byDateTimeInput; + } + + @Override + public String toString() { + return super.toString() + " (by: " + byDateTimeInput + ")"; + } +} diff --git a/src/main/java/Event.java b/src/main/java/Event.java new file mode 100644 index 000000000..834b74d17 --- /dev/null +++ b/src/main/java/Event.java @@ -0,0 +1,19 @@ +public class Event extends Task { + private final String fromDateTimeInput; + private final String toDateTimeInput; + + public Event(String description, String fromDateTimeInput, String toDateTimeInput) { + this(description, fromDateTimeInput, toDateTimeInput, false); + } + + public Event(String description, String fromDateTimeInput, String toDateTimeInput, boolean isDone) { + super(TaskType.EVENT, description, isDone); + this.fromDateTimeInput = fromDateTimeInput; + this.toDateTimeInput = toDateTimeInput; + } + + @Override + public String toString() { + return super.toString() + " (from: " + fromDateTimeInput + " to: " + toDateTimeInput + ")"; + } +} diff --git a/src/main/java/Quinn.java b/src/main/java/Quinn.java index cec1a5dde..14f0d6dd5 100644 --- a/src/main/java/Quinn.java +++ b/src/main/java/Quinn.java @@ -23,6 +23,8 @@ public void run() { int taskNum; Task task; + String taskDescription; + String taskInfo; switch (commandLineParts[0].toLowerCase()) { case "bye": @@ -39,10 +41,25 @@ public void run() { taskNum = Integer.parseInt(commandLineParts[1]); unmarkTask(taskNum); break; - default: - task = new Task(commandLine); + case "todo": + taskDescription = commandLineParts[1]; + task = new ToDo(taskDescription); + addTask(task); + break; + case "deadline": + taskInfo = commandLineParts[1]; + String[] deadlineTaskDetails = taskInfo.split("/by", 2); + task = new Deadline(deadlineTaskDetails[0].trim(), deadlineTaskDetails[1].trim()); addTask(task); break; + case "event": + taskInfo = commandLineParts[1]; + String[] eventTaskDetails = taskInfo.split("/from | /to", 3); + task = new Event(eventTaskDetails[0].trim(), eventTaskDetails[1].trim(), eventTaskDetails[2].trim()); + addTask(task); + break; + default: + break; } } } @@ -88,22 +105,39 @@ public void printLine() { public void addTask(Task task) { tasks.add(task); - echo("\t" + "added: " + task.getDescription()); + + String response = "\t" + "Got it. I've added this task:" + + System.lineSeparator() + + "\t\t" + task + + System.lineSeparator() + + "\t" + "Now you have " + tasks.size() + (tasks.size() > 1 ? " tasks" : " task") + " in the list."; + echo(response); } public void listTasks() { StringBuilder sb = new StringBuilder(); + sb.append("\t") + .append(tasks.size() > 1 ? "Here are the tasks in your list:" : "Here is the task in your list:") + .append(System.lineSeparator()) + .append("\t") + .append("[Legend: T = todo, D = deadline, E = event]") + .append(System.lineSeparator()); + for (int i = 0; i < tasks.size(); i++) { if (i != 0) { sb.append(System.lineSeparator()); } - sb.append("\t").append(i + 1).append(". ").append(tasks.get(i)); + sb.append("\t") + .append(i + 1) + .append(". ") + .append(tasks.get(i)); } echo(sb.toString()); } + public void markTask(int taskNum) { Task task = tasks.get(taskNum - 1); task.setDone(); diff --git a/src/main/java/Task.java b/src/main/java/Task.java index d64b90090..f16b291ed 100644 --- a/src/main/java/Task.java +++ b/src/main/java/Task.java @@ -1,24 +1,27 @@ -public class Task { - private String description; +public abstract class Task { + private final TaskType type; + private final String description; private boolean isDone; - public Task(String description) { + public Task(TaskType type, String description) { + // By default, the task is not done + this(type, description, false); + } + + public Task(TaskType type, String description, boolean isDone) { + this.type = type; this.description = description; - this.isDone = false; + this.isDone = isDone; } public String getStatusIcon() { if (isDone) { - return "[X]"; + return "[✔️]"; // mark done task with ✔️ } else { return "[ ]"; } } - public String getDescription() { - return description; - } - public void setDone() { this.isDone = true; } @@ -29,6 +32,6 @@ public void setNotDone() { @Override public String toString() { - return getStatusIcon() + " " + description; + return "[" + type.getAbbreviation() + "] " + getStatusIcon() + " " + description; } } diff --git a/src/main/java/TaskType.java b/src/main/java/TaskType.java new file mode 100644 index 000000000..e52044cec --- /dev/null +++ b/src/main/java/TaskType.java @@ -0,0 +1,15 @@ +public enum TaskType { + TODO("T"), + DEADLINE("D"), + EVENT("E"); + + private final String abbreviation; + + TaskType(String abbreviation) { + this.abbreviation = abbreviation; + } + + public String getAbbreviation() { + return abbreviation; + } +} diff --git a/src/main/java/ToDo.java b/src/main/java/ToDo.java new file mode 100644 index 000000000..60d7a50ce --- /dev/null +++ b/src/main/java/ToDo.java @@ -0,0 +1,9 @@ +public class ToDo extends Task { + public ToDo(String description) { + super(TaskType.TODO, description); + } + + public ToDo(String description, boolean isDone) { + super(TaskType.TODO, description, isDone); + } +} From e9a5a29833d3f4bc3471092ca6fcd1197447cb3b Mon Sep 17 00:00:00 2001 From: kaboomzxc Date: Tue, 10 Sep 2024 17:03:52 +0800 Subject: [PATCH 06/28] Implement Level-5 and review code quality --- src/main/java/Quinn.java | 317 +++++++++++++++++++----------- src/main/java/QuinnException.java | 5 + src/main/java/Task.java | 2 +- src/main/java/Ui.java | 97 +++++++++ 4 files changed, 310 insertions(+), 111 deletions(-) create mode 100644 src/main/java/QuinnException.java create mode 100644 src/main/java/Ui.java diff --git a/src/main/java/Quinn.java b/src/main/java/Quinn.java index 14f0d6dd5..01e1b0deb 100644 --- a/src/main/java/Quinn.java +++ b/src/main/java/Quinn.java @@ -1,158 +1,255 @@ import java.util.ArrayList; import java.util.List; -import java.util.Scanner; public class Quinn { private static final List tasks = new ArrayList<>(); + private final Ui ui; + + public Quinn() { + ui = new Ui(); + } + public static void main(String[] args) { new Quinn().run(); } public void run() { - greet(); + ui.displayWelcome(); - Scanner sc = new Scanner(System.in); String commandLine = ""; while (!commandLine.equals("bye")) { - System.out.print("Enter command: \t"); - commandLine = sc.nextLine().trim(); - - String[] commandLineParts = commandLine.split(" ", 2); - - int taskNum; - Task task; - String taskDescription; - String taskInfo; - - switch (commandLineParts[0].toLowerCase()) { - case "bye": - exit(); - break; - case "list": - listTasks(); - break; - case "mark": - taskNum = Integer.parseInt(commandLineParts[1]); - markTask(taskNum); - break; - case "unmark": - taskNum = Integer.parseInt(commandLineParts[1]); - unmarkTask(taskNum); - break; - case "todo": - taskDescription = commandLineParts[1]; - task = new ToDo(taskDescription); - addTask(task); - break; - case "deadline": - taskInfo = commandLineParts[1]; - String[] deadlineTaskDetails = taskInfo.split("/by", 2); - task = new Deadline(deadlineTaskDetails[0].trim(), deadlineTaskDetails[1].trim()); - addTask(task); - break; - case "event": - taskInfo = commandLineParts[1]; - String[] eventTaskDetails = taskInfo.split("/from | /to", 3); - task = new Event(eventTaskDetails[0].trim(), eventTaskDetails[1].trim(), eventTaskDetails[2].trim()); - addTask(task); - break; - default: - break; + commandLine = ui.readCommand(); + + try { + processCommand(commandLine); + } catch (QuinnException e) { + ui.displayError(e.getMessage()); + } finally { + ui.displayLine(); } } } - public void greet() { - String logo = "\t" + " QQQ U U III N N N N " + System.lineSeparator() - + "\t" + " Q Q U U I NN N NN N " + System.lineSeparator() - + "\t" + " Q Q U U I N N N N N N " + System.lineSeparator() - + "\t" + " Q Q U U I N NN N NN " + System.lineSeparator() - + "\t" + " QQQ UUU III N N N N " + System.lineSeparator() - + "\t" + " Q " + System.lineSeparator() - + "\t" + " QQ " + System.lineSeparator(); + public void processCommand(String commandLine) throws QuinnException { + String[] commandLineParts = commandLine.split(" ", 2); - String welcomeMessage = "\t" + "Hello! I'm Quinn, your Personal Assistant ChatBot." - + System.lineSeparator() - + System.lineSeparator() - + logo - + System.lineSeparator() - + "\t" + "What can I do for you?"; + String commandType; + String commandInfo; - printResponse(welcomeMessage); + if (commandLineParts.length == 2) { + commandType = commandLineParts[0].trim(); + commandInfo = commandLineParts[1].trim(); + + if ((commandType.equals("bye") || commandType.equals("list")) && !commandInfo.isEmpty()) { + throw new QuinnException("INVALID COMMAND. Please try again!"); + } + } else { // for "bye" and "list" commands which does not have any input behind + commandType = commandLineParts[0]; + commandInfo = ""; + } + + executeCommand(commandType, commandInfo); } - public void exit() { - String exitMessage = "\t" + "Bye. Hope to see you again soon!"; - printResponse(exitMessage); + public void executeCommand(String commandType, String commandInfo) throws QuinnException { + int taskNum; + Task task; + String taskDescription; + String taskInfo; + + switch (commandType.toLowerCase()) { + case "bye": + ui.displayExit(); + break; + case "list": + displayTasks(); + break; + case "mark": + taskNum = getTaskNumFromMarkCommand(commandInfo); + markTask(taskNum); + break; + case "unmark": + taskNum = getTaskNumFromUnmarkCommand(commandInfo); + unmarkTask(taskNum); + break; + case "todo": + taskDescription = getTaskDescriptionFromToDoCommand(commandInfo); + task = new ToDo(taskDescription); + addTask(task); + break; + case "deadline": + taskInfo = processTaskInfoFromDeadlineCommand(commandInfo); + String[] deadlineTaskDetails = taskInfo.split("/by", 2); + task = new Deadline(deadlineTaskDetails[0].trim(), deadlineTaskDetails[1].trim()); + addTask(task); + break; + case "event": + taskInfo = processTaskInfoFromEventCommand(commandInfo); + String[] eventTaskDetails = taskInfo.split("/from|/to", 3); + task = new Event(eventTaskDetails[0].trim(), eventTaskDetails[1].trim(), eventTaskDetails[2].trim()); + addTask(task); + break; + default: + throw new QuinnException("INVALID COMMAND. Please try again!"); + } } - public void echo(String message) { - printResponse(message); + private boolean isCommandInfoPresent(String commandInfo) { + return !commandInfo.trim().isEmpty(); } - public void printResponse(String message) { - printLine(); - System.out.println(message); - printLine(); + private int getTaskNumFromMarkCommand(String commandInfo) throws QuinnException { + if (isCommandInfoPresent(commandInfo)) { + try { + return Integer.parseInt(commandInfo); + } catch (NumberFormatException e) { + throw new QuinnException("Please enter a valid task number to be marked as done!"); + } + } else { + throw new QuinnException("Please enter a task number to be marked as done!"); + } } - public void printLine() { - String horizontalLine = "\t" + "________________________________________________________"; - System.out.println(horizontalLine); + private int getTaskNumFromUnmarkCommand(String commandInfo) throws QuinnException { + if (isCommandInfoPresent(commandInfo)) { + try { + return Integer.parseInt(commandInfo); + } catch (NumberFormatException e) { + throw new QuinnException("Please enter a valid task number to be marked as not done yet!"); + } + } else { + throw new QuinnException("Please enter a task number to be marked as not done yet!"); + } } - public void addTask(Task task) { - tasks.add(task); + private String getTaskDescriptionFromToDoCommand(String commandInfo) throws QuinnException { + if (isCommandInfoPresent(commandInfo)) { + return commandInfo; + } else { + throw new QuinnException("The description of a todo cannot be empty!"); + } + } - String response = "\t" + "Got it. I've added this task:" - + System.lineSeparator() - + "\t\t" + task - + System.lineSeparator() - + "\t" + "Now you have " + tasks.size() + (tasks.size() > 1 ? " tasks" : " task") + " in the list."; - echo(response); + private String processTaskInfoFromDeadlineCommand(String commandInfo) throws QuinnException { + if (!isCommandInfoPresent(commandInfo)) { + throw new QuinnException("INCOMPLETE COMMAND" + + System.lineSeparator() + "\t" + + "The description and date/time of a deadline cannot be empty!" + + System.lineSeparator() + "\t" + + "[Note: Enter /by before specifying the date/time]"); + } else { + String[] deadlineInfoParts = commandInfo.split("/by", 2); + + if (deadlineInfoParts.length != 2) { + throw new QuinnException("INVALID COMMAND" + + System.lineSeparator() + "\t" + + "Please check that the description and date/time of a deadline is present!" + + System.lineSeparator() + "\t" + + "[Note: Enter /by before specifying the date/time]"); + } + + String deadlineDescription = deadlineInfoParts[0].trim(); + String deadlineByDateTime = deadlineInfoParts[1].trim(); + + if (deadlineDescription.isEmpty()) { + throw new QuinnException("INCOMPLETE COMMAND" + + System.lineSeparator() + "\t" + + "The description of a deadline cannot be empty!"); + } + + if (deadlineByDateTime.isEmpty()) { + throw new QuinnException("INCOMPLETE COMMAND" + + System.lineSeparator() + "\t" + + "The date/time of a deadline cannot be empty!" + + System.lineSeparator() + "\t" + + "[Note: Enter /by before specifying the date/time]"); + } + + return commandInfo; + } } - public void listTasks() { - StringBuilder sb = new StringBuilder(); + private String processTaskInfoFromEventCommand(String commandInfo) throws QuinnException { + if (!isCommandInfoPresent(commandInfo)) { + throw new QuinnException("INCOMPLETE COMMAND" + + System.lineSeparator() + "\t" + + "The description and date/time of an event cannot be empty!" + + System.lineSeparator() + "\t" + + "[Note: Specify the date/time with '/from /to']"); + } else { + String[] eventInfoParts = commandInfo.split("/from|/to", 3); + + if (eventInfoParts.length != 3) { + throw new QuinnException("INVALID COMMAND" + + System.lineSeparator() + "\t" + + "Please check that the description and date/time of an event is present!" + + System.lineSeparator() + "\t" + + "[Note: Specify the date/time with '/from /to']"); + } - sb.append("\t") - .append(tasks.size() > 1 ? "Here are the tasks in your list:" : "Here is the task in your list:") - .append(System.lineSeparator()) - .append("\t") - .append("[Legend: T = todo, D = deadline, E = event]") - .append(System.lineSeparator()); + String eventDescription = eventInfoParts[0].trim(); + String eventFromDateTime = eventInfoParts[1].trim(); + String eventToDateTime = eventInfoParts[2].trim(); + + if (eventDescription.isEmpty()) { + throw new QuinnException("INCOMPLETE COMMAND" + + System.lineSeparator() + "\t" + + "The description of an event cannot be empty!"); + } - for (int i = 0; i < tasks.size(); i++) { - if (i != 0) { - sb.append(System.lineSeparator()); + if (eventFromDateTime.isEmpty() || eventToDateTime.isEmpty()) { + throw new QuinnException("INCOMPLETE COMMAND" + + System.lineSeparator() + "\t" + + "The date/time of an event cannot be empty!" + + System.lineSeparator() + "\t" + + "[Note: Specify the date/time with '/from /to']"); } - sb.append("\t") - .append(i + 1) - .append(". ") - .append(tasks.get(i)); + return commandInfo; } + } + + public void addTask(Task task) { + tasks.add(task); + + String response = ui.taskAddedMessage(task) + + System.lineSeparator() + + ui.numOfTasksInListMessage(tasks); + ui.displayResponse(response); + } - echo(sb.toString()); + public void displayTasks() throws QuinnException { + if (!tasks.isEmpty()) { + String response = ui.tasksInListMessage(tasks); + ui.displayResponse(response); + } else { + throw new QuinnException("There are no tasks in your list!"); + } } - public void markTask(int taskNum) { - Task task = tasks.get(taskNum - 1); - task.setDone(); + public void markTask(int taskNum) throws QuinnException { + if (taskNum > 0 && taskNum <= tasks.size()) { + Task task = tasks.get(taskNum - 1); + task.setDone(); - String message = "\t" + "Nice! I've marked this task as done:" - + System.lineSeparator() + "\t\t" + task; - echo(message); + String message = ui.taskDoneMessage(task); + ui.displayResponse(message); + } else { + throw new QuinnException("Task not found. Please try again!"); + } } - public void unmarkTask(int taskNum) { - Task task = tasks.get(taskNum - 1); - task.setNotDone(); + public void unmarkTask(int taskNum) throws QuinnException { + if (taskNum > 0 && taskNum <= tasks.size()) { + Task task = tasks.get(taskNum - 1); + task.setNotDone(); - String message = "\t" + "OK, I've marked this task as not done yet:" - + System.lineSeparator() + "\t\t" + task; - echo(message); + String message = ui.taskNotDoneMessage(task); + ui.displayResponse(message); + } else { + throw new QuinnException("Task not found. Please try again!"); + } } } diff --git a/src/main/java/QuinnException.java b/src/main/java/QuinnException.java new file mode 100644 index 000000000..3b1a71c80 --- /dev/null +++ b/src/main/java/QuinnException.java @@ -0,0 +1,5 @@ +public class QuinnException extends Exception { + public QuinnException(String errorMessage) { + super(errorMessage); + } +} diff --git a/src/main/java/Task.java b/src/main/java/Task.java index f16b291ed..f0f676fdf 100644 --- a/src/main/java/Task.java +++ b/src/main/java/Task.java @@ -16,7 +16,7 @@ public Task(TaskType type, String description, boolean isDone) { public String getStatusIcon() { if (isDone) { - return "[✔️]"; // mark done task with ✔️ + return "[✔]"; // mark done task with ✔ } else { return "[ ]"; } diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java new file mode 100644 index 000000000..1334b78c9 --- /dev/null +++ b/src/main/java/Ui.java @@ -0,0 +1,97 @@ +import java.util.List; +import java.util.Scanner; + +public class Ui { + public Ui() { + } + + public String readCommand() { + Scanner sc = new Scanner(System.in); + System.out.println("Enter Command:"); + System.out.print("\t"); + return sc.nextLine().trim(); + } + + public void displayWelcome() { + String logo = "\t" + " QQQ U U III N N N N " + System.lineSeparator() + + "\t" + " Q Q U U I NN N NN N " + System.lineSeparator() + + "\t" + " Q Q U U I N N N N N N " + System.lineSeparator() + + "\t" + " Q Q U U I N NN N NN " + System.lineSeparator() + + "\t" + " QQQ UUU III N N N N " + System.lineSeparator() + + "\t" + " Q " + System.lineSeparator() + + "\t" + " QQ " + System.lineSeparator(); + + String welcomeMessage = "\t" + "Hello! I'm Quinn, your Personal Assistant ChatBot." + + System.lineSeparator() + + System.lineSeparator() + + logo + + System.lineSeparator() + + "\t" + "What can I do for you?"; + + displayResponse(welcomeMessage); + displayLine(); + } + + public void displayExit() { + String exitMessage = "\t" + "Bye. Hope to see you again soon!"; + displayResponse(exitMessage); + } + + public void displayResponse(String message) { + displayLine(); + System.out.println(message); + } + + public void displayError(String message) { + displayLine(); + System.out.println("Error Message:"); + System.out.println("\t" + "('-')? " + message); + } + + public void displayLine() { + String horizontalLine = "____________________________________________________________"; + System.out.println(horizontalLine); + } + + public String taskAddedMessage(Task task) { + return "\t" + "Got it. I've added this task:" + + System.lineSeparator() + "\t\t" + task; + } + + public String taskDoneMessage(Task task) { + return "\t" + "Nice! I've marked this task as done:" + + System.lineSeparator() + "\t\t" + task; + } + + public String taskNotDoneMessage(Task task) { + return "\t" + "OK, I've marked this task as not done yet:" + + System.lineSeparator() + "\t\t" + task; + } + + public String numOfTasksInListMessage(List tasks) { + return "\t" + "Now you have " + tasks.size() + + (tasks.size() > 1 ? " tasks" : " task") + + " in the list."; + } + + public String tasksInListMessage(List tasks) { + StringBuilder sb = new StringBuilder(); + + sb.append("\t") + .append(tasks.size() > 1 ? "Here are the tasks in your list:" : "Here is the task in your list:") + .append(System.lineSeparator()) + .append("\t") + .append("[Legend: T = todo, D = deadline, E = event]") + .append(System.lineSeparator()); + + for (int i = 0; i < tasks.size(); i++) { + if (i != 0) { + sb.append(System.lineSeparator()); + } + + sb.append("\t").append(i + 1).append(". ").append(tasks.get(i)); + } + + return sb.toString(); + } +} From 8e7dc1c287af94941aeefd9485592e5a7a72d1c6 Mon Sep 17 00:00:00 2001 From: kaboomzxc Date: Tue, 10 Sep 2024 17:33:03 +0800 Subject: [PATCH 07/28] Organise classes into different packages --- README.md | 4 ++-- docs/README.md | 2 +- src/main/java/{ => quinn}/Quinn.java | 21 +++++++++++++------ .../{ => quinn/exception}/QuinnException.java | 2 ++ src/main/java/{ => quinn/task}/Deadline.java | 2 ++ src/main/java/{ => quinn/task}/Event.java | 2 ++ src/main/java/{ => quinn/task}/Task.java | 6 ++++-- src/main/java/{ => quinn/task}/TaskType.java | 2 ++ src/main/java/{ => quinn/task}/ToDo.java | 2 ++ src/main/java/{ => quinn/ui}/Ui.java | 14 ++++++++----- text-ui-test/runtest.bat | 2 +- 11 files changed, 42 insertions(+), 17 deletions(-) rename src/main/java/{ => quinn}/Quinn.java (92%) rename src/main/java/{ => quinn/exception}/QuinnException.java (83%) rename src/main/java/{ => quinn/task}/Deadline.java (96%) rename src/main/java/{ => quinn/task}/Event.java (97%) rename src/main/java/{ => quinn/task}/Task.java (85%) rename src/main/java/{ => quinn/task}/TaskType.java (92%) rename src/main/java/{ => quinn/task}/ToDo.java (91%) rename src/main/java/{ => quinn/ui}/Ui.java (88%) diff --git a/README.md b/README.md index d27d14052..2e370c37c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Quinn project template +# quinn.Quinn 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. @@ -13,7 +13,7 @@ Prerequisites: JDK 17, update Intellij to the most recent version. 1. If there are any further prompts, accept the defaults. 1. Configure the project to use **JDK 17** (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/Quinn.java` file, right-click it, and choose `Run Quinn.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: +3. After that, locate the `src/main/java/quinn.Quinn.java` file, right-click it, and choose `Run quinn.Quinn.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 ____ _ diff --git a/docs/README.md b/docs/README.md index 1ed55ceea..fa75c6e58 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,4 +1,4 @@ -# Quinn User Guide +# quinn.Quinn User Guide // Update the title above to match the actual product name diff --git a/src/main/java/Quinn.java b/src/main/java/quinn/Quinn.java similarity index 92% rename from src/main/java/Quinn.java rename to src/main/java/quinn/Quinn.java index 01e1b0deb..3c3420ad3 100644 --- a/src/main/java/Quinn.java +++ b/src/main/java/quinn/Quinn.java @@ -1,3 +1,12 @@ +package quinn; + +import quinn.exception.QuinnException; +import quinn.task.Deadline; +import quinn.task.Event; +import quinn.task.Task; +import quinn.task.ToDo; +import quinn.ui.Ui; + import java.util.ArrayList; import java.util.List; @@ -105,10 +114,10 @@ private int getTaskNumFromMarkCommand(String commandInfo) throws QuinnException try { return Integer.parseInt(commandInfo); } catch (NumberFormatException e) { - throw new QuinnException("Please enter a valid task number to be marked as done!"); + throw new QuinnException("Please enter a valid quinn.task number to be marked as done!"); } } else { - throw new QuinnException("Please enter a task number to be marked as done!"); + throw new QuinnException("Please enter a quinn.task number to be marked as done!"); } } @@ -117,10 +126,10 @@ private int getTaskNumFromUnmarkCommand(String commandInfo) throws QuinnExceptio try { return Integer.parseInt(commandInfo); } catch (NumberFormatException e) { - throw new QuinnException("Please enter a valid task number to be marked as not done yet!"); + throw new QuinnException("Please enter a valid quinn.task number to be marked as not done yet!"); } } else { - throw new QuinnException("Please enter a task number to be marked as not done yet!"); + throw new QuinnException("Please enter a quinn.task number to be marked as not done yet!"); } } @@ -237,7 +246,7 @@ public void markTask(int taskNum) throws QuinnException { String message = ui.taskDoneMessage(task); ui.displayResponse(message); } else { - throw new QuinnException("Task not found. Please try again!"); + throw new QuinnException("quinn.task.Task not found. Please try again!"); } } @@ -249,7 +258,7 @@ public void unmarkTask(int taskNum) throws QuinnException { String message = ui.taskNotDoneMessage(task); ui.displayResponse(message); } else { - throw new QuinnException("Task not found. Please try again!"); + throw new QuinnException("quinn.task.Task not found. Please try again!"); } } } diff --git a/src/main/java/QuinnException.java b/src/main/java/quinn/exception/QuinnException.java similarity index 83% rename from src/main/java/QuinnException.java rename to src/main/java/quinn/exception/QuinnException.java index 3b1a71c80..b1591287d 100644 --- a/src/main/java/QuinnException.java +++ b/src/main/java/quinn/exception/QuinnException.java @@ -1,3 +1,5 @@ +package quinn.exception; + public class QuinnException extends Exception { public QuinnException(String errorMessage) { super(errorMessage); diff --git a/src/main/java/Deadline.java b/src/main/java/quinn/task/Deadline.java similarity index 96% rename from src/main/java/Deadline.java rename to src/main/java/quinn/task/Deadline.java index b41eb06bc..dd1eebdc6 100644 --- a/src/main/java/Deadline.java +++ b/src/main/java/quinn/task/Deadline.java @@ -1,3 +1,5 @@ +package quinn.task; + public class Deadline extends Task { private final String byDateTimeInput; diff --git a/src/main/java/Event.java b/src/main/java/quinn/task/Event.java similarity index 97% rename from src/main/java/Event.java rename to src/main/java/quinn/task/Event.java index 834b74d17..bf75835ce 100644 --- a/src/main/java/Event.java +++ b/src/main/java/quinn/task/Event.java @@ -1,3 +1,5 @@ +package quinn.task; + public class Event extends Task { private final String fromDateTimeInput; private final String toDateTimeInput; diff --git a/src/main/java/Task.java b/src/main/java/quinn/task/Task.java similarity index 85% rename from src/main/java/Task.java rename to src/main/java/quinn/task/Task.java index f0f676fdf..ee5421a52 100644 --- a/src/main/java/Task.java +++ b/src/main/java/quinn/task/Task.java @@ -1,10 +1,12 @@ +package quinn.task; + public abstract class Task { private final TaskType type; private final String description; private boolean isDone; public Task(TaskType type, String description) { - // By default, the task is not done + // By default, the quinn.task is not done this(type, description, false); } @@ -16,7 +18,7 @@ public Task(TaskType type, String description, boolean isDone) { public String getStatusIcon() { if (isDone) { - return "[✔]"; // mark done task with ✔ + return "[✔]"; // mark done quinn.task with ✔ } else { return "[ ]"; } diff --git a/src/main/java/TaskType.java b/src/main/java/quinn/task/TaskType.java similarity index 92% rename from src/main/java/TaskType.java rename to src/main/java/quinn/task/TaskType.java index e52044cec..07eb5e556 100644 --- a/src/main/java/TaskType.java +++ b/src/main/java/quinn/task/TaskType.java @@ -1,3 +1,5 @@ +package quinn.task; + public enum TaskType { TODO("T"), DEADLINE("D"), diff --git a/src/main/java/ToDo.java b/src/main/java/quinn/task/ToDo.java similarity index 91% rename from src/main/java/ToDo.java rename to src/main/java/quinn/task/ToDo.java index 60d7a50ce..7ddf95c5d 100644 --- a/src/main/java/ToDo.java +++ b/src/main/java/quinn/task/ToDo.java @@ -1,3 +1,5 @@ +package quinn.task; + public class ToDo extends Task { public ToDo(String description) { super(TaskType.TODO, description); diff --git a/src/main/java/Ui.java b/src/main/java/quinn/ui/Ui.java similarity index 88% rename from src/main/java/Ui.java rename to src/main/java/quinn/ui/Ui.java index 1334b78c9..bee9c5379 100644 --- a/src/main/java/Ui.java +++ b/src/main/java/quinn/ui/Ui.java @@ -1,3 +1,7 @@ +package quinn.ui; + +import quinn.task.Task; + import java.util.List; import java.util.Scanner; @@ -21,7 +25,7 @@ public void displayWelcome() { + "\t" + " Q " + System.lineSeparator() + "\t" + " QQ " + System.lineSeparator(); - String welcomeMessage = "\t" + "Hello! I'm Quinn, your Personal Assistant ChatBot." + String welcomeMessage = "\t" + "Hello! I'm quinn.Quinn, your Personal Assistant ChatBot." + System.lineSeparator() + System.lineSeparator() + logo @@ -54,17 +58,17 @@ public void displayLine() { } public String taskAddedMessage(Task task) { - return "\t" + "Got it. I've added this task:" + return "\t" + "Got it. I've added this quinn.task:" + System.lineSeparator() + "\t\t" + task; } public String taskDoneMessage(Task task) { - return "\t" + "Nice! I've marked this task as done:" + return "\t" + "Nice! I've marked this quinn.task as done:" + System.lineSeparator() + "\t\t" + task; } public String taskNotDoneMessage(Task task) { - return "\t" + "OK, I've marked this task as not done yet:" + return "\t" + "OK, I've marked this quinn.task as not done yet:" + System.lineSeparator() + "\t\t" + task; } @@ -78,7 +82,7 @@ public String tasksInListMessage(List tasks) { StringBuilder sb = new StringBuilder(); sb.append("\t") - .append(tasks.size() > 1 ? "Here are the tasks in your list:" : "Here is the task in your list:") + .append(tasks.size() > 1 ? "Here are the tasks in your list:" : "Here is the quinn.task in your list:") .append(System.lineSeparator()) .append("\t") .append("[Legend: T = todo, D = deadline, E = event]") diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat index 43ebe9053..a71f37185 100644 --- a/text-ui-test/runtest.bat +++ b/text-ui-test/runtest.bat @@ -15,7 +15,7 @@ IF ERRORLEVEL 1 ( REM no error here, errorlevel == 0 REM run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT -java -classpath ..\bin Quinn < input.txt > ACTUAL.TXT +java -classpath ..\bin quinn.Quinn < input.txt > ACTUAL.TXT REM compare the output to the expected output FC ACTUAL.TXT EXPECTED.TXT From 53936b586b99b4b5e6ca0bc57dbabff649b894ef Mon Sep 17 00:00:00 2001 From: kaboomzxc Date: Tue, 10 Sep 2024 17:43:57 +0800 Subject: [PATCH 08/28] Update README.md --- README.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 2e370c37c..831573b25 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# quinn.Quinn project template +# Quinn 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. @@ -13,12 +13,15 @@ Prerequisites: JDK 17, update Intellij to the most recent version. 1. If there are any further prompts, accept the defaults. 1. Configure the project to use **JDK 17** (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/quinn.Quinn.java` file, right-click it, and choose `Run quinn.Quinn.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: +3. After that, locate the `src/main/java/quinn/Quinn.java` file, right-click it, and choose `Run Quinn.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 - ____ _ - | _ \ _ _| | _____ - | | | | | | | |/ / _ \ - | |_| | |_| | < __/ - |____/ \__,_|_|\_\___| + + QQQ U U III N N N N + Q Q U U I NN N NN N + Q Q U U I N N N N N N + Q Q U U I N NN N NN + QQQ UUU III N N N N + Q + QQ ``` From b25c7de696c0ccf476ca62a10cad709ad732e5e5 Mon Sep 17 00:00:00 2001 From: kaboomzxc Date: Tue, 10 Sep 2024 17:50:34 +0800 Subject: [PATCH 09/28] Implement Level-6 --- src/main/java/quinn/Quinn.java | 30 ++++++++++++++++++++++++++++++ src/main/java/quinn/ui/Ui.java | 5 +++++ 2 files changed, 35 insertions(+) diff --git a/src/main/java/quinn/Quinn.java b/src/main/java/quinn/Quinn.java index 3c3420ad3..a594e9efc 100644 --- a/src/main/java/quinn/Quinn.java +++ b/src/main/java/quinn/Quinn.java @@ -83,6 +83,10 @@ public void executeCommand(String commandType, String commandInfo) throws QuinnE taskNum = getTaskNumFromUnmarkCommand(commandInfo); unmarkTask(taskNum); break; + case "delete": + taskNum = getTaskNumFromDeleteCommand(commandInfo); + deleteTask(taskNum); + break; case "todo": taskDescription = getTaskDescriptionFromToDoCommand(commandInfo); task = new ToDo(taskDescription); @@ -133,6 +137,18 @@ private int getTaskNumFromUnmarkCommand(String commandInfo) throws QuinnExceptio } } + private int getTaskNumFromDeleteCommand(String commandInfo) throws QuinnException { + if (isCommandInfoPresent(commandInfo)) { + try { + return Integer.parseInt(commandInfo); + } catch (NumberFormatException e) { + throw new QuinnException("Please enter a valid task number to be deleted!"); + } + } else { + throw new QuinnException("Please enter a task number to be deleted!"); + } + } + private String getTaskDescriptionFromToDoCommand(String commandInfo) throws QuinnException { if (isCommandInfoPresent(commandInfo)) { return commandInfo; @@ -261,4 +277,18 @@ public void unmarkTask(int taskNum) throws QuinnException { throw new QuinnException("quinn.task.Task not found. Please try again!"); } } + + public void deleteTask(int taskNum) throws QuinnException { + if (taskNum > 0 && taskNum <= tasks.size()) { + Task task = tasks.get(taskNum - 1); + tasks.remove(task); + + String message = ui.taskDeletedMessage(task) + + System.lineSeparator() + + ui.numOfTasksInListMessage(tasks); + ui.displayResponse(message); + } else { + throw new QuinnException("Task not found. Please try again!"); + } + } } diff --git a/src/main/java/quinn/ui/Ui.java b/src/main/java/quinn/ui/Ui.java index bee9c5379..621e6c4df 100644 --- a/src/main/java/quinn/ui/Ui.java +++ b/src/main/java/quinn/ui/Ui.java @@ -72,6 +72,11 @@ public String taskNotDoneMessage(Task task) { + System.lineSeparator() + "\t\t" + task; } + public String taskDeletedMessage(Task task) { + return "\t" + "Noted. I've removed this task:" + + System.lineSeparator() + "\t\t" + task; + } + public String numOfTasksInListMessage(List tasks) { return "\t" + "Now you have " + tasks.size() + (tasks.size() > 1 ? " tasks" : " task") From b06b90c2619cc18b7b1f54330b90215f381a0204 Mon Sep 17 00:00:00 2001 From: kaboomzxc Date: Tue, 10 Sep 2024 18:52:38 +0800 Subject: [PATCH 10/28] Fix some text errors due to refactoring --- src/main/java/quinn/task/Task.java | 4 ++-- src/main/java/quinn/ui/Ui.java | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/quinn/task/Task.java b/src/main/java/quinn/task/Task.java index ee5421a52..77ea7a9ce 100644 --- a/src/main/java/quinn/task/Task.java +++ b/src/main/java/quinn/task/Task.java @@ -6,7 +6,7 @@ public abstract class Task { private boolean isDone; public Task(TaskType type, String description) { - // By default, the quinn.task is not done + // By default, the task is not done this(type, description, false); } @@ -18,7 +18,7 @@ public Task(TaskType type, String description, boolean isDone) { public String getStatusIcon() { if (isDone) { - return "[✔]"; // mark done quinn.task with ✔ + return "[✔]"; // mark done task with ✔ } else { return "[ ]"; } diff --git a/src/main/java/quinn/ui/Ui.java b/src/main/java/quinn/ui/Ui.java index bee9c5379..c15c60aed 100644 --- a/src/main/java/quinn/ui/Ui.java +++ b/src/main/java/quinn/ui/Ui.java @@ -25,7 +25,7 @@ public void displayWelcome() { + "\t" + " Q " + System.lineSeparator() + "\t" + " QQ " + System.lineSeparator(); - String welcomeMessage = "\t" + "Hello! I'm quinn.Quinn, your Personal Assistant ChatBot." + String welcomeMessage = "\t" + "Hello! I'm Quinn, your Personal Assistant ChatBot." + System.lineSeparator() + System.lineSeparator() + logo @@ -58,17 +58,17 @@ public void displayLine() { } public String taskAddedMessage(Task task) { - return "\t" + "Got it. I've added this quinn.task:" + return "\t" + "Got it. I've added this task:" + System.lineSeparator() + "\t\t" + task; } public String taskDoneMessage(Task task) { - return "\t" + "Nice! I've marked this quinn.task as done:" + return "\t" + "Nice! I've marked this task as done:" + System.lineSeparator() + "\t\t" + task; } public String taskNotDoneMessage(Task task) { - return "\t" + "OK, I've marked this quinn.task as not done yet:" + return "\t" + "OK, I've marked this task as not done yet:" + System.lineSeparator() + "\t\t" + task; } @@ -82,7 +82,7 @@ public String tasksInListMessage(List tasks) { StringBuilder sb = new StringBuilder(); sb.append("\t") - .append(tasks.size() > 1 ? "Here are the tasks in your list:" : "Here is the quinn.task in your list:") + .append(tasks.size() > 1 ? "Here are the tasks in your list:" : "Here is the task in your list:") .append(System.lineSeparator()) .append("\t") .append("[Legend: T = todo, D = deadline, E = event]") From bdaa224fa5d83bae57256c0083a27713677ac59b Mon Sep 17 00:00:00 2001 From: kaboomzxc Date: Tue, 10 Sep 2024 18:58:34 +0800 Subject: [PATCH 11/28] Fix text errors in Quinn java file --- src/main/java/quinn/Quinn.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/quinn/Quinn.java b/src/main/java/quinn/Quinn.java index 3c3420ad3..a12680da5 100644 --- a/src/main/java/quinn/Quinn.java +++ b/src/main/java/quinn/Quinn.java @@ -114,10 +114,10 @@ private int getTaskNumFromMarkCommand(String commandInfo) throws QuinnException try { return Integer.parseInt(commandInfo); } catch (NumberFormatException e) { - throw new QuinnException("Please enter a valid quinn.task number to be marked as done!"); + throw new QuinnException("Please enter a valid task number to be marked as done!"); } } else { - throw new QuinnException("Please enter a quinn.task number to be marked as done!"); + throw new QuinnException("Please enter a task number to be marked as done!"); } } @@ -126,10 +126,10 @@ private int getTaskNumFromUnmarkCommand(String commandInfo) throws QuinnExceptio try { return Integer.parseInt(commandInfo); } catch (NumberFormatException e) { - throw new QuinnException("Please enter a valid quinn.task number to be marked as not done yet!"); + throw new QuinnException("Please enter a valid task number to be marked as not done yet!"); } } else { - throw new QuinnException("Please enter a quinn.task number to be marked as not done yet!"); + throw new QuinnException("Please enter a task number to be marked as not done yet!"); } } @@ -246,7 +246,7 @@ public void markTask(int taskNum) throws QuinnException { String message = ui.taskDoneMessage(task); ui.displayResponse(message); } else { - throw new QuinnException("quinn.task.Task not found. Please try again!"); + throw new QuinnException("Task not found. Please try again!"); } } @@ -258,7 +258,7 @@ public void unmarkTask(int taskNum) throws QuinnException { String message = ui.taskNotDoneMessage(task); ui.displayResponse(message); } else { - throw new QuinnException("quinn.task.Task not found. Please try again!"); + throw new QuinnException("Task not found. Please try again!"); } } } From 9dde6b830b9082209e0487c7b3c39a33e28420bb Mon Sep 17 00:00:00 2001 From: kaboomzxc Date: Mon, 16 Sep 2024 14:26:09 +0800 Subject: [PATCH 12/28] Implement Level-7 --- src/main/java/quinn/Quinn.java | 36 ++++-- src/main/java/quinn/storage/Storage.java | 139 +++++++++++++++++++++++ src/main/java/quinn/task/Deadline.java | 4 + src/main/java/quinn/task/Event.java | 4 + src/main/java/quinn/task/Task.java | 4 + 5 files changed, 177 insertions(+), 10 deletions(-) create mode 100644 src/main/java/quinn/storage/Storage.java diff --git a/src/main/java/quinn/Quinn.java b/src/main/java/quinn/Quinn.java index a12680da5..28dc4eb23 100644 --- a/src/main/java/quinn/Quinn.java +++ b/src/main/java/quinn/Quinn.java @@ -6,21 +6,31 @@ import quinn.task.Task; import quinn.task.ToDo; import quinn.ui.Ui; +import quinn.storage.Storage; +import java.io.IOException; import java.util.ArrayList; import java.util.List; public class Quinn { - private static final List tasks = new ArrayList<>(); - private final Ui ui; + private Storage storage; + private List tasks; - public Quinn() { + public Quinn(String folderName, String fileName) { ui = new Ui(); + + try { + storage = new Storage(folderName, fileName); + tasks = storage.loadTasksFromFile(); + } catch (QuinnException | IOException e) { + ui.displayError(e.getMessage()); + tasks = new ArrayList<>(); + } } public static void main(String[] args) { - new Quinn().run(); + new Quinn("data", "tasks.txt").run(); } public void run() { @@ -33,7 +43,7 @@ public void run() { try { processCommand(commandLine); - } catch (QuinnException e) { + } catch (QuinnException | IOException e) { ui.displayError(e.getMessage()); } finally { ui.displayLine(); @@ -41,7 +51,7 @@ public void run() { } } - public void processCommand(String commandLine) throws QuinnException { + public void processCommand(String commandLine) throws QuinnException, IOException { String[] commandLineParts = commandLine.split(" ", 2); String commandType; @@ -62,7 +72,7 @@ public void processCommand(String commandLine) throws QuinnException { executeCommand(commandType, commandInfo); } - public void executeCommand(String commandType, String commandInfo) throws QuinnException { + public void executeCommand(String commandType, String commandInfo) throws QuinnException, IOException { int taskNum; Task task; String taskDescription; @@ -220,13 +230,15 @@ private String processTaskInfoFromEventCommand(String commandInfo) throws QuinnE } } - public void addTask(Task task) { + public void addTask(Task task) throws IOException { tasks.add(task); String response = ui.taskAddedMessage(task) + System.lineSeparator() + ui.numOfTasksInListMessage(tasks); ui.displayResponse(response); + + storage.saveTasksToFile(tasks); } public void displayTasks() throws QuinnException { @@ -238,25 +250,29 @@ public void displayTasks() throws QuinnException { } } - public void markTask(int taskNum) throws QuinnException { + public void markTask(int taskNum) throws QuinnException, IOException { if (taskNum > 0 && taskNum <= tasks.size()) { Task task = tasks.get(taskNum - 1); task.setDone(); String message = ui.taskDoneMessage(task); ui.displayResponse(message); + + storage.saveTasksToFile(tasks); } else { throw new QuinnException("Task not found. Please try again!"); } } - public void unmarkTask(int taskNum) throws QuinnException { + public void unmarkTask(int taskNum) throws QuinnException, IOException { if (taskNum > 0 && taskNum <= tasks.size()) { Task task = tasks.get(taskNum - 1); task.setNotDone(); String message = ui.taskNotDoneMessage(task); ui.displayResponse(message); + + storage.saveTasksToFile(tasks); } else { throw new QuinnException("Task not found. Please try again!"); } diff --git a/src/main/java/quinn/storage/Storage.java b/src/main/java/quinn/storage/Storage.java new file mode 100644 index 000000000..c6a0f931d --- /dev/null +++ b/src/main/java/quinn/storage/Storage.java @@ -0,0 +1,139 @@ +package quinn.storage; + +import quinn.exception.QuinnException; +import quinn.task.*; + +import java.io.*; +import java.util.ArrayList; +import java.util.List; + +/** + * A class that handles create, read and write file operations. + */ +public class Storage { + private final File dataFile; + + /** + * Constructor to initialize an instance of Storage class with folder + * name and file name. + * + * @param folderName Folder name of the quinn.storage file + * @param fileName Name of the quinn.storage file + * @throws QuinnException If the directory cannot be initialised + * @throws IOException If the quinn.storage file cannot be initialised + */ + public Storage(String folderName, String fileName) throws QuinnException, IOException { + File directory = initialiseDirectory(folderName); + dataFile = initialiseFile(directory, fileName); + } + + /** + * Initializes the directory of the quinn.storage file. + * Creates the directory if it does not exist. + * + * @param folderName Folder name of the quinn.storage file + * @return The file that represents the relative path of the directory + * @throws QuinnException If the directory cannot be initialised + */ + private File initialiseDirectory(String folderName) throws QuinnException { + File directory = new File(folderName); + boolean hasDirectory = directory.exists(); + + if (!hasDirectory) { + hasDirectory = directory.mkdir(); + } + + if (hasDirectory) { + return directory; + } else { + throw new QuinnException("\t" + "Unable to initialise directory"); + } + } + + /** + * Initializes the quinn.storage file. + * Creates the quinn.storage file if it does not exist. + * + * @param directory Relative path of the directory + * @param fileName Name of the quinn.storage file + * @return The quinn.storage file + * @throws IOException If the quinn.storage file cannot be initialised + */ + private File initialiseFile(File directory, String fileName) throws IOException { + File file = new File(directory + "/" + fileName); + boolean hasFile = file.exists(); + + if (!hasFile) { + hasFile = file.createNewFile(); + } + + if (hasFile) { + return file; + } else { + throw new IOException("\t" + "Unable to initialise file"); + } + } + + /** + * Loads all the tasks in the quinn.storage file to the task list. + * + * @return The list containing the tasks + * @throws IOException If the quinn.storage file or task cannot be read + * @throws QuinnException If an invalid type of task is found + */ + public List loadTasksFromFile() throws QuinnException, IOException { + List tasks = new ArrayList<>(); + + FileReader fileReader = new FileReader(dataFile); + BufferedReader bufferedReader = new BufferedReader(fileReader); + String line; + + while ((line = bufferedReader.readLine()) != null) { + String[] taskDetails = line.trim().split("\\|"); + String type = taskDetails[0].trim(); + boolean isDone = (Integer.parseInt(taskDetails[1].trim()) == 1); + String description = taskDetails[2].trim(); + + if (type.equals(TaskType.TODO.getAbbreviation())) { + Task todoTask = new ToDo(description, isDone); + tasks.add(todoTask); + } else if (type.equals(TaskType.DEADLINE.getAbbreviation())) { + String byDateTime = taskDetails[3].trim(); + Task deadlineTask = new Deadline(description, byDateTime, isDone); + tasks.add(deadlineTask); + } else if (type.equals(TaskType.EVENT.getAbbreviation())) { + String fromDateTimeInput = taskDetails[3].trim(); + String toDateTimeInput = taskDetails[4].trim(); + Task eventTask = new Event(description, fromDateTimeInput, toDateTimeInput, isDone); + tasks.add(eventTask); + } else { + // Error detection for any invalid type of tasks found in the + // quinn.storage file. This should not happen since the user is only + // allowed to create todo [T], deadline [D] and event [E] tasks. + throw new QuinnException("INVALID TYPE OF TASK FOUND"); + } + } + + bufferedReader.close(); + + return tasks; + } + + /** + * Saves all the tasks in the task list to the quinn.storage file. + * + * @param tasks List containing the tasks to be saved + * @throws IOException If the tasks cannot be saved + */ + public void saveTasksToFile(List tasks) throws IOException { + FileWriter fileWriter = new FileWriter(dataFile,false); + BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); + + for (int i = 0; i < tasks.size(); i++) { + Task task = tasks.get(i); + bufferedWriter.write(task.saveFormat() + System.lineSeparator()); + } + + bufferedWriter.close(); + } +} diff --git a/src/main/java/quinn/task/Deadline.java b/src/main/java/quinn/task/Deadline.java index dd1eebdc6..bdddb7441 100644 --- a/src/main/java/quinn/task/Deadline.java +++ b/src/main/java/quinn/task/Deadline.java @@ -16,4 +16,8 @@ public Deadline(String description, String byDateTimeInput, boolean isDone) { public String toString() { return super.toString() + " (by: " + byDateTimeInput + ")"; } + + public String saveFormat() { + return super.saveFormat() + " | " + byDateTimeInput; + } } diff --git a/src/main/java/quinn/task/Event.java b/src/main/java/quinn/task/Event.java index bf75835ce..32bc7af4b 100644 --- a/src/main/java/quinn/task/Event.java +++ b/src/main/java/quinn/task/Event.java @@ -18,4 +18,8 @@ public Event(String description, String fromDateTimeInput, String toDateTimeInpu public String toString() { return super.toString() + " (from: " + fromDateTimeInput + " to: " + toDateTimeInput + ")"; } + + public String saveFormat() { + return super.saveFormat() + " | " + fromDateTimeInput + " | " + toDateTimeInput; + } } diff --git a/src/main/java/quinn/task/Task.java b/src/main/java/quinn/task/Task.java index 77ea7a9ce..4cb35caf0 100644 --- a/src/main/java/quinn/task/Task.java +++ b/src/main/java/quinn/task/Task.java @@ -36,4 +36,8 @@ public void setNotDone() { public String toString() { return "[" + type.getAbbreviation() + "] " + getStatusIcon() + " " + description; } + + public String saveFormat() { + return type.getAbbreviation() + " | " + (isDone ? "1" : "0") + " | " + description; + } } From db7785fbc783c487e11409efaea254ac4ec431f8 Mon Sep 17 00:00:00 2001 From: kaboomzxc Date: Mon, 16 Sep 2024 14:34:34 +0800 Subject: [PATCH 13/28] Implement saving after deletion of tasks --- src/main/java/quinn/Quinn.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/quinn/Quinn.java b/src/main/java/quinn/Quinn.java index 2632774e8..e28885d8f 100644 --- a/src/main/java/quinn/Quinn.java +++ b/src/main/java/quinn/Quinn.java @@ -294,7 +294,7 @@ public void unmarkTask(int taskNum) throws QuinnException, IOException { } } - public void deleteTask(int taskNum) throws QuinnException { + public void deleteTask(int taskNum) throws QuinnException, IOException { if (taskNum > 0 && taskNum <= tasks.size()) { Task task = tasks.get(taskNum - 1); tasks.remove(task); @@ -303,6 +303,8 @@ public void deleteTask(int taskNum) throws QuinnException { + System.lineSeparator() + ui.numOfTasksInListMessage(tasks); ui.displayResponse(message); + + storage.saveTasksToFile(tasks); } else { throw new QuinnException("Task not found. Please try again!"); } From 8a57ddfb883f9161f967a1dd45b6db503dcdd587 Mon Sep 17 00:00:00 2001 From: kaboomzxc Date: Tue, 17 Sep 2024 01:31:39 +0800 Subject: [PATCH 14/28] update some responses by quinn --- src/main/java/quinn/ui/Ui.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/quinn/ui/Ui.java b/src/main/java/quinn/ui/Ui.java index c2c88d03b..c2bae51f9 100644 --- a/src/main/java/quinn/ui/Ui.java +++ b/src/main/java/quinn/ui/Ui.java @@ -37,7 +37,7 @@ public void displayWelcome() { } public void displayExit() { - String exitMessage = "\t" + "Bye. Hope to see you again soon!"; + String exitMessage = "\t" + "Farewell. Hope to see you again soon!"; displayResponse(exitMessage); } @@ -63,7 +63,7 @@ public String taskAddedMessage(Task task) { } public String taskDoneMessage(Task task) { - return "\t" + "Nice! I've marked this task as done:" + return "\t" + "Roger! I've marked this task as done:" + System.lineSeparator() + "\t\t" + task; } From b35fedfef33bab867409e34906f4944f38f978ed Mon Sep 17 00:00:00 2001 From: kaboomzxc Date: Thu, 26 Sep 2024 19:38:44 +0800 Subject: [PATCH 15/28] Implement A-MoreOOP, refactor code to extract out more classes --- src/main/java/quinn/Quinn.java | 288 +----------------- src/main/java/quinn/command/AddCommand.java | 27 ++ .../quinn/command/AddDeadlineCommand.java | 31 ++ .../java/quinn/command/AddEventCommand.java | 33 ++ .../java/quinn/command/AddToDoCommand.java | 25 ++ src/main/java/quinn/command/Command.java | 14 + src/main/java/quinn/command/CommandType.java | 22 ++ .../java/quinn/command/DeleteCommand.java | 38 +++ src/main/java/quinn/command/ExitCommand.java | 21 ++ src/main/java/quinn/command/ListCommand.java | 26 ++ src/main/java/quinn/command/MarkCommand.java | 36 +++ .../java/quinn/command/UnmarkCommand.java | 36 +++ src/main/java/quinn/parser/Parser.java | 224 ++++++++++++++ src/main/java/quinn/storage/Storage.java | 90 ++---- src/main/java/quinn/task/Deadline.java | 14 +- src/main/java/quinn/task/Event.java | 18 +- src/main/java/quinn/task/TaskList.java | 77 +++++ src/main/java/quinn/ui/Ui.java | 36 +-- 18 files changed, 681 insertions(+), 375 deletions(-) create mode 100644 src/main/java/quinn/command/AddCommand.java create mode 100644 src/main/java/quinn/command/AddDeadlineCommand.java create mode 100644 src/main/java/quinn/command/AddEventCommand.java create mode 100644 src/main/java/quinn/command/AddToDoCommand.java create mode 100644 src/main/java/quinn/command/Command.java create mode 100644 src/main/java/quinn/command/CommandType.java create mode 100644 src/main/java/quinn/command/DeleteCommand.java create mode 100644 src/main/java/quinn/command/ExitCommand.java create mode 100644 src/main/java/quinn/command/ListCommand.java create mode 100644 src/main/java/quinn/command/MarkCommand.java create mode 100644 src/main/java/quinn/command/UnmarkCommand.java create mode 100644 src/main/java/quinn/parser/Parser.java create mode 100644 src/main/java/quinn/task/TaskList.java diff --git a/src/main/java/quinn/Quinn.java b/src/main/java/quinn/Quinn.java index e28885d8f..d19b70650 100644 --- a/src/main/java/quinn/Quinn.java +++ b/src/main/java/quinn/Quinn.java @@ -1,31 +1,30 @@ package quinn; +import quinn.command.Command; import quinn.exception.QuinnException; -import quinn.task.Deadline; -import quinn.task.Event; -import quinn.task.Task; -import quinn.task.ToDo; +import quinn.parser.Parser; +import quinn.task.TaskList; import quinn.ui.Ui; import quinn.storage.Storage; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; public class Quinn { private final Ui ui; + private final Parser parser; private Storage storage; - private List tasks; + private TaskList taskList; public Quinn(String folderName, String fileName) { ui = new Ui(); + parser = new Parser(); try { storage = new Storage(folderName, fileName); - tasks = storage.loadTasksFromFile(); + taskList = storage.loadTasksFromFile(); } catch (QuinnException | IOException e) { ui.displayError(e.getMessage()); - tasks = new ArrayList<>(); + taskList = new TaskList(); } } @@ -35,14 +34,14 @@ public static void main(String[] args) { public void run() { ui.displayWelcome(); + boolean isExit = false; - String commandLine = ""; - - while (!commandLine.equals("bye")) { - commandLine = ui.readCommand(); - + while (!isExit) { try { - processCommand(commandLine); + String commandLine = ui.readCommand(); + Command command = parser.parse(commandLine); + command.execute(taskList, ui, storage); + isExit = command.isExit(); } catch (QuinnException | IOException e) { ui.displayError(e.getMessage()); } finally { @@ -50,263 +49,4 @@ public void run() { } } } - - public void processCommand(String commandLine) throws QuinnException, IOException { - String[] commandLineParts = commandLine.split(" ", 2); - - String commandType; - String commandInfo; - - if (commandLineParts.length == 2) { - commandType = commandLineParts[0].trim(); - commandInfo = commandLineParts[1].trim(); - - if ((commandType.equals("bye") || commandType.equals("list")) && !commandInfo.isEmpty()) { - throw new QuinnException("INVALID COMMAND. Please try again!"); - } - } else { // for "bye" and "list" commands which does not have any input behind - commandType = commandLineParts[0]; - commandInfo = ""; - } - - executeCommand(commandType, commandInfo); - } - - public void executeCommand(String commandType, String commandInfo) throws QuinnException, IOException { - int taskNum; - Task task; - String taskDescription; - String taskInfo; - - switch (commandType.toLowerCase()) { - case "bye": - ui.displayExit(); - break; - case "list": - displayTasks(); - break; - case "mark": - taskNum = getTaskNumFromMarkCommand(commandInfo); - markTask(taskNum); - break; - case "unmark": - taskNum = getTaskNumFromUnmarkCommand(commandInfo); - unmarkTask(taskNum); - break; - case "delete": - taskNum = getTaskNumFromDeleteCommand(commandInfo); - deleteTask(taskNum); - break; - case "todo": - taskDescription = getTaskDescriptionFromToDoCommand(commandInfo); - task = new ToDo(taskDescription); - addTask(task); - break; - case "deadline": - taskInfo = processTaskInfoFromDeadlineCommand(commandInfo); - String[] deadlineTaskDetails = taskInfo.split("/by", 2); - task = new Deadline(deadlineTaskDetails[0].trim(), deadlineTaskDetails[1].trim()); - addTask(task); - break; - case "event": - taskInfo = processTaskInfoFromEventCommand(commandInfo); - String[] eventTaskDetails = taskInfo.split("/from|/to", 3); - task = new Event(eventTaskDetails[0].trim(), eventTaskDetails[1].trim(), eventTaskDetails[2].trim()); - addTask(task); - break; - default: - throw new QuinnException("INVALID COMMAND. Please try again!"); - } - } - - private boolean isCommandInfoPresent(String commandInfo) { - return !commandInfo.trim().isEmpty(); - } - - private int getTaskNumFromMarkCommand(String commandInfo) throws QuinnException { - if (isCommandInfoPresent(commandInfo)) { - try { - return Integer.parseInt(commandInfo); - } catch (NumberFormatException e) { - throw new QuinnException("Please enter a valid task number to be marked as done!"); - } - } else { - throw new QuinnException("Please enter a task number to be marked as done!"); - } - } - - private int getTaskNumFromUnmarkCommand(String commandInfo) throws QuinnException { - if (isCommandInfoPresent(commandInfo)) { - try { - return Integer.parseInt(commandInfo); - } catch (NumberFormatException e) { - throw new QuinnException("Please enter a valid task number to be marked as not done yet!"); - } - } else { - throw new QuinnException("Please enter a task number to be marked as not done yet!"); - } - } - - private int getTaskNumFromDeleteCommand(String commandInfo) throws QuinnException { - if (isCommandInfoPresent(commandInfo)) { - try { - return Integer.parseInt(commandInfo); - } catch (NumberFormatException e) { - throw new QuinnException("Please enter a valid task number to be deleted!"); - } - } else { - throw new QuinnException("Please enter a task number to be deleted!"); - } - } - - private String getTaskDescriptionFromToDoCommand(String commandInfo) throws QuinnException { - if (isCommandInfoPresent(commandInfo)) { - return commandInfo; - } else { - throw new QuinnException("The description of a todo cannot be empty!"); - } - } - - private String processTaskInfoFromDeadlineCommand(String commandInfo) throws QuinnException { - if (!isCommandInfoPresent(commandInfo)) { - throw new QuinnException("INCOMPLETE COMMAND" - + System.lineSeparator() + "\t" - + "The description and date/time of a deadline cannot be empty!" - + System.lineSeparator() + "\t" - + "[Note: Enter /by before specifying the date/time]"); - } else { - String[] deadlineInfoParts = commandInfo.split("/by", 2); - - if (deadlineInfoParts.length != 2) { - throw new QuinnException("INVALID COMMAND" - + System.lineSeparator() + "\t" - + "Please check that the description and date/time of a deadline is present!" - + System.lineSeparator() + "\t" - + "[Note: Enter /by before specifying the date/time]"); - } - - String deadlineDescription = deadlineInfoParts[0].trim(); - String deadlineByDateTime = deadlineInfoParts[1].trim(); - - if (deadlineDescription.isEmpty()) { - throw new QuinnException("INCOMPLETE COMMAND" - + System.lineSeparator() + "\t" - + "The description of a deadline cannot be empty!"); - } - - if (deadlineByDateTime.isEmpty()) { - throw new QuinnException("INCOMPLETE COMMAND" - + System.lineSeparator() + "\t" - + "The date/time of a deadline cannot be empty!" - + System.lineSeparator() + "\t" - + "[Note: Enter /by before specifying the date/time]"); - } - - return commandInfo; - } - } - - private String processTaskInfoFromEventCommand(String commandInfo) throws QuinnException { - if (!isCommandInfoPresent(commandInfo)) { - throw new QuinnException("INCOMPLETE COMMAND" - + System.lineSeparator() + "\t" - + "The description and date/time of an event cannot be empty!" - + System.lineSeparator() + "\t" - + "[Note: Specify the date/time with '/from /to']"); - } else { - String[] eventInfoParts = commandInfo.split("/from|/to", 3); - - if (eventInfoParts.length != 3) { - throw new QuinnException("INVALID COMMAND" - + System.lineSeparator() + "\t" - + "Please check that the description and date/time of an event is present!" - + System.lineSeparator() + "\t" - + "[Note: Specify the date/time with '/from /to']"); - } - - String eventDescription = eventInfoParts[0].trim(); - String eventFromDateTime = eventInfoParts[1].trim(); - String eventToDateTime = eventInfoParts[2].trim(); - - if (eventDescription.isEmpty()) { - throw new QuinnException("INCOMPLETE COMMAND" - + System.lineSeparator() + "\t" - + "The description of an event cannot be empty!"); - } - - if (eventFromDateTime.isEmpty() || eventToDateTime.isEmpty()) { - throw new QuinnException("INCOMPLETE COMMAND" - + System.lineSeparator() + "\t" - + "The date/time of an event cannot be empty!" - + System.lineSeparator() + "\t" - + "[Note: Specify the date/time with '/from /to']"); - } - - return commandInfo; - } - } - - public void addTask(Task task) throws IOException { - tasks.add(task); - - String response = ui.taskAddedMessage(task) - + System.lineSeparator() - + ui.numOfTasksInListMessage(tasks); - ui.displayResponse(response); - - storage.saveTasksToFile(tasks); - } - - public void displayTasks() throws QuinnException { - if (!tasks.isEmpty()) { - String response = ui.tasksInListMessage(tasks); - ui.displayResponse(response); - } else { - throw new QuinnException("There are no tasks in your list!"); - } - } - - public void markTask(int taskNum) throws QuinnException, IOException { - if (taskNum > 0 && taskNum <= tasks.size()) { - Task task = tasks.get(taskNum - 1); - task.setDone(); - - String message = ui.taskDoneMessage(task); - ui.displayResponse(message); - - storage.saveTasksToFile(tasks); - } else { - throw new QuinnException("Task not found. Please try again!"); - } - } - - public void unmarkTask(int taskNum) throws QuinnException, IOException { - if (taskNum > 0 && taskNum <= tasks.size()) { - Task task = tasks.get(taskNum - 1); - task.setNotDone(); - - String message = ui.taskNotDoneMessage(task); - ui.displayResponse(message); - - storage.saveTasksToFile(tasks); - } else { - throw new QuinnException("Task not found. Please try again!"); - } - } - - public void deleteTask(int taskNum) throws QuinnException, IOException { - if (taskNum > 0 && taskNum <= tasks.size()) { - Task task = tasks.get(taskNum - 1); - tasks.remove(task); - - String message = ui.taskDeletedMessage(task) - + System.lineSeparator() - + ui.numOfTasksInListMessage(tasks); - ui.displayResponse(message); - - storage.saveTasksToFile(tasks); - } else { - throw new QuinnException("Task not found. Please try again!"); - } - } } diff --git a/src/main/java/quinn/command/AddCommand.java b/src/main/java/quinn/command/AddCommand.java new file mode 100644 index 000000000..821152f7b --- /dev/null +++ b/src/main/java/quinn/command/AddCommand.java @@ -0,0 +1,27 @@ +package quinn.command; + +import quinn.storage.Storage; +import quinn.task.TaskList; +import quinn.ui.Ui; + +import java.io.IOException; + +public abstract class AddCommand implements Command { + private final String taskDescription; + + public AddCommand(String taskDescription) { + this.taskDescription = taskDescription; + } + + public String getTaskDescription() { + return taskDescription; + } + + @Override + public boolean isExit() { + return false; + } + + @Override + public abstract void execute(TaskList taskList, Ui ui, Storage storage) throws IOException; +} diff --git a/src/main/java/quinn/command/AddDeadlineCommand.java b/src/main/java/quinn/command/AddDeadlineCommand.java new file mode 100644 index 000000000..53ce77500 --- /dev/null +++ b/src/main/java/quinn/command/AddDeadlineCommand.java @@ -0,0 +1,31 @@ +package quinn.command; + +import quinn.storage.Storage; +import quinn.task.Task; +import quinn.task.TaskList; +import quinn.ui.Ui; + +import java.io.IOException; + +public class AddDeadlineCommand extends AddCommand { + private final String taskDueDateTime; + + public AddDeadlineCommand(String taskInfo) { + // Task description + super(taskInfo.split("/by", 2)[0].trim()); + + // Task due datetime + taskDueDateTime = taskInfo.split("/by", 2)[1].trim(); + } + + @Override + public void execute(TaskList taskList, Ui ui, Storage storage) throws IOException { + Task newDeadlineTask = taskList.addDeadlineTask(super.getTaskDescription(), taskDueDateTime); + + String response = ui.taskAddedMessage(newDeadlineTask) + + System.lineSeparator() + ui.numOfTasksInListMessage(taskList); + ui.displayResponse(response); + + storage.saveTasksToFile(taskList); + } +} diff --git a/src/main/java/quinn/command/AddEventCommand.java b/src/main/java/quinn/command/AddEventCommand.java new file mode 100644 index 000000000..e47017c59 --- /dev/null +++ b/src/main/java/quinn/command/AddEventCommand.java @@ -0,0 +1,33 @@ +package quinn.command; + +import quinn.storage.Storage; +import quinn.task.Task; +import quinn.task.TaskList; +import quinn.ui.Ui; + +import java.io.IOException; + +public class AddEventCommand extends AddCommand { + private final String taskStartDateTime; + private final String taskEndDateTime; + + public AddEventCommand(String taskInfo) { + // Task description + super(taskInfo.split("/from|/to", 3)[0].trim()); + + // Task start and end datetime + taskStartDateTime = taskInfo.split("/from|/to", 3)[1].trim(); + taskEndDateTime = taskInfo.split("/from|/to", 3)[2].trim(); + } + + @Override + public void execute(TaskList taskList, Ui ui, Storage storage) throws IOException { + Task newEventTask = taskList.addEventTask(super.getTaskDescription(), taskStartDateTime, taskEndDateTime); + + String response = ui.taskAddedMessage(newEventTask) + + System.lineSeparator() + ui.numOfTasksInListMessage(taskList); + ui.displayResponse(response); + + storage.saveTasksToFile(taskList); + } +} diff --git a/src/main/java/quinn/command/AddToDoCommand.java b/src/main/java/quinn/command/AddToDoCommand.java new file mode 100644 index 000000000..00de042ac --- /dev/null +++ b/src/main/java/quinn/command/AddToDoCommand.java @@ -0,0 +1,25 @@ +package quinn.command; + +import quinn.storage.Storage; +import quinn.task.Task; +import quinn.task.TaskList; +import quinn.ui.Ui; + +import java.io.IOException; + +public class AddToDoCommand extends AddCommand { + public AddToDoCommand(String taskDescription) { + super(taskDescription); + } + + @Override + public void execute(TaskList taskList, Ui ui, Storage storage) throws IOException { + Task newToDoTask = taskList.addToDoTask(super.getTaskDescription()); + + String response = ui.taskAddedMessage(newToDoTask) + + System.lineSeparator() + ui.numOfTasksInListMessage(taskList); + ui.displayResponse(response); + + storage.saveTasksToFile(taskList); + } +} \ No newline at end of file diff --git a/src/main/java/quinn/command/Command.java b/src/main/java/quinn/command/Command.java new file mode 100644 index 000000000..89e58a360 --- /dev/null +++ b/src/main/java/quinn/command/Command.java @@ -0,0 +1,14 @@ +package quinn.command; + +import quinn.exception.QuinnException; +import quinn.storage.Storage; +import quinn.task.TaskList; +import quinn.ui.Ui; + +import java.io.IOException; + +public interface Command { + boolean isExit(); + + void execute(TaskList taskList, Ui ui, Storage storage) throws QuinnException, IOException; +} diff --git a/src/main/java/quinn/command/CommandType.java b/src/main/java/quinn/command/CommandType.java new file mode 100644 index 000000000..cf56be735 --- /dev/null +++ b/src/main/java/quinn/command/CommandType.java @@ -0,0 +1,22 @@ +package quinn.command; + +public enum CommandType { + BYE("bye"), + LIST("list"), + MARK("mark"), + UNMARK("unmark"), + DELETE("delete"), + TODO("todo"), + DEADLINE("deadline"), + EVENT("event"); + + private final String label; + + CommandType(String label) { + this.label = label; + } + + public String getLabel() { + return label; + } +} diff --git a/src/main/java/quinn/command/DeleteCommand.java b/src/main/java/quinn/command/DeleteCommand.java new file mode 100644 index 000000000..6b6de79b6 --- /dev/null +++ b/src/main/java/quinn/command/DeleteCommand.java @@ -0,0 +1,38 @@ +package quinn.command; + +import quinn.exception.QuinnException; +import quinn.storage.Storage; +import quinn.task.Task; +import quinn.task.TaskList; +import quinn.ui.Ui; + +import java.io.IOException; + +public class DeleteCommand implements Command { + private final int taskNum; + + public DeleteCommand(int taskNum) { + this.taskNum = taskNum; + } + + @Override + public boolean isExit() { + return false; + } + + @Override + public void execute(TaskList taskList, Ui ui, Storage storage) throws QuinnException, IOException { + if (taskNum > 0 && taskNum <= taskList.getNumOfTasks()) { + Task taskDeleted = taskList.deleteTask(taskNum); + + String response = ui.taskDeletedMessage(taskDeleted) + + System.lineSeparator() + + ui.numOfTasksInListMessage(taskList); + ui.displayResponse(response); + + storage.saveTasksToFile(taskList); + } else { + throw new QuinnException("Task not found. Please try again!"); + } + } +} diff --git a/src/main/java/quinn/command/ExitCommand.java b/src/main/java/quinn/command/ExitCommand.java new file mode 100644 index 000000000..2079da74d --- /dev/null +++ b/src/main/java/quinn/command/ExitCommand.java @@ -0,0 +1,21 @@ +package quinn.command; + +import quinn.storage.Storage; +import quinn.task.TaskList; +import quinn.ui.Ui; + +public class ExitCommand implements Command { + public ExitCommand() { + } + + @Override + public boolean isExit() { + return true; + } + + @Override + public void execute(TaskList taskList, Ui ui, Storage storage) { + ui.displayExit(); + } +} + diff --git a/src/main/java/quinn/command/ListCommand.java b/src/main/java/quinn/command/ListCommand.java new file mode 100644 index 000000000..3a70038cc --- /dev/null +++ b/src/main/java/quinn/command/ListCommand.java @@ -0,0 +1,26 @@ +package quinn.command; + +import quinn.exception.QuinnException; +import quinn.storage.Storage; +import quinn.task.TaskList; +import quinn.ui.Ui; + +public class ListCommand implements Command { + public ListCommand() { + } + + @Override + public boolean isExit() { + return false; + } + + @Override + public void execute(TaskList taskList, Ui ui, Storage storage) throws QuinnException { + if (taskList.getNumOfTasks() != 0) { + String response = ui.tasksInListMessage(taskList); + ui.displayResponse(response); + } else { + throw new QuinnException("There are no tasks in your list!"); + } + } +} diff --git a/src/main/java/quinn/command/MarkCommand.java b/src/main/java/quinn/command/MarkCommand.java new file mode 100644 index 000000000..3980870cc --- /dev/null +++ b/src/main/java/quinn/command/MarkCommand.java @@ -0,0 +1,36 @@ +package quinn.command; + +import quinn.exception.QuinnException; +import quinn.storage.Storage; +import quinn.task.Task; +import quinn.task.TaskList; +import quinn.ui.Ui; + +import java.io.IOException; + +public class MarkCommand implements Command { + private final int taskNum; + + public MarkCommand(int taskNum) { + this.taskNum = taskNum; + } + + @Override + public boolean isExit() { + return false; + } + + @Override + public void execute(TaskList taskList, Ui ui, Storage storage) throws QuinnException, IOException { + if (taskNum > 0 && taskNum <= taskList.getNumOfTasks()) { + Task taskDone = taskList.markDone(taskNum); + + String response = ui.taskDoneMessage(taskDone); + ui.displayResponse(response); + + storage.saveTasksToFile(taskList); + } else { + throw new QuinnException("Task not found. Please try again!"); + } + } +} diff --git a/src/main/java/quinn/command/UnmarkCommand.java b/src/main/java/quinn/command/UnmarkCommand.java new file mode 100644 index 000000000..a29e0e338 --- /dev/null +++ b/src/main/java/quinn/command/UnmarkCommand.java @@ -0,0 +1,36 @@ +package quinn.command; + +import quinn.exception.QuinnException; +import quinn.storage.Storage; +import quinn.task.Task; +import quinn.task.TaskList; +import quinn.ui.Ui; + +import java.io.IOException; + +public class UnmarkCommand implements Command { + private final int taskNum; + + public UnmarkCommand(int taskNum) { + this.taskNum = taskNum; + } + + @Override + public boolean isExit() { + return false; + } + + @Override + public void execute(TaskList taskList, Ui ui, Storage storage) throws QuinnException, IOException { + if (taskNum > 0 && taskNum <= taskList.getNumOfTasks()) { + Task taskNotDone = taskList.markNotDone(taskNum); + + String response = ui.taskNotDoneMessage(taskNotDone); + ui.displayResponse(response); + + storage.saveTasksToFile(taskList); + } else { + throw new QuinnException("Task not found. Please try again!"); + } + } +} diff --git a/src/main/java/quinn/parser/Parser.java b/src/main/java/quinn/parser/Parser.java new file mode 100644 index 000000000..14de052bb --- /dev/null +++ b/src/main/java/quinn/parser/Parser.java @@ -0,0 +1,224 @@ +package quinn.parser; + +import quinn.command.AddDeadlineCommand; +import quinn.command.AddEventCommand; +import quinn.command.AddToDoCommand; +import quinn.command.Command; +import quinn.command.CommandType; +import quinn.command.DeleteCommand; +import quinn.command.ExitCommand; +import quinn.command.ListCommand; +import quinn.command.MarkCommand; +import quinn.command.UnmarkCommand; +import quinn.exception.QuinnException; + +public class Parser { + public Command parse(String commandLine) throws QuinnException { + String[] commandLineParts = commandLine.split("\\s+", 2); + + CommandType commandType = validateCommand(commandLineParts[0].toLowerCase()); + + if (commandType == null) { + throw new QuinnException("INVALID COMMAND. Please try again!"); + } + + String commandInfo = getCommandInfo(commandLineParts, commandType); + + return initialiseCommand(commandType, commandInfo); + } + + private CommandType validateCommand(String commandType) { + for (CommandType c : CommandType.values()) { + if (c.getLabel().equals(commandType)) { + return c; + } + } + + return null; + } + + private String getCommandInfo(String[] commandLineParts, CommandType commandType) throws QuinnException { + String commandInfo; + + if (commandLineParts.length == 2) { + commandInfo = commandLineParts[1]; + + // If user inputs extra information for "bye" or "list" commands, + // then it is not a valid command + if ((commandType == CommandType.BYE) || (commandType == CommandType.LIST)) { + throw new QuinnException("INVALID COMMAND. Please try again!"); + } + } else { + // For "bye" and "list" commands + commandInfo = ""; + } + + return commandInfo; + } + + private Command initialiseCommand(CommandType commandType, String commandInfo) throws QuinnException { + Command command; + int taskNum; + String taskDescription; + String taskInfo; + + // Enhanced 'switch' + command = switch (commandType) { + case BYE -> new ExitCommand(); + case LIST -> new ListCommand(); + case MARK -> { + taskNum = getTaskNumFromMarkCommand(commandInfo); + yield new MarkCommand(taskNum); + } + case UNMARK -> { + taskNum = getTaskNumFromUnmarkCommand(commandInfo); + yield new UnmarkCommand(taskNum); + } + case DELETE -> { + taskNum = getTaskNumFromDeleteCommand(commandInfo); + yield new DeleteCommand(taskNum); + } + case TODO -> { + taskDescription = getTaskDescriptionFromToDoCommand(commandInfo); + yield new AddToDoCommand(taskDescription); + } + case DEADLINE -> { + taskInfo = processTaskInfoFromDeadlineCommand(commandInfo); + yield new AddDeadlineCommand(taskInfo); + } + case EVENT -> { + taskInfo = processTaskInfoFromEventCommand(commandInfo); + yield new AddEventCommand(taskInfo); + } + }; + + return command; + } + + private boolean isCommandInfoPresent(String commandInfo) { + return !commandInfo.trim().isEmpty(); + } + + private int getTaskNumFromMarkCommand(String commandInfo) throws QuinnException { + if (isCommandInfoPresent(commandInfo)) { + try { + return Integer.parseInt(commandInfo); + } catch (NumberFormatException e) { + throw new QuinnException("Please enter a valid task number to be marked as done!"); + } + } else { + throw new QuinnException("Please enter a task number to be marked as done!"); + } + } + + private int getTaskNumFromUnmarkCommand(String commandInfo) throws QuinnException { + if (isCommandInfoPresent(commandInfo)) { + try { + return Integer.parseInt(commandInfo); + } catch (NumberFormatException e) { + throw new QuinnException("Please enter a valid task number to be marked as not done yet!"); + } + } else { + throw new QuinnException("Please enter a task number to be marked as not done yet!"); + } + } + + private int getTaskNumFromDeleteCommand(String commandInfo) throws QuinnException { + if (isCommandInfoPresent(commandInfo)) { + try { + return Integer.parseInt(commandInfo); + } catch (NumberFormatException e) { + throw new QuinnException("Please enter a valid task number to be deleted!"); + } + } else { + throw new QuinnException("Please enter a task number to be deleted!"); + } + } + + private String getTaskDescriptionFromToDoCommand(String commandInfo) throws QuinnException { + if (isCommandInfoPresent(commandInfo)) { + return commandInfo; + } else { + throw new QuinnException("The description of a todo cannot be empty!"); + } + } + + private String processTaskInfoFromDeadlineCommand(String commandInfo) throws QuinnException { + if (!isCommandInfoPresent(commandInfo)) { + throw new QuinnException("INCOMPLETE COMMAND" + + System.lineSeparator() + "\t" + + "The description and date/time of a deadline cannot be empty!" + + System.lineSeparator() + "\t" + + "[Note: Enter /by before specifying the date/time]"); + } else { + String[] deadlineInfoParts = commandInfo.split("/by", 2); + + if (deadlineInfoParts.length != 2) { + throw new QuinnException("INVALID COMMAND" + + System.lineSeparator() + "\t" + + "Please check that the description and date/time of a deadline is present!" + + System.lineSeparator() + "\t" + + "[Note: Enter /by before specifying the date/time]"); + } + + String deadlineDescription = deadlineInfoParts[0].trim(); + String deadlineByDateTime = deadlineInfoParts[1].trim(); + + if (deadlineDescription.isEmpty()) { + throw new QuinnException("INCOMPLETE COMMAND" + + System.lineSeparator() + "\t" + + "The description of a deadline cannot be empty!"); + } + + if (deadlineByDateTime.isEmpty()) { + throw new QuinnException("INCOMPLETE COMMAND" + + System.lineSeparator() + "\t" + + "The date/time of a deadline cannot be empty!" + + System.lineSeparator() + "\t" + + "[Note: Enter /by before specifying the date/time]"); + } + + return commandInfo; + } + } + + private String processTaskInfoFromEventCommand(String commandInfo) throws QuinnException { + if (!isCommandInfoPresent(commandInfo)) { + throw new QuinnException("INCOMPLETE COMMAND" + + System.lineSeparator() + "\t" + + "The description and date/time of an event cannot be empty!" + + System.lineSeparator() + "\t" + + "[Note: Specify the date/time with '/from /to']"); + } else { + String[] eventInfoParts = commandInfo.split("/from|/to", 3); + + if (eventInfoParts.length != 3) { + throw new QuinnException("INVALID COMMAND" + + System.lineSeparator() + "\t" + + "Please check that the description and date/time of an event is present!" + + System.lineSeparator() + "\t" + + "[Note: Specify the date/time with '/from /to']"); + } + + String eventDescription = eventInfoParts[0].trim(); + String eventFromDateTime = eventInfoParts[1].trim(); + String eventToDateTime = eventInfoParts[2].trim(); + + if (eventDescription.isEmpty()) { + throw new QuinnException("INCOMPLETE COMMAND" + + System.lineSeparator() + "\t" + + "The description of an event cannot be empty!"); + } + + if (eventFromDateTime.isEmpty() || eventToDateTime.isEmpty()) { + throw new QuinnException("INCOMPLETE COMMAND" + + System.lineSeparator() + "\t" + + "The date/time of an event cannot be empty!" + + System.lineSeparator() + "\t" + + "[Note: Specify the date/time with '/from /to']"); + } + + return commandInfo; + } + } +} diff --git a/src/main/java/quinn/storage/Storage.java b/src/main/java/quinn/storage/Storage.java index c6a0f931d..fbf6d60bb 100644 --- a/src/main/java/quinn/storage/Storage.java +++ b/src/main/java/quinn/storage/Storage.java @@ -1,40 +1,28 @@ package quinn.storage; import quinn.exception.QuinnException; -import quinn.task.*; +import quinn.task.Deadline; +import quinn.task.Event; +import quinn.task.Task; +import quinn.task.TaskList; +import quinn.task.TaskType; +import quinn.task.ToDo; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; -import java.io.*; -import java.util.ArrayList; -import java.util.List; - -/** - * A class that handles create, read and write file operations. - */ public class Storage { private final File dataFile; - /** - * Constructor to initialize an instance of Storage class with folder - * name and file name. - * - * @param folderName Folder name of the quinn.storage file - * @param fileName Name of the quinn.storage file - * @throws QuinnException If the directory cannot be initialised - * @throws IOException If the quinn.storage file cannot be initialised - */ public Storage(String folderName, String fileName) throws QuinnException, IOException { File directory = initialiseDirectory(folderName); dataFile = initialiseFile(directory, fileName); } - /** - * Initializes the directory of the quinn.storage file. - * Creates the directory if it does not exist. - * - * @param folderName Folder name of the quinn.storage file - * @return The file that represents the relative path of the directory - * @throws QuinnException If the directory cannot be initialised - */ private File initialiseDirectory(String folderName) throws QuinnException { File directory = new File(folderName); boolean hasDirectory = directory.exists(); @@ -50,15 +38,6 @@ private File initialiseDirectory(String folderName) throws QuinnException { } } - /** - * Initializes the quinn.storage file. - * Creates the quinn.storage file if it does not exist. - * - * @param directory Relative path of the directory - * @param fileName Name of the quinn.storage file - * @return The quinn.storage file - * @throws IOException If the quinn.storage file cannot be initialised - */ private File initialiseFile(File directory, String fileName) throws IOException { File file = new File(directory + "/" + fileName); boolean hasFile = file.exists(); @@ -74,15 +53,8 @@ private File initialiseFile(File directory, String fileName) throws IOException } } - /** - * Loads all the tasks in the quinn.storage file to the task list. - * - * @return The list containing the tasks - * @throws IOException If the quinn.storage file or task cannot be read - * @throws QuinnException If an invalid type of task is found - */ - public List loadTasksFromFile() throws QuinnException, IOException { - List tasks = new ArrayList<>(); + public TaskList loadTasksFromFile() throws QuinnException, IOException { + TaskList taskList = new TaskList(); FileReader fileReader = new FileReader(dataFile); BufferedReader bufferedReader = new BufferedReader(fileReader); @@ -96,19 +68,19 @@ public List loadTasksFromFile() throws QuinnException, IOException { if (type.equals(TaskType.TODO.getAbbreviation())) { Task todoTask = new ToDo(description, isDone); - tasks.add(todoTask); + taskList.addTask(todoTask); } else if (type.equals(TaskType.DEADLINE.getAbbreviation())) { - String byDateTime = taskDetails[3].trim(); - Task deadlineTask = new Deadline(description, byDateTime, isDone); - tasks.add(deadlineTask); + String dueDateTime = taskDetails[3].trim(); + Task deadlineTask = new Deadline(description, dueDateTime, isDone); + taskList.addTask(deadlineTask); } else if (type.equals(TaskType.EVENT.getAbbreviation())) { - String fromDateTimeInput = taskDetails[3].trim(); - String toDateTimeInput = taskDetails[4].trim(); - Task eventTask = new Event(description, fromDateTimeInput, toDateTimeInput, isDone); - tasks.add(eventTask); + String startDateTime = taskDetails[3].trim(); + String endDateTime = taskDetails[4].trim(); + Task eventTask = new Event(description, startDateTime, endDateTime, isDone); + taskList.addTask(eventTask); } else { // Error detection for any invalid type of tasks found in the - // quinn.storage file. This should not happen since the user is only + // storage file. This should not happen since the user is only // allowed to create todo [T], deadline [D] and event [E] tasks. throw new QuinnException("INVALID TYPE OF TASK FOUND"); } @@ -116,21 +88,15 @@ public List loadTasksFromFile() throws QuinnException, IOException { bufferedReader.close(); - return tasks; + return taskList; } - /** - * Saves all the tasks in the task list to the quinn.storage file. - * - * @param tasks List containing the tasks to be saved - * @throws IOException If the tasks cannot be saved - */ - public void saveTasksToFile(List tasks) throws IOException { + public void saveTasksToFile(TaskList taskList) throws IOException { FileWriter fileWriter = new FileWriter(dataFile,false); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); - for (int i = 0; i < tasks.size(); i++) { - Task task = tasks.get(i); + for (int i = 0; i < taskList.getNumOfTasks(); i++) { + Task task = taskList.getTask(i); bufferedWriter.write(task.saveFormat() + System.lineSeparator()); } diff --git a/src/main/java/quinn/task/Deadline.java b/src/main/java/quinn/task/Deadline.java index bdddb7441..f344fb66f 100644 --- a/src/main/java/quinn/task/Deadline.java +++ b/src/main/java/quinn/task/Deadline.java @@ -1,23 +1,23 @@ package quinn.task; public class Deadline extends Task { - private final String byDateTimeInput; + private final String dueDateTime; - public Deadline(String description, String byDateTimeInput) { - this(description, byDateTimeInput, false); + public Deadline(String description, String dueDateTime) { + this(description, dueDateTime, false); } - public Deadline(String description, String byDateTimeInput, boolean isDone) { + public Deadline(String description, String dueDateTime, boolean isDone) { super(TaskType.DEADLINE, description, isDone); - this.byDateTimeInput = byDateTimeInput; + this.dueDateTime = dueDateTime; } @Override public String toString() { - return super.toString() + " (by: " + byDateTimeInput + ")"; + return super.toString() + " (by: " + dueDateTime + ")"; } public String saveFormat() { - return super.saveFormat() + " | " + byDateTimeInput; + return super.saveFormat() + " | " + dueDateTime; } } diff --git a/src/main/java/quinn/task/Event.java b/src/main/java/quinn/task/Event.java index 32bc7af4b..7870c1162 100644 --- a/src/main/java/quinn/task/Event.java +++ b/src/main/java/quinn/task/Event.java @@ -1,25 +1,25 @@ package quinn.task; public class Event extends Task { - private final String fromDateTimeInput; - private final String toDateTimeInput; + private final String startDateTime; + private final String endDateTime; - public Event(String description, String fromDateTimeInput, String toDateTimeInput) { - this(description, fromDateTimeInput, toDateTimeInput, false); + public Event(String description, String startDateTime, String endDateTime) { + this(description, startDateTime, endDateTime, false); } - public Event(String description, String fromDateTimeInput, String toDateTimeInput, boolean isDone) { + public Event(String description, String startDateTime, String endDateTime, boolean isDone) { super(TaskType.EVENT, description, isDone); - this.fromDateTimeInput = fromDateTimeInput; - this.toDateTimeInput = toDateTimeInput; + this.startDateTime = startDateTime; + this.endDateTime = endDateTime; } @Override public String toString() { - return super.toString() + " (from: " + fromDateTimeInput + " to: " + toDateTimeInput + ")"; + return super.toString() + " (from: " + startDateTime + " to: " + endDateTime + ")"; } public String saveFormat() { - return super.saveFormat() + " | " + fromDateTimeInput + " | " + toDateTimeInput; + return super.saveFormat() + " | " + startDateTime + " | " + endDateTime; } } diff --git a/src/main/java/quinn/task/TaskList.java b/src/main/java/quinn/task/TaskList.java new file mode 100644 index 000000000..121452fdb --- /dev/null +++ b/src/main/java/quinn/task/TaskList.java @@ -0,0 +1,77 @@ +package quinn.task; + +import java.util.ArrayList; +import java.util.List; + +public class TaskList { + private final List tasks; + + public TaskList() { + this.tasks = new ArrayList(); + } + + public int getNumOfTasks() { + return tasks.size(); + } + + public Task getTask(int index) { + return tasks.get(index); + } + + public Task addToDoTask(String description) { + Task toDoTask = new ToDo(description); + addTask(toDoTask); + return toDoTask; + } + + public Task addDeadlineTask(String description, String dueDateTime) { + Task deadlineTask = new Deadline(description, dueDateTime); + addTask(deadlineTask); + return deadlineTask; + } + + public Task addEventTask(String description, String startDateTime, String endDateTime) { + Task eventTask = new Event(description, startDateTime,endDateTime); + addTask(eventTask); + return eventTask; + } + + public void addTask(Task task) { + tasks.add(task); + } + + public Task markDone(int taskNum) { + Task task = getTask(taskNum - 1); + task.setDone(); + return task; + } + + public Task markNotDone(int taskNum) { + Task task = getTask(taskNum - 1); + task.setNotDone(); + return task; + } + + public Task deleteTask(int taskNum) { + Task task = getTask(taskNum - 1); + tasks.remove(task); + return task; + } + + @Override + public String toString() { + StringBuilder listBuilder = new StringBuilder(); + + for (int i = 0; i < getNumOfTasks(); i++) { + String listItem = (i + 1) + "." + "\t" + getTask(i); + + if (i != 0) { + listBuilder.append(System.lineSeparator()); + } + + listBuilder.append("\t").append(listItem); + } + + return listBuilder.toString(); + } +} diff --git a/src/main/java/quinn/ui/Ui.java b/src/main/java/quinn/ui/Ui.java index c2bae51f9..66bf94ddf 100644 --- a/src/main/java/quinn/ui/Ui.java +++ b/src/main/java/quinn/ui/Ui.java @@ -1,8 +1,8 @@ package quinn.ui; import quinn.task.Task; +import quinn.task.TaskList; -import java.util.List; import java.util.Scanner; public class Ui { @@ -77,30 +77,20 @@ public String taskDeletedMessage(Task task) { + System.lineSeparator() + "\t\t" + task; } - public String numOfTasksInListMessage(List tasks) { - return "\t" + "Now you have " + tasks.size() - + (tasks.size() > 1 ? " tasks" : " task") + public String numOfTasksInListMessage(TaskList taskList) { + return "\t" + "Now you have " + taskList.getNumOfTasks() + + (taskList.getNumOfTasks() > 1 ? " tasks" : " task") + " in the list."; } - public String tasksInListMessage(List tasks) { - StringBuilder sb = new StringBuilder(); - - sb.append("\t") - .append(tasks.size() > 1 ? "Here are the tasks in your list:" : "Here is the task in your list:") - .append(System.lineSeparator()) - .append("\t") - .append("[Legend: T = todo, D = deadline, E = event]") - .append(System.lineSeparator()); - - for (int i = 0; i < tasks.size(); i++) { - if (i != 0) { - sb.append(System.lineSeparator()); - } - - sb.append("\t").append(i + 1).append(". ").append(tasks.get(i)); - } - - return sb.toString(); + public String tasksInListMessage(TaskList taskList) { + return "\t" + "Here" + + (taskList.getNumOfTasks() > 1 ? " are the tasks " : " is the task ") + + "in your list:" + + System.lineSeparator() + + "\t" + "[Legend: T = todo, D = deadline, E = event]" + + System.lineSeparator() + + System.lineSeparator() + + taskList; } } From a9c924aa99e7936d04b09db559b21e2cf3889623 Mon Sep 17 00:00:00 2001 From: kaboomzxc Date: Thu, 26 Sep 2024 19:55:19 +0800 Subject: [PATCH 16/28] Implement Level-8 for chatbot to understand date time --- src/main/java/quinn/parser/Parser.java | 2 +- src/main/java/quinn/task/Deadline.java | 32 ++++++++++++++++++++-- src/main/java/quinn/task/Event.java | 38 ++++++++++++++++++++++++-- 3 files changed, 67 insertions(+), 5 deletions(-) diff --git a/src/main/java/quinn/parser/Parser.java b/src/main/java/quinn/parser/Parser.java index 14de052bb..e351977cf 100644 --- a/src/main/java/quinn/parser/Parser.java +++ b/src/main/java/quinn/parser/Parser.java @@ -62,7 +62,7 @@ private Command initialiseCommand(CommandType commandType, String commandInfo) t String taskDescription; String taskInfo; - // Enhanced 'switch' + // Enhanced 'switch' (https://dev.to/nikhilxd/exploring-enhanced-switch-in-java-44fh) command = switch (commandType) { case BYE -> new ExitCommand(); case LIST -> new ListCommand(); diff --git a/src/main/java/quinn/task/Deadline.java b/src/main/java/quinn/task/Deadline.java index f344fb66f..bf27270f2 100644 --- a/src/main/java/quinn/task/Deadline.java +++ b/src/main/java/quinn/task/Deadline.java @@ -1,7 +1,12 @@ package quinn.task; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + public class Deadline extends Task { private final String dueDateTime; + private final LocalDateTime parsedDueDateTime; public Deadline(String description, String dueDateTime) { this(description, dueDateTime, false); @@ -10,14 +15,37 @@ public Deadline(String description, String dueDateTime) { public Deadline(String description, String dueDateTime, boolean isDone) { super(TaskType.DEADLINE, description, isDone); this.dueDateTime = dueDateTime; + this.parsedDueDateTime = parseDateTime(dueDateTime); // parse dueDateTime into a LocalDateTime object + } + + private LocalDateTime parseDateTime(String inputDateTime) { + try { + DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm"); + return LocalDateTime.parse(inputDateTime, inputFormatter); + } catch (DateTimeParseException e) { + return null; // if inputDateTime is not in "yyyy-MM-dd HHmm" format + } + } + + private String formatDateTime(LocalDateTime parsedDateTime) { + DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("MMM d yyyy hh:mm a"); + return parsedDateTime.format(outputFormatter); } @Override public String toString() { - return super.toString() + " (by: " + dueDateTime + ")"; + if (parsedDueDateTime != null) { + return super.toString() + " (by: " + formatDateTime(parsedDueDateTime) + ")"; + } else { + return super.toString() + " (by: " + dueDateTime + ")"; + } } public String saveFormat() { - return super.saveFormat() + " | " + dueDateTime; + if (parsedDueDateTime != null) { + return super.saveFormat() + " | " + formatDateTime(parsedDueDateTime); + } else { + return super.saveFormat() + " | " + dueDateTime; + } } } diff --git a/src/main/java/quinn/task/Event.java b/src/main/java/quinn/task/Event.java index 7870c1162..4d8121a28 100644 --- a/src/main/java/quinn/task/Event.java +++ b/src/main/java/quinn/task/Event.java @@ -1,8 +1,14 @@ package quinn.task; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + public class Event extends Task { private final String startDateTime; private final String endDateTime; + private final LocalDateTime parsedStartDateTime; + private final LocalDateTime parsedEndDateTime; public Event(String description, String startDateTime, String endDateTime) { this(description, startDateTime, endDateTime, false); @@ -12,14 +18,42 @@ public Event(String description, String startDateTime, String endDateTime, boole super(TaskType.EVENT, description, isDone); this.startDateTime = startDateTime; this.endDateTime = endDateTime; + this.parsedStartDateTime = parseDateTime(startDateTime); // parse startDateTime into a LocalDateTime object + this.parsedEndDateTime = parseDateTime(endDateTime); // parse endDateTime into a LocalDateTime object + } + + private LocalDateTime parseDateTime(String inputDateTime) { + try { + DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm"); + return LocalDateTime.parse(inputDateTime, inputFormatter); + } catch (DateTimeParseException e) { + return null; // if inputDateTime is not in "yyyy-MM-dd HHmm" format + } + } + + private String formatDateTime(LocalDateTime parsedDateTime) { + DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("MMM d yyyy hh:mm a"); + return parsedDateTime.format(outputFormatter); } @Override public String toString() { - return super.toString() + " (from: " + startDateTime + " to: " + endDateTime + ")"; + if (parsedStartDateTime != null && parsedEndDateTime != null) { + return super.toString() + + " (from: " + formatDateTime(parsedStartDateTime) + + " to: " + formatDateTime(parsedEndDateTime) + ")"; + } else { + return super.toString() + " (from: " + startDateTime + " to: " + endDateTime + ")"; + } } public String saveFormat() { - return super.saveFormat() + " | " + startDateTime + " | " + endDateTime; + if (parsedStartDateTime != null && parsedEndDateTime != null) { + return super.saveFormat() + + " | " + formatDateTime(parsedStartDateTime) + + " | " + formatDateTime(parsedEndDateTime); + } else { + return super.saveFormat() + " | " + startDateTime + " | " + endDateTime; + } } } From b46f62128f08d50be8c7c7d889c8f4422c278e76 Mon Sep 17 00:00:00 2001 From: kaboomzxc Date: Thu, 26 Sep 2024 20:14:32 +0800 Subject: [PATCH 17/28] Implement Level-9 --- src/main/java/quinn/Quinn.java | 25 +++++- .../quinn/command/AddDeadlineCommand.java | 4 + .../java/quinn/command/AddEventCommand.java | 4 + .../java/quinn/command/AddToDoCommand.java | 4 + src/main/java/quinn/command/CommandType.java | 3 +- .../java/quinn/command/DeleteCommand.java | 34 ++++++-- src/main/java/quinn/command/ExitCommand.java | 4 + src/main/java/quinn/command/FindCommand.java | 40 +++++++++ src/main/java/quinn/command/ListCommand.java | 4 + src/main/java/quinn/command/MarkCommand.java | 24 ++++-- .../java/quinn/command/UnmarkCommand.java | 24 ++++-- src/main/java/quinn/parser/Parser.java | 16 +++- src/main/java/quinn/task/Task.java | 4 + src/main/java/quinn/task/TaskList.java | 83 +++++++++++++++++-- src/main/java/quinn/ui/Ui.java | 19 +++++ 15 files changed, 267 insertions(+), 25 deletions(-) create mode 100644 src/main/java/quinn/command/FindCommand.java diff --git a/src/main/java/quinn/Quinn.java b/src/main/java/quinn/Quinn.java index d19b70650..f3acfd30f 100644 --- a/src/main/java/quinn/Quinn.java +++ b/src/main/java/quinn/Quinn.java @@ -1,6 +1,8 @@ package quinn; import quinn.command.Command; +import quinn.command.CommandType; +import quinn.command.FindCommand; import quinn.exception.QuinnException; import quinn.parser.Parser; import quinn.task.TaskList; @@ -19,6 +21,8 @@ public Quinn(String folderName, String fileName) { ui = new Ui(); parser = new Parser(); + Command command = null; + try { storage = new Storage(folderName, fileName); taskList = storage.loadTasksFromFile(); @@ -28,6 +32,22 @@ public Quinn(String folderName, String fileName) { } } + public void checkAndDisplayFilteredTasks(Command command) { + if (taskList.hasFilter()) { + String filteredTasksMessage; + + if (taskList.getFilterCommandType() == CommandType.FIND && !(command instanceof FindCommand)) { + filteredTasksMessage = ui.tasksWithKeywordMessage(taskList, taskList.getFilterInfo()); + } else { + filteredTasksMessage = ""; + } + + if (!filteredTasksMessage.isEmpty()) { + ui.displayFilteredTasks(filteredTasksMessage); + } + } + } + public static void main(String[] args) { new Quinn("data", "tasks.txt").run(); } @@ -36,15 +56,18 @@ public void run() { ui.displayWelcome(); boolean isExit = false; + Command command = null; + while (!isExit) { try { String commandLine = ui.readCommand(); - Command command = parser.parse(commandLine); + command = parser.parse(commandLine); command.execute(taskList, ui, storage); isExit = command.isExit(); } catch (QuinnException | IOException e) { ui.displayError(e.getMessage()); } finally { + checkAndDisplayFilteredTasks(command); ui.displayLine(); } } diff --git a/src/main/java/quinn/command/AddDeadlineCommand.java b/src/main/java/quinn/command/AddDeadlineCommand.java index 53ce77500..9daf9b3e7 100644 --- a/src/main/java/quinn/command/AddDeadlineCommand.java +++ b/src/main/java/quinn/command/AddDeadlineCommand.java @@ -22,6 +22,10 @@ public AddDeadlineCommand(String taskInfo) { public void execute(TaskList taskList, Ui ui, Storage storage) throws IOException { Task newDeadlineTask = taskList.addDeadlineTask(super.getTaskDescription(), taskDueDateTime); + // Reset the List of filteredTasks when AddCommand is executed + // This will clear the List of filteredTasks + taskList.resetFilteredTasks(); + String response = ui.taskAddedMessage(newDeadlineTask) + System.lineSeparator() + ui.numOfTasksInListMessage(taskList); ui.displayResponse(response); diff --git a/src/main/java/quinn/command/AddEventCommand.java b/src/main/java/quinn/command/AddEventCommand.java index e47017c59..170e1880e 100644 --- a/src/main/java/quinn/command/AddEventCommand.java +++ b/src/main/java/quinn/command/AddEventCommand.java @@ -24,6 +24,10 @@ public AddEventCommand(String taskInfo) { public void execute(TaskList taskList, Ui ui, Storage storage) throws IOException { Task newEventTask = taskList.addEventTask(super.getTaskDescription(), taskStartDateTime, taskEndDateTime); + // Reset the List of filteredTasks when AddCommand is executed + // This will clear the List of filteredTasks + taskList.resetFilteredTasks(); + String response = ui.taskAddedMessage(newEventTask) + System.lineSeparator() + ui.numOfTasksInListMessage(taskList); ui.displayResponse(response); diff --git a/src/main/java/quinn/command/AddToDoCommand.java b/src/main/java/quinn/command/AddToDoCommand.java index 00de042ac..ff03999b7 100644 --- a/src/main/java/quinn/command/AddToDoCommand.java +++ b/src/main/java/quinn/command/AddToDoCommand.java @@ -16,6 +16,10 @@ public AddToDoCommand(String taskDescription) { public void execute(TaskList taskList, Ui ui, Storage storage) throws IOException { Task newToDoTask = taskList.addToDoTask(super.getTaskDescription()); + // Reset the List of filteredTasks when AddCommand is executed + // This will clear the List of filteredTasks + taskList.resetFilteredTasks(); + String response = ui.taskAddedMessage(newToDoTask) + System.lineSeparator() + ui.numOfTasksInListMessage(taskList); ui.displayResponse(response); diff --git a/src/main/java/quinn/command/CommandType.java b/src/main/java/quinn/command/CommandType.java index cf56be735..476031665 100644 --- a/src/main/java/quinn/command/CommandType.java +++ b/src/main/java/quinn/command/CommandType.java @@ -8,7 +8,8 @@ public enum CommandType { DELETE("delete"), TODO("todo"), DEADLINE("deadline"), - EVENT("event"); + EVENT("event"), + FIND("find"); private final String label; diff --git a/src/main/java/quinn/command/DeleteCommand.java b/src/main/java/quinn/command/DeleteCommand.java index 6b6de79b6..64ed9f7de 100644 --- a/src/main/java/quinn/command/DeleteCommand.java +++ b/src/main/java/quinn/command/DeleteCommand.java @@ -22,15 +22,35 @@ public boolean isExit() { @Override public void execute(TaskList taskList, Ui ui, Storage storage) throws QuinnException, IOException { - if (taskNum > 0 && taskNum <= taskList.getNumOfTasks()) { - Task taskDeleted = taskList.deleteTask(taskNum); + Task taskDeleted = !taskList.hasFilter() + ? deleteTaskBasedOnAllTasks(taskList) + : deleteTaskBasedOnFilteredTasks(taskList); + + if (taskList.getNumOfFilteredTasks() == 0) { + // Reset the List of filteredTasks when the List is empty + // This will clear the List of filteredTasks + taskList.resetFilteredTasks(); + } + + String response = ui.taskDeletedMessage(taskDeleted) + + System.lineSeparator() + + ui.numOfTasksInListMessage(taskList); + ui.displayResponse(response); + + storage.saveTasksToFile(taskList); + } - String response = ui.taskDeletedMessage(taskDeleted) - + System.lineSeparator() - + ui.numOfTasksInListMessage(taskList); - ui.displayResponse(response); + public Task deleteTaskBasedOnAllTasks(TaskList taskList) throws QuinnException { + if (taskNum > 0 && taskNum <= taskList.getNumOfTasks()) { + return taskList.deleteTask(taskNum); + } else { + throw new QuinnException("Task not found. Please try again!"); + } + } - storage.saveTasksToFile(taskList); + public Task deleteTaskBasedOnFilteredTasks(TaskList taskList) throws QuinnException { + if (taskNum > 0 && taskNum <= taskList.getNumOfFilteredTasks()) { + return taskList.deleteTask(taskNum); } else { throw new QuinnException("Task not found. Please try again!"); } diff --git a/src/main/java/quinn/command/ExitCommand.java b/src/main/java/quinn/command/ExitCommand.java index 2079da74d..12ae58d19 100644 --- a/src/main/java/quinn/command/ExitCommand.java +++ b/src/main/java/quinn/command/ExitCommand.java @@ -15,6 +15,10 @@ public boolean isExit() { @Override public void execute(TaskList taskList, Ui ui, Storage storage) { + // Reset the List of filteredTasks when ExitCommand is executed + // This will clear the List of filteredTasks + taskList.resetFilteredTasks(); + ui.displayExit(); } } diff --git a/src/main/java/quinn/command/FindCommand.java b/src/main/java/quinn/command/FindCommand.java new file mode 100644 index 000000000..e68b0b539 --- /dev/null +++ b/src/main/java/quinn/command/FindCommand.java @@ -0,0 +1,40 @@ +package quinn.command; + +import quinn.exception.QuinnException; +import quinn.storage.Storage; +import quinn.task.TaskList; +import quinn.ui.Ui; + +public class FindCommand implements Command { + private final String keyword; + + public FindCommand(String keyword) { + this.keyword = keyword; + } + + @Override + public boolean isExit() { + return false; + } + + @Override + public void execute(TaskList taskList, Ui ui, Storage storage) throws QuinnException { + if (taskList.getNumOfTasks() != 0) { + taskList.setFilteredTasksByKeyword(keyword); + + if (taskList.getNumOfFilteredTasks() != 0) { + String response = ui.tasksWithKeywordMessage(taskList, keyword); + ui.displayResponse(response); + } else { + // Reset the List of filteredTasks when FindCommand is executed + // and there are no matching tasks + // This will clear the List of filteredTasks + taskList.resetFilteredTasks(); + + throw new QuinnException("There are no matching tasks!"); + } + } else { + throw new QuinnException("There are no tasks in your list!"); + } + } +} diff --git a/src/main/java/quinn/command/ListCommand.java b/src/main/java/quinn/command/ListCommand.java index 3a70038cc..6b1c75cec 100644 --- a/src/main/java/quinn/command/ListCommand.java +++ b/src/main/java/quinn/command/ListCommand.java @@ -17,6 +17,10 @@ public boolean isExit() { @Override public void execute(TaskList taskList, Ui ui, Storage storage) throws QuinnException { if (taskList.getNumOfTasks() != 0) { + // Reset the List of filteredTasks when ListCommand is executed + // This will clear the List of filteredTasks + taskList.resetFilteredTasks(); + String response = ui.tasksInListMessage(taskList); ui.displayResponse(response); } else { diff --git a/src/main/java/quinn/command/MarkCommand.java b/src/main/java/quinn/command/MarkCommand.java index 3980870cc..4996ea9c7 100644 --- a/src/main/java/quinn/command/MarkCommand.java +++ b/src/main/java/quinn/command/MarkCommand.java @@ -22,13 +22,27 @@ public boolean isExit() { @Override public void execute(TaskList taskList, Ui ui, Storage storage) throws QuinnException, IOException { - if (taskNum > 0 && taskNum <= taskList.getNumOfTasks()) { - Task taskDone = taskList.markDone(taskNum); + Task taskDone = !taskList.hasFilter() + ? markTaskDoneBasedOnAllTasks(taskList) + : markTaskDoneBasedOnFilteredTasks(taskList); + + String response = ui.taskDoneMessage(taskDone); + ui.displayResponse(response); - String response = ui.taskDoneMessage(taskDone); - ui.displayResponse(response); + storage.saveTasksToFile(taskList); + } + + public Task markTaskDoneBasedOnAllTasks(TaskList taskList) throws QuinnException { + if (taskNum > 0 && taskNum <= taskList.getNumOfTasks()) { + return taskList.markDone(taskNum); + } else { + throw new QuinnException("Task not found. Please try again!"); + } + } - storage.saveTasksToFile(taskList); + public Task markTaskDoneBasedOnFilteredTasks(TaskList taskList) throws QuinnException { + if (taskNum > 0 && taskNum <= taskList.getNumOfFilteredTasks()) { + return taskList.markDone(taskNum); } else { throw new QuinnException("Task not found. Please try again!"); } diff --git a/src/main/java/quinn/command/UnmarkCommand.java b/src/main/java/quinn/command/UnmarkCommand.java index a29e0e338..d33af47e2 100644 --- a/src/main/java/quinn/command/UnmarkCommand.java +++ b/src/main/java/quinn/command/UnmarkCommand.java @@ -22,13 +22,27 @@ public boolean isExit() { @Override public void execute(TaskList taskList, Ui ui, Storage storage) throws QuinnException, IOException { - if (taskNum > 0 && taskNum <= taskList.getNumOfTasks()) { - Task taskNotDone = taskList.markNotDone(taskNum); + Task taskNotDone = !taskList.hasFilter() + ? markTaskNotDoneBasedOnAllTasks(taskList) + : markTaskNotDoneBasedOnFilteredTasks(taskList); + + String response = ui.taskNotDoneMessage(taskNotDone); + ui.displayResponse(response); - String response = ui.taskNotDoneMessage(taskNotDone); - ui.displayResponse(response); + storage.saveTasksToFile(taskList); + } + + public Task markTaskNotDoneBasedOnAllTasks(TaskList taskList) throws QuinnException { + if (taskNum > 0 && taskNum <= taskList.getNumOfTasks()) { + return taskList.markNotDone(taskNum); + } else { + throw new QuinnException("Task not found. Please try again!"); + } + } - storage.saveTasksToFile(taskList); + public Task markTaskNotDoneBasedOnFilteredTasks(TaskList taskList) throws QuinnException { + if (taskNum > 0 && taskNum <= taskList.getNumOfFilteredTasks()) { + return taskList.markNotDone(taskNum); } else { throw new QuinnException("Task not found. Please try again!"); } diff --git a/src/main/java/quinn/parser/Parser.java b/src/main/java/quinn/parser/Parser.java index 14de052bb..9dacf0d0b 100644 --- a/src/main/java/quinn/parser/Parser.java +++ b/src/main/java/quinn/parser/Parser.java @@ -7,6 +7,7 @@ import quinn.command.CommandType; import quinn.command.DeleteCommand; import quinn.command.ExitCommand; +import quinn.command.FindCommand; import quinn.command.ListCommand; import quinn.command.MarkCommand; import quinn.command.UnmarkCommand; @@ -61,8 +62,9 @@ private Command initialiseCommand(CommandType commandType, String commandInfo) t int taskNum; String taskDescription; String taskInfo; + String keyword; - // Enhanced 'switch' + // Enhanced 'switch' (https://dev.to/nikhilxd/exploring-enhanced-switch-in-java-44fh) command = switch (commandType) { case BYE -> new ExitCommand(); case LIST -> new ListCommand(); @@ -90,6 +92,10 @@ private Command initialiseCommand(CommandType commandType, String commandInfo) t taskInfo = processTaskInfoFromEventCommand(commandInfo); yield new AddEventCommand(taskInfo); } + case FIND -> { + keyword = getKeywordFromFindCommand(commandInfo); + yield new FindCommand(keyword); + } }; return command; @@ -221,4 +227,12 @@ private String processTaskInfoFromEventCommand(String commandInfo) throws QuinnE return commandInfo; } } + + private String getKeywordFromFindCommand(String commandInfo) throws QuinnException { + if (isCommandInfoPresent(commandInfo)) { + return commandInfo; + } else { + throw new QuinnException("Please enter the keyword to search for matching tasks!"); + } + } } diff --git a/src/main/java/quinn/task/Task.java b/src/main/java/quinn/task/Task.java index 4cb35caf0..b558c1ae1 100644 --- a/src/main/java/quinn/task/Task.java +++ b/src/main/java/quinn/task/Task.java @@ -32,6 +32,10 @@ public void setNotDone() { this.isDone = false; } + public boolean hasKeyword(String keyword) { + return description.toLowerCase().contains(keyword.toLowerCase()); + } + @Override public String toString() { return "[" + type.getAbbreviation() + "] " + getStatusIcon() + " " + description; diff --git a/src/main/java/quinn/task/TaskList.java b/src/main/java/quinn/task/TaskList.java index 121452fdb..dd782a042 100644 --- a/src/main/java/quinn/task/TaskList.java +++ b/src/main/java/quinn/task/TaskList.java @@ -1,23 +1,71 @@ package quinn.task; +import quinn.command.CommandType; + import java.util.ArrayList; import java.util.List; public class TaskList { private final List tasks; + private List filteredTasks; + private CommandType filterCommandType; + private String filterInfo; public TaskList() { this.tasks = new ArrayList(); + filteredTasks = new ArrayList<>(); + filterCommandType = null; + filterInfo = null; } public int getNumOfTasks() { return tasks.size(); } + public int getNumOfFilteredTasks() { + return filteredTasks.size(); + } + public Task getTask(int index) { return tasks.get(index); } + public Task getFilteredTask(int index) { + return filteredTasks.get(index); + } + + public boolean hasFilter() { + return !filteredTasks.isEmpty(); + } + + public CommandType getFilterCommandType() { + return filterCommandType; + } + + public String getFilterInfo() { + return filterInfo; + } + + public void resetFilteredTasks() { + filteredTasks = new ArrayList<>(); + filterCommandType = null; + filterInfo = null; + } + + public void setFilteredTasksByKeyword(String keyword) { + filteredTasks = new ArrayList<>(); + + // Iterate through each task and filter those that contain the keyword + for (Task task : tasks) { + if (task.hasKeyword(keyword)) { + filteredTasks.add(task); + } + } + + filterCommandType = CommandType.FIND; + filterInfo = keyword; + } + public Task addToDoTask(String description) { Task toDoTask = new ToDo(description); addTask(toDoTask); @@ -41,25 +89,29 @@ public void addTask(Task task) { } public Task markDone(int taskNum) { - Task task = getTask(taskNum - 1); + Task task = !hasFilter() ? getTask(taskNum - 1) : getFilteredTask(taskNum - 1); task.setDone(); return task; } public Task markNotDone(int taskNum) { - Task task = getTask(taskNum - 1); + Task task = !hasFilter() ? getTask(taskNum - 1) : getFilteredTask(taskNum - 1); task.setNotDone(); return task; } public Task deleteTask(int taskNum) { - Task task = getTask(taskNum - 1); + Task task = !hasFilter() ? getTask(taskNum - 1) : getFilteredTask(taskNum - 1); tasks.remove(task); + + if (hasFilter()) { + filteredTasks.remove(task); + } + return task; } - @Override - public String toString() { + public String listOfTasksString() { StringBuilder listBuilder = new StringBuilder(); for (int i = 0; i < getNumOfTasks(); i++) { @@ -74,4 +126,25 @@ public String toString() { return listBuilder.toString(); } + + public String listOfFilteredTasksString() { + StringBuilder listBuilder = new StringBuilder(); + + for (int i = 0; i < getNumOfFilteredTasks(); i++) { + String listItem = (i + 1) + "." + "\t" + getFilteredTask(i); + + if (i != 0) { + listBuilder.append(System.lineSeparator()); + } + + listBuilder.append("\t").append(listItem); + } + + return listBuilder.toString(); + } + + @Override + public String toString() { + return !hasFilter() ? listOfTasksString() : listOfFilteredTasksString(); + } } diff --git a/src/main/java/quinn/ui/Ui.java b/src/main/java/quinn/ui/Ui.java index 66bf94ddf..311b290b5 100644 --- a/src/main/java/quinn/ui/Ui.java +++ b/src/main/java/quinn/ui/Ui.java @@ -52,6 +52,12 @@ public void displayError(String message) { System.out.println("\t" + "('-')? " + message); } + public void displayFilteredTasks(String message) { + displayLine(); + System.out.println("[FILTERED TASKS]" + System.lineSeparator()); + System.out.println(message); + } + public void displayLine() { String horizontalLine = "____________________________________________________________"; System.out.println(horizontalLine); @@ -93,4 +99,17 @@ public String tasksInListMessage(TaskList taskList) { + System.lineSeparator() + taskList; } + + public String tasksWithKeywordMessage(TaskList taskList, String keyword) { + return "\t" + "Here" + + (taskList.getNumOfFilteredTasks() > 1 ? " are the matching tasks " : " is the matching task ") + + "in your list:" + + System.lineSeparator() + + "\t" + "[Keyword Search: " + keyword + "]" + + System.lineSeparator() + + "\t" + "[Legend: T = todo, D = deadline, E = event]" + + System.lineSeparator() + + System.lineSeparator() + + taskList; + } } From 02bc63addb83d3356a4c96804b227bcaf5f5ae4d Mon Sep 17 00:00:00 2001 From: kaboomzxc Date: Fri, 27 Sep 2024 01:45:08 +0800 Subject: [PATCH 18/28] Added JavaDoc comments --- src/main/java/quinn/Quinn.java | 52 +++++++ src/main/java/quinn/command/AddCommand.java | 34 +++++ .../quinn/command/AddDeadlineCommand.java | 22 +++ .../java/quinn/command/AddEventCommand.java | 24 ++++ .../java/quinn/command/AddToDoCommand.java | 20 +++ src/main/java/quinn/command/Command.java | 18 +++ src/main/java/quinn/command/CommandType.java | 9 ++ .../java/quinn/command/DeleteCommand.java | 22 +++ src/main/java/quinn/command/ExitCommand.java | 6 + src/main/java/quinn/command/FindCommand.java | 8 ++ src/main/java/quinn/command/ListCommand.java | 6 + src/main/java/quinn/command/MarkCommand.java | 22 +++ .../java/quinn/command/UnmarkCommand.java | 22 +++ .../java/quinn/exception/QuinnException.java | 25 ++++ src/main/java/quinn/parser/Parser.java | 94 +++++++++++++ src/main/java/quinn/storage/Storage.java | 34 +++++ src/main/java/quinn/task/Deadline.java | 42 ++++++ src/main/java/quinn/task/Event.java | 50 +++++++ src/main/java/quinn/task/Task.java | 43 ++++++ src/main/java/quinn/task/TaskList.java | 130 ++++++++++++++++++ src/main/java/quinn/task/TaskType.java | 28 ++++ src/main/java/quinn/task/ToDo.java | 20 +++ src/main/java/quinn/ui/Ui.java | 92 ++++++++++++- 23 files changed, 821 insertions(+), 2 deletions(-) diff --git a/src/main/java/quinn/Quinn.java b/src/main/java/quinn/Quinn.java index f3acfd30f..08e6a7294 100644 --- a/src/main/java/quinn/Quinn.java +++ b/src/main/java/quinn/Quinn.java @@ -11,12 +11,38 @@ import java.io.IOException; +/** + * The Quinn class represents the main controller for the Quinn task management application. + * It initializes the application components, manages the command execution loop, and + * coordinates interactions between the user interface, task list, storage, and parser. + * + * This class is responsible for: + * Initializing the UI, parser, storage, and task list + * Running the main command execution loop + * Handling exceptions during command execution + * Managing the display of filtered tasks + */ public class Quinn { + + /** The user interface component for handling input/output. */ private final Ui ui; + + /** The parser for interpreting user commands. */ private final Parser parser; + + /** The storage component for persisting task data. */ private Storage storage; + + /** The list of tasks managed by the application. */ private TaskList taskList; + /** + * Constructs a new Quinn application instance. + * Initializes the UI, parser, storage, and task list components. + * + * @param folderName the name of the folder to store task data + * @param fileName the name of the file to store task data + */ public Quinn(String folderName, String fileName) { ui = new Ui(); parser = new Parser(); @@ -32,6 +58,14 @@ public Quinn(String folderName, String fileName) { } } + + /** + * Checks if there are filtered tasks and displays them if necessary. + * This method is called after each command execution to maintain + * the display of filtered tasks when appropriate. + * + * @param command the last executed command + */ public void checkAndDisplayFilteredTasks(Command command) { if (taskList.hasFilter()) { String filteredTasksMessage; @@ -48,10 +82,28 @@ public void checkAndDisplayFilteredTasks(Command command) { } } + /** + * The main entry point of the Quinn application. + * Creates a new Quinn instance and starts its execution. + * + * @param args command-line arguments (not used) + */ public static void main(String[] args) { new Quinn("data", "tasks.txt").run(); } + /** + * Runs the main execution loop of the Quinn application. + * This method continuously reads user input, executes commands, + * and displays results until an exit command is received. + * + * The execution loop performs the following steps: + * Read a command from the user + * Parse the command + * Execute the command + * Check and display filtered tasks if necessary + * Handle any exceptions that occur during execution + */ public void run() { ui.displayWelcome(); boolean isExit = false; diff --git a/src/main/java/quinn/command/AddCommand.java b/src/main/java/quinn/command/AddCommand.java index 821152f7b..d66b77095 100644 --- a/src/main/java/quinn/command/AddCommand.java +++ b/src/main/java/quinn/command/AddCommand.java @@ -6,22 +6,56 @@ import java.io.IOException; +/** + * Represents an abstract base class for all add commands in the task management system. + * This class implements the Command interface and provides common functionality + * for adding tasks to the task list. + * + * Subclasses must implement the {@link #execute(TaskList, Ui, Storage)} method + * to define the specific behavior for adding different types of tasks. + * + */ public abstract class AddCommand implements Command { + /** The description of the task to be added. */ private final String taskDescription; + /** + * Constructs an AddCommand with the specified task description. + * + * @param taskDescription the description of the task to be added + */ public AddCommand(String taskDescription) { this.taskDescription = taskDescription; } + /** + * Returns the description of the task to be added. + * + * @return the task description + */ public String getTaskDescription() { return taskDescription; } + /** + * Indicates whether this command should cause the program to exit. + * + * @return false, as add commands do not cause the program to exit + */ @Override public boolean isExit() { return false; } + /** + * Executes the add command. This method must be implemented by subclasses + * to define the specific behavior for adding different types of tasks. + * + * @param taskList the task list to which the task will be added + * @param ui the user interface for displaying messages + * @param storage the storage for saving tasks + * @throws IOException if there's an error saving the updated task list + */ @Override public abstract void execute(TaskList taskList, Ui ui, Storage storage) throws IOException; } diff --git a/src/main/java/quinn/command/AddDeadlineCommand.java b/src/main/java/quinn/command/AddDeadlineCommand.java index 9daf9b3e7..2332530b7 100644 --- a/src/main/java/quinn/command/AddDeadlineCommand.java +++ b/src/main/java/quinn/command/AddDeadlineCommand.java @@ -7,9 +7,22 @@ import java.io.IOException; +/** + * Represents a command to add a deadline task to the task list. + * This class extends the AddCommand abstract class and implements + * the specific behavior for adding a deadline task. + * + */ public class AddDeadlineCommand extends AddCommand { + /** The due date and time of the deadline task. */ private final String taskDueDateTime; + /** + * Constructs an AddDeadlineCommand with the specified task information. + * + * @param taskInfo a string containing the task description and due date/time, + * separated by "/by" + */ public AddDeadlineCommand(String taskInfo) { // Task description super(taskInfo.split("/by", 2)[0].trim()); @@ -18,6 +31,15 @@ public AddDeadlineCommand(String taskInfo) { taskDueDateTime = taskInfo.split("/by", 2)[1].trim(); } + /** + * Executes the add deadline command. This method adds a new deadline task + * to the task list, updates the UI, and saves the changes to storage. + * + * @param taskList the task list to which the deadline task will be added + * @param ui the user interface for displaying messages + * @param storage the storage for saving tasks + * @throws IOException if there's an error saving the updated task list + */ @Override public void execute(TaskList taskList, Ui ui, Storage storage) throws IOException { Task newDeadlineTask = taskList.addDeadlineTask(super.getTaskDescription(), taskDueDateTime); diff --git a/src/main/java/quinn/command/AddEventCommand.java b/src/main/java/quinn/command/AddEventCommand.java index 170e1880e..71661b04d 100644 --- a/src/main/java/quinn/command/AddEventCommand.java +++ b/src/main/java/quinn/command/AddEventCommand.java @@ -7,10 +7,25 @@ import java.io.IOException; +/** + * Represents a command to add an event task to the task list. + * This class extends the AddCommand abstract class and implements + * the specific behavior for adding an event task. + * + */ public class AddEventCommand extends AddCommand { + /** The start date and time of the event task. */ private final String taskStartDateTime; + + /** The end date and time of the event task. */ private final String taskEndDateTime; + /** + * Constructs an AddEventCommand with the specified task information. + * + * @param taskInfo a string containing the task description, start date/time, + * and end date/time, separated by "/from" and "/to" + */ public AddEventCommand(String taskInfo) { // Task description super(taskInfo.split("/from|/to", 3)[0].trim()); @@ -20,6 +35,15 @@ public AddEventCommand(String taskInfo) { taskEndDateTime = taskInfo.split("/from|/to", 3)[2].trim(); } + /** + * Executes the add event command. This method adds a new event task + * to the task list, updates the UI, and saves the changes to storage. + * + * @param taskList the task list to which the event task will be added + * @param ui the user interface for displaying messages + * @param storage the storage for saving tasks + * @throws IOException if there's an error saving the updated task list + */ @Override public void execute(TaskList taskList, Ui ui, Storage storage) throws IOException { Task newEventTask = taskList.addEventTask(super.getTaskDescription(), taskStartDateTime, taskEndDateTime); diff --git a/src/main/java/quinn/command/AddToDoCommand.java b/src/main/java/quinn/command/AddToDoCommand.java index ff03999b7..ea298c1a1 100644 --- a/src/main/java/quinn/command/AddToDoCommand.java +++ b/src/main/java/quinn/command/AddToDoCommand.java @@ -7,11 +7,31 @@ import java.io.IOException; +/** + * Represents a command to add a to-do task to the task list. + * This class extends the AddCommand abstract class and implements + * the specific behavior for adding a to-do task. + * + */ public class AddToDoCommand extends AddCommand { + /** + * Constructs an AddToDoCommand with the specified task description. + * + * @param taskDescription the description of the to-do task + */ public AddToDoCommand(String taskDescription) { super(taskDescription); } + /** + * Executes the add to-do command. This method adds a new to-do task + * to the task list, updates the UI, and saves the changes to storage. + * + * @param taskList the task list to which the to-do task will be added + * @param ui the user interface for displaying messages + * @param storage the storage for saving tasks + * @throws IOException if there's an error saving the updated task list + */ @Override public void execute(TaskList taskList, Ui ui, Storage storage) throws IOException { Task newToDoTask = taskList.addToDoTask(super.getTaskDescription()); diff --git a/src/main/java/quinn/command/Command.java b/src/main/java/quinn/command/Command.java index 89e58a360..2b10699c8 100644 --- a/src/main/java/quinn/command/Command.java +++ b/src/main/java/quinn/command/Command.java @@ -7,8 +7,26 @@ import java.io.IOException; +/** + * Represents a command in the task management system. + * This interface defines the basic structure for all commands. + */ public interface Command { + /** + * Checks if this command should cause the program to exit. + * + * @return true if this command should cause the program to exit, false otherwise + */ boolean isExit(); + /** + * Executes the command. + * + * @param taskList the list of tasks to operate on + * @param ui the user interface to display results + * @param storage the storage to save updates + * @throws QuinnException if there's an error specific to the application + * @throws IOException if there's an I/O error during execution + */ void execute(TaskList taskList, Ui ui, Storage storage) throws QuinnException, IOException; } diff --git a/src/main/java/quinn/command/CommandType.java b/src/main/java/quinn/command/CommandType.java index 476031665..75709d512 100644 --- a/src/main/java/quinn/command/CommandType.java +++ b/src/main/java/quinn/command/CommandType.java @@ -1,5 +1,8 @@ package quinn.command; +/** + * Enumerates the types of commands available in the task management system. + */ public enum CommandType { BYE("bye"), LIST("list"), @@ -13,6 +16,12 @@ public enum CommandType { private final String label; + + /** + * Constructs a CommandType with the specified label. + * + * @param label the string representation of the command + */ CommandType(String label) { this.label = label; } diff --git a/src/main/java/quinn/command/DeleteCommand.java b/src/main/java/quinn/command/DeleteCommand.java index 64ed9f7de..2c0552041 100644 --- a/src/main/java/quinn/command/DeleteCommand.java +++ b/src/main/java/quinn/command/DeleteCommand.java @@ -8,9 +8,17 @@ import java.io.IOException; +/** + * Represents a command to delete a task from the task list. + */ public class DeleteCommand implements Command { private final int taskNum; + /** + * Constructs a DeleteCommand with the specified task number. + * + * @param taskNum the number of the task to be deleted + */ public DeleteCommand(int taskNum) { this.taskNum = taskNum; } @@ -40,6 +48,13 @@ public void execute(TaskList taskList, Ui ui, Storage storage) throws QuinnExcep storage.saveTasksToFile(taskList); } + /** + * Deletes a task based on all tasks in the list. + * + * @param taskList the list of all tasks + * @return the deleted task + * @throws QuinnException if the task number is invalid + */ public Task deleteTaskBasedOnAllTasks(TaskList taskList) throws QuinnException { if (taskNum > 0 && taskNum <= taskList.getNumOfTasks()) { return taskList.deleteTask(taskNum); @@ -48,6 +63,13 @@ public Task deleteTaskBasedOnAllTasks(TaskList taskList) throws QuinnException { } } + /** + * Deletes a task based on filtered tasks in the list. + * + * @param taskList the list of filtered tasks + * @return the deleted task + * @throws QuinnException if the task number is invalid + */ public Task deleteTaskBasedOnFilteredTasks(TaskList taskList) throws QuinnException { if (taskNum > 0 && taskNum <= taskList.getNumOfFilteredTasks()) { return taskList.deleteTask(taskNum); diff --git a/src/main/java/quinn/command/ExitCommand.java b/src/main/java/quinn/command/ExitCommand.java index 12ae58d19..50091444c 100644 --- a/src/main/java/quinn/command/ExitCommand.java +++ b/src/main/java/quinn/command/ExitCommand.java @@ -4,7 +4,13 @@ import quinn.task.TaskList; import quinn.ui.Ui; +/** + * Represents a command to exit the task management system. + */ public class ExitCommand implements Command { + /** + * Constructs an ExitCommand. + */ public ExitCommand() { } diff --git a/src/main/java/quinn/command/FindCommand.java b/src/main/java/quinn/command/FindCommand.java index e68b0b539..b3622df87 100644 --- a/src/main/java/quinn/command/FindCommand.java +++ b/src/main/java/quinn/command/FindCommand.java @@ -5,9 +5,17 @@ import quinn.task.TaskList; import quinn.ui.Ui; +/** + * Represents a command to find tasks based on a keyword. + */ public class FindCommand implements Command { private final String keyword; + /** + * Constructs a FindCommand with the specified keyword. + * + * @param keyword the keyword to search for in tasks + */ public FindCommand(String keyword) { this.keyword = keyword; } diff --git a/src/main/java/quinn/command/ListCommand.java b/src/main/java/quinn/command/ListCommand.java index 6b1c75cec..fc6576568 100644 --- a/src/main/java/quinn/command/ListCommand.java +++ b/src/main/java/quinn/command/ListCommand.java @@ -5,7 +5,13 @@ import quinn.task.TaskList; import quinn.ui.Ui; +/** + * Represents a command to list all tasks. + */ public class ListCommand implements Command { + /** + * Constructs a ListCommand. + */ public ListCommand() { } diff --git a/src/main/java/quinn/command/MarkCommand.java b/src/main/java/quinn/command/MarkCommand.java index 4996ea9c7..9d92d6cec 100644 --- a/src/main/java/quinn/command/MarkCommand.java +++ b/src/main/java/quinn/command/MarkCommand.java @@ -8,9 +8,17 @@ import java.io.IOException; +/** + * Represents a command to mark a task as done. + */ public class MarkCommand implements Command { private final int taskNum; + /** + * Constructs a MarkCommand with the specified task number. + * + * @param taskNum the number of the task to be marked as done + */ public MarkCommand(int taskNum) { this.taskNum = taskNum; } @@ -32,6 +40,13 @@ public void execute(TaskList taskList, Ui ui, Storage storage) throws QuinnExcep storage.saveTasksToFile(taskList); } + /** + * Marks a task as done based on all tasks in the list. + * + * @param taskList the list of all tasks + * @return the task marked as done + * @throws QuinnException if the task number is invalid + */ public Task markTaskDoneBasedOnAllTasks(TaskList taskList) throws QuinnException { if (taskNum > 0 && taskNum <= taskList.getNumOfTasks()) { return taskList.markDone(taskNum); @@ -40,6 +55,13 @@ public Task markTaskDoneBasedOnAllTasks(TaskList taskList) throws QuinnException } } + /** + * Marks a task as done based on filtered tasks in the list. + * + * @param taskList the list of filtered tasks + * @return the task marked as done + * @throws QuinnException if the task number is invalid + */ public Task markTaskDoneBasedOnFilteredTasks(TaskList taskList) throws QuinnException { if (taskNum > 0 && taskNum <= taskList.getNumOfFilteredTasks()) { return taskList.markDone(taskNum); diff --git a/src/main/java/quinn/command/UnmarkCommand.java b/src/main/java/quinn/command/UnmarkCommand.java index d33af47e2..b2a585ba2 100644 --- a/src/main/java/quinn/command/UnmarkCommand.java +++ b/src/main/java/quinn/command/UnmarkCommand.java @@ -8,9 +8,17 @@ import java.io.IOException; +/** + * Represents a command to unmark a task (mark it as not done). + */ public class UnmarkCommand implements Command { private final int taskNum; + /** + * Constructs an UnmarkCommand with the specified task number. + * + * @param taskNum the number of the task to be unmarked + */ public UnmarkCommand(int taskNum) { this.taskNum = taskNum; } @@ -32,6 +40,13 @@ public void execute(TaskList taskList, Ui ui, Storage storage) throws QuinnExcep storage.saveTasksToFile(taskList); } + /** + * Marks a task as not done based on all tasks in the list. + * + * @param taskList the list of all tasks + * @return the task marked as not done + * @throws QuinnException if the task number is invalid + */ public Task markTaskNotDoneBasedOnAllTasks(TaskList taskList) throws QuinnException { if (taskNum > 0 && taskNum <= taskList.getNumOfTasks()) { return taskList.markNotDone(taskNum); @@ -40,6 +55,13 @@ public Task markTaskNotDoneBasedOnAllTasks(TaskList taskList) throws QuinnExcept } } + /** + * Marks a task as not done based on filtered tasks in the list. + * + * @param taskList the list of filtered tasks + * @return the task marked as not done + * @throws QuinnException if the task number is invalid + */ public Task markTaskNotDoneBasedOnFilteredTasks(TaskList taskList) throws QuinnException { if (taskNum > 0 && taskNum <= taskList.getNumOfFilteredTasks()) { return taskList.markNotDone(taskNum); diff --git a/src/main/java/quinn/exception/QuinnException.java b/src/main/java/quinn/exception/QuinnException.java index b1591287d..c4760742d 100644 --- a/src/main/java/quinn/exception/QuinnException.java +++ b/src/main/java/quinn/exception/QuinnException.java @@ -1,6 +1,31 @@ package quinn.exception; + +/** + * Represents a custom exception specific to the Quinn application. + * This exception is thrown when application-specific errors occur during execution. + * + * QuinnException extends the standard Java {@link Exception} class, + * allowing it to be caught and handled like any other exception in Java. + * + * This exception is typically used to encapsulate and report errors that are + * specific to the logic or operations of the Quinn application, + * providing more contextual information about what went wrong. + * + * Common scenarios where this exception might be thrown include: + * Attempting to access or modify a non-existent task + * Invalid user input that cannot be processed by Quinn + */ public class QuinnException extends Exception { + /** + * Constructs a new QuinnException with the specified error message. + * + * This constructor creates a QuinnException with a detailed message + * describing the specific error condition that occurred in the Quinn application. + * + * @param errorMessage a detailed message describing the error condition + * that led to this exception being thrown. + */ public QuinnException(String errorMessage) { super(errorMessage); } diff --git a/src/main/java/quinn/parser/Parser.java b/src/main/java/quinn/parser/Parser.java index 9dacf0d0b..51938e005 100644 --- a/src/main/java/quinn/parser/Parser.java +++ b/src/main/java/quinn/parser/Parser.java @@ -13,7 +13,24 @@ import quinn.command.UnmarkCommand; import quinn.exception.QuinnException; + +/** + * The Parser class is responsible for interpreting user input and converting it into + * appropriate Command objects in the Quinn task management application. + * + * This class handles the parsing of various command types, including task creation, + * listing, marking, unmarking, deletion, and searching. It validates user input and + * throws QuinnExceptions for invalid or incomplete commands. + * + */ public class Parser { + /** + * Parses a command line input and returns the corresponding Command object. + * + * @param commandLine the full command line input from the user + * @return a Command object representing the parsed command + * @throws QuinnException if the command is invalid or incomplete + */ public Command parse(String commandLine) throws QuinnException { String[] commandLineParts = commandLine.split("\\s+", 2); @@ -28,6 +45,12 @@ public Command parse(String commandLine) throws QuinnException { return initialiseCommand(commandType, commandInfo); } + /** + * Validates the command type against known command types. + * + * @param commandType the command type string to validate + * @return the corresponding CommandType enum value, or null if invalid + */ private CommandType validateCommand(String commandType) { for (CommandType c : CommandType.values()) { if (c.getLabel().equals(commandType)) { @@ -38,6 +61,14 @@ private CommandType validateCommand(String commandType) { return null; } + /** + * Extracts command information from the command line parts. + * + * @param commandLineParts the split parts of the command line + * @param commandType the type of the command + * @return the command information string + * @throws QuinnException if the command format is invalid + */ private String getCommandInfo(String[] commandLineParts, CommandType commandType) throws QuinnException { String commandInfo; @@ -57,6 +88,14 @@ private String getCommandInfo(String[] commandLineParts, CommandType commandType return commandInfo; } + /** + * Initializes and returns the appropriate Command object based on the command type and information. + * + * @param commandType the type of the command + * @param commandInfo additional information for the command + * @return the initialized Command object + * @throws QuinnException if there's an error in command initialization + */ private Command initialiseCommand(CommandType commandType, String commandInfo) throws QuinnException { Command command; int taskNum; @@ -101,10 +140,23 @@ private Command initialiseCommand(CommandType commandType, String commandInfo) t return command; } + /** + * Checks if the command information is present and non-empty. + * + * @param commandInfo the command information string to check + * @return true if command information is present, false otherwise + */ private boolean isCommandInfoPresent(String commandInfo) { return !commandInfo.trim().isEmpty(); } + /** + * Extracts the task number from a mark command. + * + * @param commandInfo the command information string + * @return the task number to be marked + * @throws QuinnException if the task number is invalid or missing + */ private int getTaskNumFromMarkCommand(String commandInfo) throws QuinnException { if (isCommandInfoPresent(commandInfo)) { try { @@ -117,6 +169,13 @@ private int getTaskNumFromMarkCommand(String commandInfo) throws QuinnException } } + /** + * Extracts the task number from an unmark command. + * + * @param commandInfo the command information string + * @return the task number to be unmarked + * @throws QuinnException if the task number is invalid or missing + */ private int getTaskNumFromUnmarkCommand(String commandInfo) throws QuinnException { if (isCommandInfoPresent(commandInfo)) { try { @@ -129,6 +188,13 @@ private int getTaskNumFromUnmarkCommand(String commandInfo) throws QuinnExceptio } } + /** + * Extracts the task number from a delete command. + * + * @param commandInfo the command information string + * @return the task number to be deleted + * @throws QuinnException if the task number is invalid or missing + */ private int getTaskNumFromDeleteCommand(String commandInfo) throws QuinnException { if (isCommandInfoPresent(commandInfo)) { try { @@ -141,6 +207,13 @@ private int getTaskNumFromDeleteCommand(String commandInfo) throws QuinnExceptio } } + /** + * Extracts the task description from a todo command. + * + * @param commandInfo the command information string + * @return the task description + * @throws QuinnException if the description is empty + */ private String getTaskDescriptionFromToDoCommand(String commandInfo) throws QuinnException { if (isCommandInfoPresent(commandInfo)) { return commandInfo; @@ -149,6 +222,13 @@ private String getTaskDescriptionFromToDoCommand(String commandInfo) throws Quin } } + /** + * Processes and validates the information for a deadline command. + * + * @param commandInfo the command information string + * @return the processed deadline task information + * @throws QuinnException if the deadline information is invalid or incomplete + */ private String processTaskInfoFromDeadlineCommand(String commandInfo) throws QuinnException { if (!isCommandInfoPresent(commandInfo)) { throw new QuinnException("INCOMPLETE COMMAND" @@ -188,6 +268,13 @@ private String processTaskInfoFromDeadlineCommand(String commandInfo) throws Qui } } + /** + * Processes and validates the information for an event command. + * + * @param commandInfo the command information string + * @return the processed event task information + * @throws QuinnException if the event information is invalid or incomplete + */ private String processTaskInfoFromEventCommand(String commandInfo) throws QuinnException { if (!isCommandInfoPresent(commandInfo)) { throw new QuinnException("INCOMPLETE COMMAND" @@ -228,6 +315,13 @@ private String processTaskInfoFromEventCommand(String commandInfo) throws QuinnE } } + /** + * Extracts the keyword from a find command. + * + * @param commandInfo the command information string + * @return the search keyword + * @throws QuinnException if the keyword is missing + */ private String getKeywordFromFindCommand(String commandInfo) throws QuinnException { if (isCommandInfoPresent(commandInfo)) { return commandInfo; diff --git a/src/main/java/quinn/storage/Storage.java b/src/main/java/quinn/storage/Storage.java index fbf6d60bb..5131f1676 100644 --- a/src/main/java/quinn/storage/Storage.java +++ b/src/main/java/quinn/storage/Storage.java @@ -15,14 +15,35 @@ import java.io.FileWriter; import java.io.IOException; +/** + * The Storage class manages the persistence of task data to and from a file. + * It handles the initialization of the storage directory and file, as well as + * reading from and writing to the storage file. + */ public class Storage { + /** The File object representing the data storage file. */ private final File dataFile; + /** + * Constructs a new Storage object with the specified folder and file name. + * + * @param folderName the name of the folder to store the data file + * @param fileName the name of the data file + * @throws QuinnException if unable to initialize the directory + * @throws IOException if unable to initialize the file + */ public Storage(String folderName, String fileName) throws QuinnException, IOException { File directory = initialiseDirectory(folderName); dataFile = initialiseFile(directory, fileName); } + /** + * Initializes the directory for data storage. + * + * @param folderName the name of the folder to be initialized + * @return the File object representing the initialized directory + * @throws QuinnException if unable to initialize the directory + */ private File initialiseDirectory(String folderName) throws QuinnException { File directory = new File(folderName); boolean hasDirectory = directory.exists(); @@ -53,6 +74,13 @@ private File initialiseFile(File directory, String fileName) throws IOException } } + /** + * Loads tasks from the data file and returns them as a TaskList. + * + * @return a TaskList containing all tasks loaded from the file + * @throws QuinnException if an invalid task type is encountered + * @throws IOException if an I/O error occurs while reading the file + */ public TaskList loadTasksFromFile() throws QuinnException, IOException { TaskList taskList = new TaskList(); @@ -91,6 +119,12 @@ public TaskList loadTasksFromFile() throws QuinnException, IOException { return taskList; } + /** + * Saves the given TaskList to the data file. + * + * @param taskList the TaskList to be saved to the file + * @throws IOException if an I/O error occurs while writing to the file + */ public void saveTasksToFile(TaskList taskList) throws IOException { FileWriter fileWriter = new FileWriter(dataFile,false); BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); diff --git a/src/main/java/quinn/task/Deadline.java b/src/main/java/quinn/task/Deadline.java index bf27270f2..0435a2800 100644 --- a/src/main/java/quinn/task/Deadline.java +++ b/src/main/java/quinn/task/Deadline.java @@ -4,20 +4,46 @@ import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; +/** + * Represents a deadline task in the Quinn task management application. + * A deadline task is a task with a specific due date and time. + */ public class Deadline extends Task { + /** The due date and time of the deadline task as a string. */ private final String dueDateTime; + + /** The parsed LocalDateTime object of the due date and time. */ private final LocalDateTime parsedDueDateTime; + /** + * Constructs a new Deadline task with the given description and due date/time. + * + * @param description the description of the task + * @param dueDateTime the due date and time of the task in the format "yyyy-MM-dd HHmm" + */ public Deadline(String description, String dueDateTime) { this(description, dueDateTime, false); } + /** + * Constructs a new Deadline task with the given description, due date/time, and completion status. + * + * @param description the description of the task + * @param dueDateTime the due date and time of the task in the format "yyyy-MM-dd HHmm" + * @param isDone the completion status of the task + */ public Deadline(String description, String dueDateTime, boolean isDone) { super(TaskType.DEADLINE, description, isDone); this.dueDateTime = dueDateTime; this.parsedDueDateTime = parseDateTime(dueDateTime); // parse dueDateTime into a LocalDateTime object } + /** + * Parses the input date/time string into a LocalDateTime object. + * + * @param inputDateTime the input date/time string in the format "yyyy-MM-dd HHmm" + * @return the parsed LocalDateTime object, or null if parsing fails + */ private LocalDateTime parseDateTime(String inputDateTime) { try { DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm"); @@ -27,11 +53,22 @@ private LocalDateTime parseDateTime(String inputDateTime) { } } + /** + * Formats a LocalDateTime object into a readable string. + * + * @param parsedDateTime the LocalDateTime object to format + * @return a formatted string representation of the date/time + */ private String formatDateTime(LocalDateTime parsedDateTime) { DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("MMM d yyyy hh:mm a"); return parsedDateTime.format(outputFormatter); } + /** + * Returns a string representation of the Deadline task. + * + * @return a string representation of the task, including its description and due date/time + */ @Override public String toString() { if (parsedDueDateTime != null) { @@ -41,6 +78,11 @@ public String toString() { } } + /** + * Returns a string representation of the Deadline task suitable for saving to a file. + * + * @return a string representation of the task for file storage + */ public String saveFormat() { if (parsedDueDateTime != null) { return super.saveFormat() + " | " + formatDateTime(parsedDueDateTime); diff --git a/src/main/java/quinn/task/Event.java b/src/main/java/quinn/task/Event.java index 4d8121a28..b32ba90c6 100644 --- a/src/main/java/quinn/task/Event.java +++ b/src/main/java/quinn/task/Event.java @@ -4,16 +4,44 @@ import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; +/** + * Represents an event task in the Quinn task management application. + * An event task is a task with a specific start and end date/time. + */ public class Event extends Task { + /** The start date and time of the event task as a string. */ private final String startDateTime; + + /** The end date and time of the event task as a string. */ private final String endDateTime; + + /** The parsed LocalDateTime object of the start date and time. */ private final LocalDateTime parsedStartDateTime; + + /** The parsed LocalDateTime object of the end date and time. */ private final LocalDateTime parsedEndDateTime; + + /** + * Constructs a new Event task with the given description, start date/time, and end date/time. + * + * @param description the description of the task + * @param startDateTime the start date and time of the event in the format "yyyy-MM-dd HHmm" + * @param endDateTime the end date and time of the event in the format "yyyy-MM-dd HHmm" + */ public Event(String description, String startDateTime, String endDateTime) { this(description, startDateTime, endDateTime, false); } + + /** + * Constructs a new Event task with the given description, start date/time, end date/time, and completion status. + * + * @param description the description of the task + * @param startDateTime the start date and time of the event in the format "yyyy-MM-dd HHmm" + * @param endDateTime the end date and time of the event in the format "yyyy-MM-dd HHmm" + * @param isDone the completion status of the task + */ public Event(String description, String startDateTime, String endDateTime, boolean isDone) { super(TaskType.EVENT, description, isDone); this.startDateTime = startDateTime; @@ -22,6 +50,12 @@ public Event(String description, String startDateTime, String endDateTime, boole this.parsedEndDateTime = parseDateTime(endDateTime); // parse endDateTime into a LocalDateTime object } + /** + * Parses the input date/time string into a LocalDateTime object. + * + * @param inputDateTime the input date/time string in the format "yyyy-MM-dd HHmm" + * @return the parsed LocalDateTime object, or null if parsing fails + */ private LocalDateTime parseDateTime(String inputDateTime) { try { DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm"); @@ -31,11 +65,22 @@ private LocalDateTime parseDateTime(String inputDateTime) { } } + /** + * Formats a LocalDateTime object into a readable string. + * + * @param parsedDateTime the LocalDateTime object to format + * @return a formatted string representation of the date/time + */ private String formatDateTime(LocalDateTime parsedDateTime) { DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern("MMM d yyyy hh:mm a"); return parsedDateTime.format(outputFormatter); } + /** + * Returns a string representation of the Event task. + * + * @return a string representation of the task, including its description, start date/time, and end date/time + */ @Override public String toString() { if (parsedStartDateTime != null && parsedEndDateTime != null) { @@ -47,6 +92,11 @@ public String toString() { } } + /** + * Returns a string representation of the Event task suitable for saving to a file. + * + * @return a string representation of the task for file storage + */ public String saveFormat() { if (parsedStartDateTime != null && parsedEndDateTime != null) { return super.saveFormat() diff --git a/src/main/java/quinn/task/Task.java b/src/main/java/quinn/task/Task.java index b558c1ae1..cc9d0b674 100644 --- a/src/main/java/quinn/task/Task.java +++ b/src/main/java/quinn/task/Task.java @@ -1,21 +1,46 @@ package quinn.task; +/** + * Represents an abstract base class for all types of tasks in the Quinn task management application. + * This class defines common properties and behaviors for all tasks. + * + */ public abstract class Task { private final TaskType type; private final String description; + + /** The completion status of the task. */ private boolean isDone; + /** + * Constructs a new Task with the specified type and description. + * + * @param type the type of the task + * @param description the description of the task + */ public Task(TaskType type, String description) { // By default, the task is not done this(type, description, false); } + /** + * Constructs a new Task with the specified type, description, and completion status. + * + * @param type the type of the task + * @param description the description of the task + * @param isDone the initial completion status of the task + */ public Task(TaskType type, String description, boolean isDone) { this.type = type; this.description = description; this.isDone = isDone; } + /** + * Returns the status icon of the task. + * + * @return "[✔]" if the task is done, "[ ]" otherwise + */ public String getStatusIcon() { if (isDone) { return "[✔]"; // mark done task with ✔ @@ -24,23 +49,41 @@ public String getStatusIcon() { } } + /** Marks the task as done. */ public void setDone() { this.isDone = true; } + /**Marks the task as not done.*/ public void setNotDone() { this.isDone = false; } + /** + * Checks if the task description contains the given keyword (case-insensitive). + * + * @param keyword the keyword to search for in the task description + * @return true if the task description contains the keyword, false otherwise + */ public boolean hasKeyword(String keyword) { return description.toLowerCase().contains(keyword.toLowerCase()); } + /** + * Returns a string representation of the task. + * + * @return a string representation of the task, including its type, status, and description + */ @Override public String toString() { return "[" + type.getAbbreviation() + "] " + getStatusIcon() + " " + description; } + /** + * Returns a string representation of the task suitable for saving to a file. + * + * @return a string representation of the task for file storage + */ public String saveFormat() { return type.getAbbreviation() + " | " + (isDone ? "1" : "0") + " | " + description; } diff --git a/src/main/java/quinn/task/TaskList.java b/src/main/java/quinn/task/TaskList.java index dd782a042..dd7cc7774 100644 --- a/src/main/java/quinn/task/TaskList.java +++ b/src/main/java/quinn/task/TaskList.java @@ -5,12 +5,26 @@ import java.util.ArrayList; import java.util.List; +/** + * Represents a list of tasks in the Quinn task management application. + * This class manages the collection of tasks, including filtering and various operations on tasks. + * The TaskList maintains both a main list of all tasks and a filtered list of tasks. + * The filter is applied when searching for tasks, and is reset in the following scenarios: + * When a new task is added + * When the list command is executed + * When the exit command is executed + * When a delete command is executed and the filtered list becomes empty + */ public class TaskList { private final List tasks; private List filteredTasks; private CommandType filterCommandType; private String filterInfo; + /** + * Constructs an empty TaskList. + * Initializes the main task list and the filtered task list. + */ public TaskList() { this.tasks = new ArrayList(); filteredTasks = new ArrayList<>(); @@ -18,40 +32,93 @@ public TaskList() { filterInfo = null; } + /** + * Returns the total number of tasks in the list. + * + * @return the number of tasks in the main task list. + */ public int getNumOfTasks() { return tasks.size(); } + /** + * Returns the number of tasks in the filtered list. + * + * @return the number of tasks in the filtered task list + */ public int getNumOfFilteredTasks() { return filteredTasks.size(); } + /** + * Retrieves a task from the main task list by its index. + * + * @param index the index of the task to retrieve (0-based) + * @return the Task at the specified index + * @throws IndexOutOfBoundsException if the index is out of range + */ public Task getTask(int index) { return tasks.get(index); } + /** + * Retrieves a task from the filtered task list by its index. + * + * @param index the index of the task to retrieve from the filtered list (0-based) + * @return the Task at the specified index in the filtered list + * @throws IndexOutOfBoundsException if the index is out of range + */ public Task getFilteredTask(int index) { return filteredTasks.get(index); } + /** + * Checks if there is an active filter applied to the task list. + * + * @return true if there are tasks in the filtered list, false otherwise + */ public boolean hasFilter() { return !filteredTasks.isEmpty(); } + /** + * Retrieves the type of command that was used to apply the current filter. + * + * @return the CommandType of the current filter, or null if no filter is applied + */ public CommandType getFilterCommandType() { return filterCommandType; } + /** + * Retrieves the information used for the current filter. + * + * @return the filter information (e.g., keyword for search), or null if no filter is applied + */ public String getFilterInfo() { return filterInfo; } + /** + * Resets the filtered task list and clears filter information. + * This method is typically called when a new operation that affects all tasks is performed. + * This method is called in the following scenarios: + * When a new task is added + * When the list command is executed + * When the exit command is executed + * When a delete command is executed and the filtered list becomes empty + */ public void resetFilteredTasks() { filteredTasks = new ArrayList<>(); filterCommandType = null; filterInfo = null; } + /** + * Filters the tasks based on a given keyword and updates the filtered task list. + * + * @param keyword the keyword to search for in task descriptions + */ public void setFilteredTasksByKeyword(String keyword) { filteredTasks = new ArrayList<>(); @@ -66,40 +133,88 @@ public void setFilteredTasksByKeyword(String keyword) { filterInfo = keyword; } + /** + * Adds a new ToDo task to the task list. + * also resets any active filter. + * @param description the description of the ToDo task + * @return the newly created ToDo task + */ public Task addToDoTask(String description) { Task toDoTask = new ToDo(description); addTask(toDoTask); return toDoTask; } + /** + * Adds a new Deadline task to the task list. + * also resets any filter + * @param description the description of the Deadline task + * @param dueDateTime the due date and time of the Deadline task. This should be in the format "yyyy-MM-dd HHmm". + * @return the newly created Deadline task + */ public Task addDeadlineTask(String description, String dueDateTime) { Task deadlineTask = new Deadline(description, dueDateTime); addTask(deadlineTask); return deadlineTask; } + /** + * Adds a new Event task to the task list. + * also resets any filter + * @param description the description of the Event task + * @param startDateTime the start date and time of the Event task. This should be in the format "yyyy-MM-dd HHmm". + * @param endDateTime the end date and time of the Event task. This should be in the format "yyyy-MM-dd HHmm". + * @return the newly created Event task + */ public Task addEventTask(String description, String startDateTime, String endDateTime) { Task eventTask = new Event(description, startDateTime,endDateTime); addTask(eventTask); return eventTask; } + /** + * Adds a task to the main task list. + * + * @param task the task to be added + */ public void addTask(Task task) { tasks.add(task); } + + /** + * Marks a task as done. + * + * @param taskNum the number of the task to be marked as done (1-based index) + * @return the task that was marked as done + * @throws IndexOutOfBoundsException if the task number is out of range + */ public Task markDone(int taskNum) { Task task = !hasFilter() ? getTask(taskNum - 1) : getFilteredTask(taskNum - 1); task.setDone(); return task; } + /** + * Marks a task as not done. + * + * @param taskNum the number of the task to be marked as not done (1-based index) + * @return the task that was marked as not done + * @throws IndexOutOfBoundsException if the task number is out of range + */ public Task markNotDone(int taskNum) { Task task = !hasFilter() ? getTask(taskNum - 1) : getFilteredTask(taskNum - 1); task.setNotDone(); return task; } + /** + * Deletes a task from the task list. + * + * @param taskNum the number of the task to be deleted (1-based index) + * @return the task that was deleted + * @throws IndexOutOfBoundsException if the task number is out of range + */ public Task deleteTask(int taskNum) { Task task = !hasFilter() ? getTask(taskNum - 1) : getFilteredTask(taskNum - 1); tasks.remove(task); @@ -111,6 +226,11 @@ public Task deleteTask(int taskNum) { return task; } + /** + * Generates a string representation of all tasks in the main task list. + * + * @return a formatted string containing all tasks, each on a new line + */ public String listOfTasksString() { StringBuilder listBuilder = new StringBuilder(); @@ -127,6 +247,11 @@ public String listOfTasksString() { return listBuilder.toString(); } + /** + * Generates a string representation of all tasks in the filtered task list. + * + * @return a formatted string containing all filtered tasks, each on a new line + */ public String listOfFilteredTasksString() { StringBuilder listBuilder = new StringBuilder(); @@ -143,6 +268,11 @@ public String listOfFilteredTasksString() { return listBuilder.toString(); } + /** + * Returns a string representation of the task list. + * + * @return a string representing all tasks or filtered tasks if a filter is applied + */ @Override public String toString() { return !hasFilter() ? listOfTasksString() : listOfFilteredTasksString(); diff --git a/src/main/java/quinn/task/TaskType.java b/src/main/java/quinn/task/TaskType.java index 07eb5e556..1f290345a 100644 --- a/src/main/java/quinn/task/TaskType.java +++ b/src/main/java/quinn/task/TaskType.java @@ -1,16 +1,44 @@ package quinn.task; +/** + * Enumerates the types of tasks available in the Quinn task management application. + * This enum defines the different categories of tasks that can be created and managed within the system. + * + */ public enum TaskType { + /** + * Represents a ToDo task. + * A ToDo task is a simple task without any specific date or time constraints. + */ TODO("T"), + + /** + * A Deadline task is associated with a specific due date and time. + */ DEADLINE("D"), + + /** + * An Event task is associated with both a start and end date and time. + */ EVENT("E"); + /** The single-character abbreviation used to represent the task type. */ private final String abbreviation; + /** + * Constructs a TaskType with the specified abbreviation. + * + * @param abbreviation the single-character string used to represent this task type + */ TaskType(String abbreviation) { this.abbreviation = abbreviation; } + /** + * Retrieves the abbreviation associated with this task type. + * + * @return the single-character string abbreviation of this task type + */ public String getAbbreviation() { return abbreviation; } diff --git a/src/main/java/quinn/task/ToDo.java b/src/main/java/quinn/task/ToDo.java index 7ddf95c5d..41cec904f 100644 --- a/src/main/java/quinn/task/ToDo.java +++ b/src/main/java/quinn/task/ToDo.java @@ -1,10 +1,30 @@ package quinn.task; +/** + * Represents a ToDo task in the Quinn task management application. + * A ToDo task is the simplest form of task, consisting of a description without any specific date or time constraints. + * + * This class extends the abstract {@link Task} class and inherits its basic properties and methods. + * It does not add any additional fields or methods beyond those provided by the parent class. + */ public class ToDo extends Task { + /** + * Constructs a new ToDo task with the given description. + * The task is initially marked as not done. + * + * @param description the description of the ToDo task + */ public ToDo(String description) { super(TaskType.TODO, description); } + /** + * Constructs a new ToDo task with the given description and completion status. + * This constructor is primarily used when loading tasks from storage. + * + * @param description the description of the ToDo task + * @param isDone the initial completion status of the task + */ public ToDo(String description, boolean isDone) { super(TaskType.TODO, description, isDone); } diff --git a/src/main/java/quinn/ui/Ui.java b/src/main/java/quinn/ui/Ui.java index 311b290b5..07cbf3891 100644 --- a/src/main/java/quinn/ui/Ui.java +++ b/src/main/java/quinn/ui/Ui.java @@ -5,10 +5,26 @@ import java.util.Scanner; +/** + * The Ui (User Interface) class handles all interactions between the Quinn task management application + * and the user. It is responsible for displaying information to the user and reading user input. + * This class provides methods for reading commands, displaying various messages and task information, + * and formatting the output for better readability. + */ public class Ui { + + /** + * Constructs a new Ui object. + * This constructor doesn't initialize any fields as the Ui class currently has no instance variables. + */ public Ui() { } + /** + * Reads a command from the user via the console. + * + * @return the user's input command as a trimmed string + */ public String readCommand() { Scanner sc = new Scanner(System.in); System.out.println("Enter Command:"); @@ -16,6 +32,10 @@ public String readCommand() { return sc.nextLine().trim(); } + /** + * Displays a welcome message and the Quinn logo when the application starts. + * This method prints the welcome message and logo to the console. + */ public void displayWelcome() { String logo = "\t" + " QQQ U U III N N N N " + System.lineSeparator() + "\t" + " Q Q U U I NN N NN N " + System.lineSeparator() @@ -30,65 +50,126 @@ public void displayWelcome() { + System.lineSeparator() + logo + System.lineSeparator() - + "\t" + "What can I do for you?"; + + "\t" + "How can I help you?"; displayResponse(welcomeMessage); displayLine(); } + /** + * Displays an exit message when the user chooses to exit the application. + * This method prints the farewell message to the console. + */ public void displayExit() { String exitMessage = "\t" + "Farewell. Hope to see you again soon!"; displayResponse(exitMessage); } + + /** + * Displays a given message to the user, prefixed with a horizontal line for better readability. + * + * @param message the message to be displayed + */ public void displayResponse(String message) { displayLine(); System.out.println(message); } + + /** + * Displays an error message to the user + * + * @param message the error message to be displayed + */ public void displayError(String message) { displayLine(); System.out.println("Error Message:"); System.out.println("\t" + "('-')? " + message); } + /** + * Displays a list of filtered tasks to the user. + * + * @param message the message containing the filtered task information + */ public void displayFilteredTasks(String message) { displayLine(); System.out.println("[FILTERED TASKS]" + System.lineSeparator()); System.out.println(message); } + /** + * Displays a horizontal line for separating different sections of output. + */ public void displayLine() { String horizontalLine = "____________________________________________________________"; System.out.println(horizontalLine); } + + /** + * Generates a message indicating that a task has been added to the list. + * + * @param task the Task that was added + * @return a formatted string confirming the addition of the task + */ public String taskAddedMessage(Task task) { return "\t" + "Got it. I've added this task:" + System.lineSeparator() + "\t\t" + task; } + /** + * Generates a message indicating that a task has been marked as done. + * + * @param task the Task that was marked as done + * @return a formatted string confirming the task has been marked as done + */ public String taskDoneMessage(Task task) { return "\t" + "Roger! I've marked this task as done:" + System.lineSeparator() + "\t\t" + task; } + /** + * Generates a message indicating that a task has been marked as not done. + * + * @param task the Task that was marked as not done + * @return a formatted string confirming the task has been marked as not done + */ public String taskNotDoneMessage(Task task) { return "\t" + "OK, I've marked this task as not done yet:" + System.lineSeparator() + "\t\t" + task; } + /** + * Generates a message indicating that a task has been deleted from the list. + * + * @param task the Task that was deleted + * @return a formatted string confirming the deletion of the task + */ public String taskDeletedMessage(Task task) { - return "\t" + "Noted. I've removed this task:" + return "\t" + "Roger. I've removed this task:" + System.lineSeparator() + "\t\t" + task; } + /** + * Generates a message indicating the current number of tasks in the list. + * + * @param taskList the TaskList containing the tasks + * @return a formatted string stating the number of tasks in the list + */ public String numOfTasksInListMessage(TaskList taskList) { return "\t" + "Now you have " + taskList.getNumOfTasks() + (taskList.getNumOfTasks() > 1 ? " tasks" : " task") + " in the list."; } + /** + * Generates a message listing all tasks currently in the task list. + * + * @param taskList the TaskList containing the tasks to be listed + * @return a formatted string containing all tasks in the list + */ public String tasksInListMessage(TaskList taskList) { return "\t" + "Here" + (taskList.getNumOfTasks() > 1 ? " are the tasks " : " is the task ") @@ -100,6 +181,13 @@ public String tasksInListMessage(TaskList taskList) { + taskList; } + /** + * Generates a message listing all tasks that match a given keyword. + * + * @param taskList the TaskList containing the filtered tasks + * @param keyword the keyword used for filtering the tasks + * @return a formatted string containing all tasks that match the keyword + */ public String tasksWithKeywordMessage(TaskList taskList, String keyword) { return "\t" + "Here" + (taskList.getNumOfFilteredTasks() > 1 ? " are the matching tasks " : " is the matching task ") From c621d5ee2ac4bc00af42028dbfcc76e7c7c21153 Mon Sep 17 00:00:00 2001 From: kaboomzxc Date: Wed, 9 Oct 2024 01:49:31 +0800 Subject: [PATCH 19/28] Implement User Guide --- build.gradle | 44 ++++++++++ docs/README.md | 232 +++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 260 insertions(+), 16 deletions(-) create mode 100644 build.gradle diff --git a/build.gradle b/build.gradle new file mode 100644 index 000000000..d8f94ce07 --- /dev/null +++ b/build.gradle @@ -0,0 +1,44 @@ +plugins { + id 'java' + id 'com.github.johnrengelman.shadow' version '8.1.1' +} + +group 'org.example' +version '1.0-SNAPSHOT' + +repositories { + mavenCentral() +} + +sourceSets { + main { + java { + srcDirs = ['src'] + } + } +} + +dependencies { + testImplementation platform('org.junit:junit-bom:5.10.0') + testImplementation 'org.junit.jupiter:junit-jupiter' + + // Add any other dependencies your project requires here +} + +test { + useJUnitPlatform() +} + +shadowJar { + // Set the name of the output JAR file + archiveBaseName.set('Quinn') + archiveClassifier.set('') + archiveVersion.set('') + + // Specify the Main-Class attribute in the manifest + manifest { + attributes( + 'Main-Class': 'quinn.Quinn' + ) + } +} diff --git a/docs/README.md b/docs/README.md index fa75c6e58..21af34ceb 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,30 +1,230 @@ -# quinn.Quinn User Guide +Quinn Task Manager User Guide -// Update the title above to match the actual product name +Table of Contents -// Product screenshot goes here +1. Introduction +2. Getting Started +3. Main Features +3.1 Adding Tasks +3.2 Listing Tasks +3.3 Marking Tasks as Done +3.4 Unmarking Tasks +3.5 Deleting Tasks +3.6 Finding Tasks +4. Command Reference +5. Understanding Task Types +6. Error Handling +7. Data Storage +8. Tips and Best Practices +9. Troubleshooting +10. Quinn Command Summary -// Product intro goes here +1. Introduction + Welcome to Quinn, your personal task management assistant! Quinn is a command-line application designed to help you efficiently manage your tasks, deadlines, and events. With its simple yet powerful interface, Quinn makes it easy to keep track of your to-do list and stay organized. + Key Features: -## Adding deadlines +Add various types of tasks: ToDos, Deadlines, and Events +List and view your tasks +Mark tasks as done or not done +Delete tasks +Search for specific tasks +Persistent storage of your tasks -// Describe the action and its outcome. +2. Getting Started + System Requirements -// Give examples of usage +Java Runtime Environment (JRE) 8 or higher -Example: `keyword (optional arguments)` +Installation -// A description of the expected outcome goes here +Download the Quinn.jar file from [insert download link here]. +Place the JAR file in your desired directory. -``` -expected output -``` +Running Quinn +Open a command prompt or terminal, navigate to the directory containing Quinn.jar, and run: +java -jar Quinn.jar +Upon successful launch, you'll see the Quinn welcome message: +Hello! I'm Quinn, your Personal Assistant ChatBot. -## Feature ABC +QQQ U U III N N N N +Q Q U U I NN N NN N +Q Q U U I N N N N N N +Q Q U U I N NN N NN +QQQ UUU III N N N N +Q +QQ -// Feature details +What can I do for you? +3. Main Features + 3.1 Adding Tasks + Quinn supports three types of tasks: ToDos, Deadlines, and Events. + Adding a ToDo + Command: todo [description] + Example: + Enter Command: + todo Buy groceries + Output: + Got it. I've added this task: + [T][ ] Buy groceries + Now you have 1 task in the list. + Adding a Deadline + Command: deadline [description] /by [date] [time] + Example: + Enter Command: + deadline Submit report /by 2023-06-30 1400 + Output: + Got it. I've added this task: + [D][ ] Submit report (by: Jun 30 2023 02:00 PM) + Now you have 2 tasks in the list. + Adding an Event + Command: event [description] /from [start date] [start time] /to [end date] [end time] + Example: + Enter Command: + event Team meeting /from 2023-06-15 0900 /to 2023-06-15 1100 + Output: + Got it. I've added this task: + [E][ ] Team meeting (from: Jun 15 2023 09:00 AM to: Jun 15 2023 11:00 AM) + Now you have 3 tasks in the list. + 3.2 Listing Tasks + To view all your tasks, use the list command. + Command: list + Example: + Enter Command: + list + Output: + Here are the tasks in your list: + [Legend: T = todo, D = deadline, E = event] + 1.[T][ ] Buy groceries + 2.[D][ ] Submit report (by: Jun 30 2023 02:00 PM) + 3.[E][ ] Team meeting (from: Jun 15 2023 09:00 AM to: Jun 15 2023 11:00 AM) + 3.3 Marking Tasks as Done + To mark a task as completed, use the mark command followed by the task number. + Command: mark [task number] + Example: + Enter Command: + mark 1 + Output: + Roger! I've marked this task as done: + [T][✔] Buy groceries + 3.4 Unmarking Tasks + To mark a completed task as not done, use the unmark command followed by the task number. + Command: unmark [task number] + Example: + Enter Command: + unmark 1 + Output: + OK, I've marked this task as not done yet: + [T][ ] Buy groceries + 3.5 Deleting Tasks + To remove a task from your list, use the delete command followed by the task number. + Command: delete [task number] + Example: + Enter Command: + delete 2 + Output: + Noted. I've removed this task: + [D][ ] Submit report (by: Jun 30 2023 02:00 PM) + Now you have 2 tasks in the list. + 3.6 Finding Tasks + To search for tasks containing a specific keyword, use the find command. + Command: find [keyword] + Example: + Enter Command: + find meeting + Output: + Here is the matching task in your list: + [Keyword Search: meeting] + [Legend: T = todo, D = deadline, E = event] -## Feature XYZ + 1.[E][ ] Team meeting (from: Jun 15 2023 09:00 AM to: Jun 15 2023 11:00 AM) +4. Command Reference + Here's a quick reference for all available commands: -// Feature details \ No newline at end of file +todo [description]: Add a ToDo task +deadline [description] /by [date] [time]: Add a Deadline task +event [description] /from [start date] [start time] /to [end date] [end time]: Add an Event task +list: Display all tasks +mark [task number]: Mark a task as done +unmark [task number]: Mark a task as not done +delete [task number]: Remove a task +find [keyword]: Search for tasks containing the keyword +bye: Exit the application + +5. Understanding Task Types + Quinn supports three types of tasks: + +ToDo: A simple task without any date/time constraint. + +Displayed as: [T][ ] Description + + +Deadline: A task with a specific due date and time. + +Displayed as: [D][ ] Description (by: Date Time) + + +Event: A task with a start and end date/time. + +Displayed as: [E][ ] Description (from: Start Date Time to: End Date Time) + + + +The square brackets next to the task type indicator (T/D/E) show the task's completion status: + +[ ]: Task is not done +[✔]: Task is done + +6. Error Handling + Quinn will display error messages if it encounters issues. Here are some common errors and their meanings: + +"INVALID COMMAND. Please try again!": The command entered is not recognized. +"The description of a todo cannot be empty!": You need to provide a description for the ToDo task. +"INCOMPLETE COMMAND": Some required information is missing from the command. +"Task not found. Please try again!": The task number provided doesn't exist in the list. +"Please enter a valid task number to be marked as done!": The mark/unmark command requires a valid task number. + +If you encounter an error, read the error message carefully and adjust your command accordingly. +7. Data Storage + Quinn automatically saves your tasks to a file named "tasks.txt" in a "data" folder in the same directory as the Quinn.jar file. This ensures that your tasks persist between sessions. + Note: Do not modify the "tasks.txt" file manually, as this may cause Quinn to malfunction. +8. Tips and Best Practices + +Use descriptive task names to make them easier to find later. +Regularly review and update your task list to keep it current. +Use the find command to quickly locate specific tasks in a long list. +Mark tasks as done as soon as you complete them to keep your list up-to-date. + +9. Troubleshooting + If you encounter issues while using Quinn: +Ensure you're using the correct command syntax. +Check that your Java Runtime Environment is up to date. +Make sure Quinn has write permissions in its directory for saving tasks. +If Quinn fails to start, check your system's console for error messages. + +10. Quinn Command Summary +## Quinn Command Summary + +| Command | Description | Example | +|---------|-------------|---------| +| `todo [description]` | Add a ToDo task | `todo Buy groceries` | +| `deadline [description] /by [date] [time]` | Add a Deadline task | `deadline Submit report /by 2023-06-30 1400` | +| `event [description] /from [start date] [start time] /to [end date] [end time]` | Add an Event task | `event Team meeting /from 2023-06-15 0900 /to 2023-06-15 1100` | +| `list` | Display all tasks | `list` | +| `mark [task number]` | Mark a task as done | `mark 1` | +| `unmark [task number]` | Mark a task as not done | `unmark 2` | +| `delete [task number]` | Remove a task | `delete 3` | +| `find [keyword]` | Search for tasks containing the keyword | `find meeting` | +| `bye` | Exit the application | `bye` | + +### Examples of Task Display + +After using these commands, tasks will be displayed in the following format: + +1. ToDo: `[T][ ] Buy groceries` +2. Deadline: `[D][ ] Submit report (by: Jun 30 2023 02:00 PM)` +3. Event: `[E][ ] Team meeting (from: Jun 15 2023 09:00 AM to: Jun 15 2023 11:00 AM)` + +Note: +- `[ ]` indicates a task is not done +- `[✔]` indicates a task is done \ No newline at end of file From b0bf095cd96918404a9344907883954a5abb06ac Mon Sep 17 00:00:00 2001 From: kaboomzxc Date: Wed, 9 Oct 2024 21:39:45 +0800 Subject: [PATCH 20/28] Update User Guide --- docs/README.md | 249 +++++++++++++++++-------------------------------- 1 file changed, 83 insertions(+), 166 deletions(-) diff --git a/docs/README.md b/docs/README.md index 21af34ceb..7c3326b78 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,145 +1,78 @@ -Quinn Task Manager User Guide - -Table of Contents - -1. Introduction -2. Getting Started -3. Main Features -3.1 Adding Tasks -3.2 Listing Tasks -3.3 Marking Tasks as Done -3.4 Unmarking Tasks -3.5 Deleting Tasks -3.6 Finding Tasks -4. Command Reference -5. Understanding Task Types -6. Error Handling -7. Data Storage -8. Tips and Best Practices -9. Troubleshooting -10. Quinn Command Summary - -1. Introduction - Welcome to Quinn, your personal task management assistant! Quinn is a command-line application designed to help you efficiently manage your tasks, deadlines, and events. With its simple yet powerful interface, Quinn makes it easy to keep track of your to-do list and stay organized. - Key Features: - -Add various types of tasks: ToDos, Deadlines, and Events -List and view your tasks -Mark tasks as done or not done -Delete tasks -Search for specific tasks -Persistent storage of your tasks - -2. Getting Started - System Requirements - -Java Runtime Environment (JRE) 8 or higher - -Installation - -Download the Quinn.jar file from [insert download link here]. -Place the JAR file in your desired directory. - -Running Quinn -Open a command prompt or terminal, navigate to the directory containing Quinn.jar, and run: -java -jar Quinn.jar -Upon successful launch, you'll see the Quinn welcome message: -Hello! I'm Quinn, your Personal Assistant ChatBot. - -QQQ U U III N N N N -Q Q U U I NN N NN N -Q Q U U I N N N N N N -Q Q U U I N NN N NN -QQQ UUU III N N N N -Q -QQ - -What can I do for you? -3. Main Features - 3.1 Adding Tasks - Quinn supports three types of tasks: ToDos, Deadlines, and Events. - Adding a ToDo - Command: todo [description] - Example: - Enter Command: - todo Buy groceries - Output: - Got it. I've added this task: - [T][ ] Buy groceries - Now you have 1 task in the list. - Adding a Deadline - Command: deadline [description] /by [date] [time] - Example: - Enter Command: - deadline Submit report /by 2023-06-30 1400 - Output: - Got it. I've added this task: - [D][ ] Submit report (by: Jun 30 2023 02:00 PM) - Now you have 2 tasks in the list. - Adding an Event - Command: event [description] /from [start date] [start time] /to [end date] [end time] - Example: - Enter Command: - event Team meeting /from 2023-06-15 0900 /to 2023-06-15 1100 - Output: - Got it. I've added this task: - [E][ ] Team meeting (from: Jun 15 2023 09:00 AM to: Jun 15 2023 11:00 AM) - Now you have 3 tasks in the list. - 3.2 Listing Tasks - To view all your tasks, use the list command. - Command: list - Example: - Enter Command: - list - Output: - Here are the tasks in your list: - [Legend: T = todo, D = deadline, E = event] - - 1.[T][ ] Buy groceries - 2.[D][ ] Submit report (by: Jun 30 2023 02:00 PM) - 3.[E][ ] Team meeting (from: Jun 15 2023 09:00 AM to: Jun 15 2023 11:00 AM) - 3.3 Marking Tasks as Done - To mark a task as completed, use the mark command followed by the task number. - Command: mark [task number] - Example: - Enter Command: - mark 1 - Output: - Roger! I've marked this task as done: - [T][✔] Buy groceries - 3.4 Unmarking Tasks - To mark a completed task as not done, use the unmark command followed by the task number. - Command: unmark [task number] - Example: - Enter Command: - unmark 1 - Output: - OK, I've marked this task as not done yet: - [T][ ] Buy groceries - 3.5 Deleting Tasks - To remove a task from your list, use the delete command followed by the task number. - Command: delete [task number] - Example: - Enter Command: - delete 2 - Output: - Noted. I've removed this task: - [D][ ] Submit report (by: Jun 30 2023 02:00 PM) - Now you have 2 tasks in the list. - 3.6 Finding Tasks - To search for tasks containing a specific keyword, use the find command. - Command: find [keyword] - Example: - Enter Command: - find meeting - Output: - Here is the matching task in your list: - [Keyword Search: meeting] - [Legend: T = todo, D = deadline, E = event] - - 1.[E][ ] Team meeting (from: Jun 15 2023 09:00 AM to: Jun 15 2023 11:00 AM) -4. Command Reference - Here's a quick reference for all available commands: +# Quinn Task Manager User Guide + +Quinn is a personal assistant chatbot that helps in Task Management. +It is a desktop application optimized to use from a Command Line Interface (CLI). +Quinn helps to keep track of your to-dos, deadlines, and events. +With Quinn, you can easily add, list, mark, and delete tasks using simple commands. + +## Table of Contents +1. [Quick Start](#quick-start) +2. [Features](#features) +3. [Command Reference](#command-reference) +4. [Understanding Task Types](#understanding-task-types) +5. [Error Handling](#error-handling) +6. [Data Storage](#data-storage) +7. [Command Summary](#command-summary) + +## Quick Start + +1. Ensure you have Java 17 installed on your computer. +2. Download the latest `Quinn.jar` file from [here](https://github.com/kaboomzxc/ip/releases/tag/A-Release). +3. Copy the file to your desired folder. +4. Open a command prompt or terminal, navigate to the folder containing Quinn.jar, and run: **java -jar Quinn.jar** + + +## Features + +### Adding Tasks + +Quinn supports three types of tasks: ToDos, Deadlines, and Events. + +#### Adding a ToDo +Command: `todo ` +Example: `todo Buy groceries` + +#### Adding a Deadline +Command: `deadline /by