From 0897fa14f9d338d8f4f8a30fc7c5f4f2a589fc00 Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Sun, 9 Feb 2025 12:24:13 +0800 Subject: [PATCH 01/25] Level 0. Rename, Greet, Exit --- src/main/java/Eddie.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/main/java/Eddie.java diff --git a/src/main/java/Eddie.java b/src/main/java/Eddie.java new file mode 100644 index 000000000..636e57a00 --- /dev/null +++ b/src/main/java/Eddie.java @@ -0,0 +1,12 @@ +public class Eddie { + public static void main(String[] args) { + System.out.println("____________________________________________________________"); + System.out.println("Hello! I'm Eddie"); + System.out.println("What can I do for you?"); + System.out.println("____________________________________________________________"); + System.out.println(); + System.out.println("____________________________________________________________"); + System.out.println("Bye. Hope to see you again soon!"); + System.out.println("____________________________________________________________"); + } +} From 07734412d136edeed3ac770c3c914aab91397b23 Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Mon, 10 Feb 2025 15:42:35 +0800 Subject: [PATCH 02/25] Level 1. Echo --- src/main/java/Eddie.java | 57 +++++++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/src/main/java/Eddie.java b/src/main/java/Eddie.java index 636e57a00..b866e947c 100644 --- a/src/main/java/Eddie.java +++ b/src/main/java/Eddie.java @@ -1,12 +1,55 @@ +import java.util.Scanner; + public class Eddie { public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + Display.showStartScreen(); + + while(true) { + String userInput = scanner.nextLine(); + if(userInput.equals("bye")) { + Display.showEndScreen(); + break; + } + Display.echoUserInput(userInput); + } + scanner.close(); + } +} + +class Display { + public static void showStartScreen() { + String logo = " ______ ______ ______ ___ ______ \n" + + " | ____| | __ \\ | __ \\ | | | ____| \n" + + " | |___ | | | | | | | | | | | |___ \n" + + " | ___| | | | | | | | | | | | ___| \n" + + " | |____ | |__| | | |__| | | | | |____ \n" + + " |______| |_____/ |______/ |_| |______|"; + String startScreen = "Eddie:\n" + + "Hello! I'm Eddie, your friendly assistant.\n" + + "How can I help you today?\n"; + + printLine(); + System.out.println(logo); + printLine(); + System.out.println(startScreen); + printLine(); + } + public static void showEndScreen() { + String endScreen = "Eddie:\n" + + "Goodbye! Hope to see you soon!\n"; + printLine(); + System.out.println(endScreen); + printLine(); + } + + public static void printLine() { System.out.println("____________________________________________________________"); - System.out.println("Hello! I'm Eddie"); - System.out.println("What can I do for you?"); - System.out.println("____________________________________________________________"); - System.out.println(); - System.out.println("____________________________________________________________"); - System.out.println("Bye. Hope to see you again soon!"); - System.out.println("____________________________________________________________"); + } + + public static void echoUserInput(String input) { + printLine(); + System.out.println("Eddie:\n" + input); + printLine(); } } From 479267b429fbcee23107f860e8f1fd52dcc7c029 Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Mon, 10 Feb 2025 16:03:32 +0800 Subject: [PATCH 03/25] no message --- src/main/java/Duke.java | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 src/main/java/Duke.java 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); - } -} From bd94a754383b6d469a74aa1280a4412e6b79d10b Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Mon, 10 Feb 2025 16:04:01 +0800 Subject: [PATCH 04/25] Revert "no message" This reverts commit 479267b429fbcee23107f860e8f1fd52dcc7c029. --- src/main/java/Duke.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/Duke.java diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java new file mode 100644 index 000000000..5d313334c --- /dev/null +++ b/src/main/java/Duke.java @@ -0,0 +1,10 @@ +public class Duke { + public static void main(String[] args) { + String logo = " ____ _ \n" + + "| _ \\ _ _| | _____ \n" + + "| | | | | | | |/ / _ \\\n" + + "| |_| | |_| | < __/\n" + + "|____/ \\__,_|_|\\_\\___|\n"; + System.out.println("Hello from\n" + logo); + } +} From 955c3e141a1414c0bcf200283cb70c4ff136e4c8 Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Mon, 10 Feb 2025 16:05:13 +0800 Subject: [PATCH 05/25] Reapply "no message" This reverts commit bd94a754383b6d469a74aa1280a4412e6b79d10b. --- src/main/java/Duke.java | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 src/main/java/Duke.java 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); - } -} From ae75c2a7b1068e7e20313ffc5f7e1781c1725d97 Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Tue, 11 Feb 2025 00:42:55 +0800 Subject: [PATCH 06/25] Level 2. Add, List --- src/main/java/Eddie.java | 103 +++++++++++++++++++++++++++++---------- 1 file changed, 76 insertions(+), 27 deletions(-) diff --git a/src/main/java/Eddie.java b/src/main/java/Eddie.java index b866e947c..2cd298655 100644 --- a/src/main/java/Eddie.java +++ b/src/main/java/Eddie.java @@ -1,55 +1,104 @@ import java.util.Scanner; public class Eddie { + private boolean isRunning = true; + private static final int MAX_TASKS = 100; + private String[] tasks = new String[MAX_TASKS]; + private int countTask = 0; + public static void main(String[] args) { + Eddie eddie = new Eddie(); + eddie.run(); + } + + public void run() { + Display.showStartPage(); Scanner scanner = new Scanner(System.in); - Display.showStartScreen(); - while(true) { - String userInput = scanner.nextLine(); - if(userInput.equals("bye")) { - Display.showEndScreen(); - break; - } - Display.echoUserInput(userInput); + while (isRunning) { + System.out.print("You: "); + String userInput = scanner.nextLine().trim(); + Display.printLine(); + processUserInput(userInput); } scanner.close(); } + + private void processUserInput(String input) { + switch (input.toLowerCase()) { + case "bye": + isRunning = false; + Display.showEndPage(); + break; + case "list": + Display.showTaskList(tasks, countTask); + break; + default: + addTask(input); + break; + } + Display.printLine(); + } + + private void addTask(String task) { + if (countTask < MAX_TASKS) { + tasks[countTask] = task; + countTask++; + Display.showTaskAdded(tasks[countTask -1]); + } + else { + Display.showError("You have reached the maximum number of tasks"); + } + } } class Display { - public static void showStartScreen() { - String logo = " ______ ______ ______ ___ ______ \n" - + " | ____| | __ \\ | __ \\ | | | ____| \n" - + " | |___ | | | | | | | | | | | |___ \n" - + " | ___| | | | | | | | | | | | ___| \n" - + " | |____ | |__| | | |__| | | | | |____ \n" - + " |______| |_____/ |______/ |_| |______|"; + public static void showStartPage() { + String logo = + " _____ ____ ____ ___ _____ \n" + + " | ____|| _ \\| _ \\|_ _|| ____| \n" + + " | _| | | | | | | || | | _| \n" + + " | |___ | |_| | |_| || | | |___ \n" + + " |_____||____/|____/|___||_____| \n"; + String startScreen = "Eddie:\n" + "Hello! I'm Eddie, your friendly assistant.\n" - + "How can I help you today?\n"; + + "Type anything to add it as a task!\n" + + "Type 'list' to view your tasks or 'bye' to exit.\n"; - printLine(); System.out.println(logo); printLine(); System.out.println(startScreen); printLine(); } - public static void showEndScreen() { - String endScreen = "Eddie:\n" - + "Goodbye! Hope to see you soon!\n"; - printLine(); - System.out.println(endScreen); - printLine(); + + public static void showEndPage() { + System.out.println("Eddie:\nGoodbye! Hope to see you again soon!"); } public static void printLine() { System.out.println("____________________________________________________________"); } - public static void echoUserInput(String input) { - printLine(); - System.out.println("Eddie:\n" + input); - printLine(); + public static void showTaskAdded(String task) { + System.out.println("Eddie:\nTask added: " + task); + } + + public static void showTaskList(String[] tasks, int countTask) { + System.out.println("Eddie:\nHere are your tasks:"); + + if (countTask == 0) { + System.out.println("No tasks added yet."); + } + else { + for (int i = 0; i < countTask; i++) { + System.out.println((i + 1) + ". " + tasks[i]); + } + } + } + + public static void showError(String message) { + System.out.println("Eddie:\nError: " + message); } } + From bd6973cae8c793952890881aedbcb628b9e6cb87 Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Tue, 11 Feb 2025 01:50:41 +0800 Subject: [PATCH 07/25] Level 3. Mark as Done --- src/main/java/Eddie.java | 118 +++++++++++++++++++++++++++++++-------- 1 file changed, 96 insertions(+), 22 deletions(-) diff --git a/src/main/java/Eddie.java b/src/main/java/Eddie.java index 2cd298655..141bfcb31 100644 --- a/src/main/java/Eddie.java +++ b/src/main/java/Eddie.java @@ -3,8 +3,8 @@ public class Eddie { private boolean isRunning = true; private static final int MAX_TASKS = 100; - private String[] tasks = new String[MAX_TASKS]; - private int countTask = 0; + private Task[] tasks = new Task[MAX_TASKS]; // Store Task objects + private int taskCount = 0; public static void main(String[] args) { Eddie eddie = new Eddie(); @@ -23,15 +23,32 @@ public void run() { } scanner.close(); } - + private void processUserInput(String input) { - switch (input.toLowerCase()) { + String[] parts = input.split(" ", 2); + String command = parts[0]; + + switch (command.toLowerCase()) { case "bye": isRunning = false; Display.showEndPage(); break; case "list": - Display.showTaskList(tasks, countTask); + Display.showTaskList(tasks, taskCount); + break; + case "mark": + if (parts.length > 1) { + markTask(parts[1]); + } else { + Display.showError("Please provide a task number to mark."); + } + break; + case "unmark": + if (parts.length > 1) { + unmarkTask(parts[1]); + } else { + Display.showError("Please provide a task number to unmark."); + } break; default: addTask(input); @@ -40,16 +57,63 @@ private void processUserInput(String input) { Display.printLine(); } - private void addTask(String task) { - if (countTask < MAX_TASKS) { - tasks[countTask] = task; - countTask++; - Display.showTaskAdded(tasks[countTask -1]); - } - else { + private void addTask(String taskName) { + if (taskCount < MAX_TASKS) { + tasks[taskCount] = new Task(taskName); + taskCount++; + Display.showTaskAdded(taskName); + } else { Display.showError("You have reached the maximum number of tasks"); } } + + private void markTask(String indexStr) { + int index = Integer.parseInt(indexStr) - 1; + if (index >= 0 && index < taskCount) { + tasks[index].markDone(); + Display.showTaskMarked(tasks[index]); + } else { + Display.showError("Invalid task number."); + } + + } + + private void unmarkTask(String indexStr) { + int index = Integer.parseInt(indexStr) - 1; + if (index >= 0 && index < taskCount) { + tasks[index].markNotDone(); + Display.showTaskUnmarked(tasks[index]); + } else { + Display.showError("Invalid task number."); + } + } +} + + +class Task { + private String description; + private boolean isDone; + + public Task(String description) { + this.description = description; + this.isDone = false; + } + + public void markDone() { + this.isDone = true; + } + + public void markNotDone() { + this.isDone = false; + } + + public String getIcon() { + return isDone ? "[X]" : "[ ]"; + } + + public String getDescription() { + return description; + } } class Display { @@ -64,7 +128,7 @@ public static void showStartPage() { String startScreen = "Eddie:\n" + "Hello! I'm Eddie, your friendly assistant.\n" + "Type anything to add it as a task!\n" - + "Type 'list' to view your tasks or 'bye' to exit.\n"; + + "Use 'list' to view tasks, 'mark {num}' to mark done, and 'unmark {num}' to undo.\n"; System.out.println(logo); printLine(); @@ -80,25 +144,35 @@ public static void printLine() { System.out.println("____________________________________________________________"); } - public static void showTaskAdded(String task) { - System.out.println("Eddie:\nTask added: " + task); + public static void showTaskAdded(String taskName) { + System.out.println("Eddie:\nTask added: " + taskName); } - public static void showTaskList(String[] tasks, int countTask) { - System.out.println("Eddie:\nHere are your tasks:"); + public static void showTaskList(Task[] tasks, int taskCount) { + System.out.println("Eddie:\nHere are the tasks in your list:"); - if (countTask == 0) { + if (taskCount == 0) { System.out.println("No tasks added yet."); - } - else { - for (int i = 0; i < countTask; i++) { - System.out.println((i + 1) + ". " + tasks[i]); + } else { + for (int i = 0; i < taskCount; i++) { + System.out.println((i + 1) + ". " + tasks[i].getIcon() + " " + tasks[i].getDescription()); } } } + public static void showTaskMarked(Task task) { + System.out.println("Eddie:\nYay! I've marked this task as done:"); + System.out.println(" " + task.getIcon() + " " + task.getDescription()); + } + + public static void showTaskUnmarked(Task task) { + System.out.println("Eddie:\nOh no!, I've marked this task as not done yet:"); + System.out.println(" " + task.getIcon() + " " + task.getDescription()); + } + public static void showError(String message) { System.out.println("Eddie:\nError: " + message); } } + From 5950407799d1e14a9520319613055fbd175e8d4f Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Tue, 11 Feb 2025 02:08:55 +0800 Subject: [PATCH 08/25] A-CodingStandard --- src/main/java/Eddie.java | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/main/java/Eddie.java b/src/main/java/Eddie.java index 141bfcb31..4b148d641 100644 --- a/src/main/java/Eddie.java +++ b/src/main/java/Eddie.java @@ -99,21 +99,13 @@ public Task(String description) { this.isDone = false; } - public void markDone() { - this.isDone = true; - } + public void markDone() {this.isDone = true;} - public void markNotDone() { - this.isDone = false; - } + public void markNotDone() {this.isDone = false;} - public String getIcon() { - return isDone ? "[X]" : "[ ]"; - } + public String getIcon() {return isDone ? "[X]" : "[ ]";} - public String getDescription() { - return description; - } + public String getDescription() {return description;} } class Display { From 1127f7c4017ec3c045b7e5b8cbcae8e8d6b49f16 Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Wed, 12 Feb 2025 02:12:48 +0800 Subject: [PATCH 09/25] Level 4. ToDos, Events, Deadlines --- src/main/java/Eddie.java | 244 +++++++++++++++++++++++++++------------ 1 file changed, 171 insertions(+), 73 deletions(-) diff --git a/src/main/java/Eddie.java b/src/main/java/Eddie.java index 4b148d641..ac25f11ba 100644 --- a/src/main/java/Eddie.java +++ b/src/main/java/Eddie.java @@ -3,7 +3,7 @@ public class Eddie { private boolean isRunning = true; private static final int MAX_TASKS = 100; - private Task[] tasks = new Task[MAX_TASKS]; // Store Task objects + private Task[] tasks = new Task[MAX_TASKS]; private int taskCount = 0; public static void main(String[] args) { @@ -26,9 +26,10 @@ public void run() { private void processUserInput(String input) { String[] parts = input.split(" ", 2); - String command = parts[0]; + String command = parts[0].toLowerCase(); + String arguments = (parts.length > 1) ? parts[1] : ""; - switch (command.toLowerCase()) { + switch (command) { case "bye": isRunning = false; Display.showEndPage(); @@ -37,134 +38,231 @@ private void processUserInput(String input) { Display.showTaskList(tasks, taskCount); break; case "mark": - if (parts.length > 1) { - markTask(parts[1]); - } else { - Display.showError("Please provide a task number to mark."); - } + markTask(arguments); break; case "unmark": - if (parts.length > 1) { - unmarkTask(parts[1]); - } else { - Display.showError("Please provide a task number to unmark."); - } + unmarkTask(arguments); break; - default: - addTask(input); + case "todo": + case "deadline": + case "event": + addTask(command, arguments); break; + default: + Display.showError("Invalid command. Use: todo, deadline, event, list, mark {num}, or unmark {num}."); } Display.printLine(); } - private void addTask(String taskName) { - if (taskCount < MAX_TASKS) { - tasks[taskCount] = new Task(taskName); - taskCount++; - Display.showTaskAdded(taskName); - } else { - Display.showError("You have reached the maximum number of tasks"); + private void addTask(String taskType, String details) { + if (taskCount >= MAX_TASKS) { + Display.showError("You have reached the maximum number of tasks."); + return; + } + + Task newTask = null; + + switch (taskType) { + case "todo": + if (!details.isEmpty()) newTask = new Todo(details); + else Display.showError("Invalid format. Use: todo {task description}"); + break; + case "deadline": + String[] deadlineParts = details.split(" /by ", 2); + if (deadlineParts.length > 1) newTask = new Deadline(deadlineParts[0], deadlineParts[1]); + else Display.showError("Invalid format. Use: deadline {task} /by {date}"); + break; + case "event": + String[] eventParts = details.split(" /from ", 2); + if (eventParts.length > 1) { + String[] timeParts = eventParts[1].split(" /to ", 2); + if (timeParts.length > 1) newTask = new Event(eventParts[0], timeParts[0], timeParts[1]); + else Display.showError("Invalid format. Use: event {task} /from {start} /to {end}"); + } else Display.showError("Invalid format. Use: event {task} /from {start} /to {end}"); + break; + } + + if (newTask != null) { + tasks[taskCount++] = newTask; + Display.showTaskAdded(newTask, taskCount); } } private void markTask(String indexStr) { - int index = Integer.parseInt(indexStr) - 1; - if (index >= 0 && index < taskCount) { - tasks[index].markDone(); - Display.showTaskMarked(tasks[index]); - } else { - Display.showError("Invalid task number."); + try { + int index = Integer.parseInt(indexStr) - 1; + if (index >= 0 && index < taskCount) { + tasks[index].markDone(); + Display.showTaskMarked(tasks[index]); + } else Display.showError("Invalid task number."); + } catch (NumberFormatException e) { + Display.showError("Please provide a valid task number."); } - } private void unmarkTask(String indexStr) { - int index = Integer.parseInt(indexStr) - 1; - if (index >= 0 && index < taskCount) { - tasks[index].markNotDone(); - Display.showTaskUnmarked(tasks[index]); - } else { - Display.showError("Invalid task number."); + try { + int index = Integer.parseInt(indexStr) - 1; + if (index >= 0 && index < taskCount) { + tasks[index].markNotDone(); + Display.showTaskUnmarked(tasks[index]); + } else Display.showError("Invalid task number."); + } catch (NumberFormatException e) { + Display.showError("Please provide a valid task number."); } } } - class Task { - private String description; - private boolean isDone; + protected String description; + protected boolean isDone; public Task(String description) { this.description = description; this.isDone = false; } - public void markDone() {this.isDone = true;} + public void markDone() { + this.isDone = true; + } + + public void markNotDone() { + this.isDone = false; + } + + public String getIcon() { + return isDone ? "[X]" : "[ ]"; + } + + public String getDescription() { + return description; + } + + public String getTaskType() { + return "[ ]"; + } + + @Override + public String toString() { + return getTaskType() + getIcon() + " " + getDescription(); + } +} + +class Todo extends Task { + public Todo(String description) { + super(description); + } + + @Override + public String getTaskType() { + return "[T]"; + } +} + +class Deadline extends Task { + private String by; + + public Deadline(String description, String by) { + super(description); + this.by = by; + } + + @Override + public String getTaskType() { + return "[D]"; + } + + @Override + public String toString() { + return super.toString() + " (by: " + by + ")"; + } +} + +class Event extends Task { + private String from, to; - public void markNotDone() {this.isDone = false;} + public Event(String description, String from, String to) { + super(description); + this.from = from; + this.to = to; + } - public String getIcon() {return isDone ? "[X]" : "[ ]";} + @Override + public String getTaskType() { + return "[E]"; + } - public String getDescription() {return description;} + @Override + public String toString() { + return super.toString() + " (from: " + from + " to: " + to + ")"; + } } class Display { + private static final String LOGO = + " _____ ____ ____ ___ _____ \n" + + " | ____|| _ \\| _ \\|_ _|| ____| \n" + + " | _| | | | | | | || | | _| \n" + + " | |___ | |_| | |_| || | | |___ \n" + + " |_____||____/|____/|___||_____| \n"; + public static void showStartPage() { - String logo = - " _____ ____ ____ ___ _____ \n" - + " | ____|| _ \\| _ \\|_ _|| ____| \n" - + " | _| | | | | | | || | | _| \n" - + " | |___ | |_| | |_| || | | |___ \n" - + " |_____||____/|____/|___||_____| \n"; - - String startScreen = "Eddie:\n" - + "Hello! I'm Eddie, your friendly assistant.\n" - + "Type anything to add it as a task!\n" - + "Use 'list' to view tasks, 'mark {num}' to mark done, and 'unmark {num}' to undo.\n"; - - System.out.println(logo); + System.out.println(LOGO); printLine(); - System.out.println(startScreen); + System.out.println("Eddie: Welcome to your personal task manager!"); + System.out.println("I can help you manage different types of tasks.\n"); + + System.out.println("HOW TO USE EDDIE by typing"); + System.out.println("Adding a Task!"); + System.out.println("To add a ToDo: `todo {Name of Task}`"); + System.out.println("To add a Deadline: `deadline {Name of Deadline} /by {Date or Day}`"); + System.out.println("To add an Event: `event {Name of Event} /from {Day/Date} {Time} /to {Time}`\n"); + + System.out.println("To view your Task List!"); + System.out.println("See all tasks: `list`\n"); + + System.out.println("Managing Tasks!"); + System.out.println("To mark as done: `mark 2`"); + System.out.println("To unmark: `unmark 2`\n"); + + System.out.println("Exiting the Program!"); + System.out.println("To exit: `bye`\n"); printLine(); } public static void showEndPage() { + System.out.println(LOGO); + printLine(); System.out.println("Eddie:\nGoodbye! Hope to see you again soon!"); + printLine(); } public static void printLine() { System.out.println("____________________________________________________________"); } - public static void showTaskAdded(String taskName) { - System.out.println("Eddie:\nTask added: " + taskName); + public static void showTaskAdded(Task task, int count) { + System.out.println("Eddie:\nGot it. I've added this task:\n " + task); + System.out.println("Now you have " + count + " tasks in the list."); } - public static void showTaskList(Task[] tasks, int taskCount) { + public static void showTaskList(Task[] tasks, int count) { System.out.println("Eddie:\nHere are the tasks in your list:"); - - if (taskCount == 0) { - System.out.println("No tasks added yet."); - } else { - for (int i = 0; i < taskCount; i++) { - System.out.println((i + 1) + ". " + tasks[i].getIcon() + " " + tasks[i].getDescription()); - } - } + for (int i = 0; i < count; i++) System.out.println((i + 1) + ". " + tasks[i]); } public static void showTaskMarked(Task task) { - System.out.println("Eddie:\nYay! I've marked this task as done:"); - System.out.println(" " + task.getIcon() + " " + task.getDescription()); + System.out.println("Eddie:\nYay! Marked as done:\n " + task); } public static void showTaskUnmarked(Task task) { - System.out.println("Eddie:\nOh no!, I've marked this task as not done yet:"); - System.out.println(" " + task.getIcon() + " " + task.getDescription()); + System.out.println("Eddie:\nMarked as not done:\n " + task); } - public static void showError(String message) { - System.out.println("Eddie:\nError: " + message); + public static void showError(String msg) { + System.out.println("Eddie:\nError: " + msg); } } + From c907615554826d4f8b25af414f40d35f4b2709d1 Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Thu, 13 Feb 2025 00:27:00 +0800 Subject: [PATCH 10/25] A-CodeQuality --- src/main/java/Eddie.java | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/src/main/java/Eddie.java b/src/main/java/Eddie.java index ac25f11ba..fce3d6790 100644 --- a/src/main/java/Eddie.java +++ b/src/main/java/Eddie.java @@ -44,7 +44,11 @@ private void processUserInput(String input) { unmarkTask(arguments); break; case "todo": + addTask(command, arguments); + break; case "deadline": + addTask(command, arguments); + break; case "event": addTask(command, arguments); break; @@ -64,21 +68,32 @@ private void addTask(String taskType, String details) { switch (taskType) { case "todo": - if (!details.isEmpty()) newTask = new Todo(details); - else Display.showError("Invalid format. Use: todo {task description}"); + if (!details.isEmpty()) { + newTask = new Todo(details); + } else { + Display.showError("Invalid format. Use: todo {task description}"); + } break; case "deadline": String[] deadlineParts = details.split(" /by ", 2); - if (deadlineParts.length > 1) newTask = new Deadline(deadlineParts[0], deadlineParts[1]); - else Display.showError("Invalid format. Use: deadline {task} /by {date}"); + if (deadlineParts.length > 1) { + newTask = new Deadline(deadlineParts[0], deadlineParts[1]); + } else { + Display.showError("Invalid format. Use: deadline {task} /by {date}"); + } break; case "event": String[] eventParts = details.split(" /from ", 2); if (eventParts.length > 1) { String[] timeParts = eventParts[1].split(" /to ", 2); - if (timeParts.length > 1) newTask = new Event(eventParts[0], timeParts[0], timeParts[1]); - else Display.showError("Invalid format. Use: event {task} /from {start} /to {end}"); - } else Display.showError("Invalid format. Use: event {task} /from {start} /to {end}"); + if (timeParts.length > 1) { + newTask = new Event(eventParts[0], timeParts[0], timeParts[1]); + } else { + Display.showError("Invalid format. Use: event {task} /from {start} /to {end}"); + } + } else { + Display.showError("Invalid format. Use: event {task} /from {start} /to {end}"); + } break; } @@ -94,7 +109,9 @@ private void markTask(String indexStr) { if (index >= 0 && index < taskCount) { tasks[index].markDone(); Display.showTaskMarked(tasks[index]); - } else Display.showError("Invalid task number."); + } else { + Display.showError("Invalid task number."); + } } catch (NumberFormatException e) { Display.showError("Please provide a valid task number."); } @@ -106,7 +123,9 @@ private void unmarkTask(String indexStr) { if (index >= 0 && index < taskCount) { tasks[index].markNotDone(); Display.showTaskUnmarked(tasks[index]); - } else Display.showError("Invalid task number."); + } else { + Display.showError("Invalid task number."); + } } catch (NumberFormatException e) { Display.showError("Please provide a valid task number."); } From 41658879f2e34f42981460f1bf91b04ad80a8e98 Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Thu, 13 Feb 2025 01:17:03 +0800 Subject: [PATCH 11/25] Level 5. Handle Errors --- src/main/java/Eddie.java | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/main/java/Eddie.java b/src/main/java/Eddie.java index fce3d6790..e78775bed 100644 --- a/src/main/java/Eddie.java +++ b/src/main/java/Eddie.java @@ -53,14 +53,14 @@ private void processUserInput(String input) { addTask(command, arguments); break; default: - Display.showError("Invalid command. Use: todo, deadline, event, list, mark {num}, or unmark {num}."); + Display.showError(ErrorMessages.INVALID_COMMAND); } Display.printLine(); } private void addTask(String taskType, String details) { if (taskCount >= MAX_TASKS) { - Display.showError("You have reached the maximum number of tasks."); + Display.showError(ErrorMessages.TASK_LIST_FULL); return; } @@ -71,7 +71,7 @@ private void addTask(String taskType, String details) { if (!details.isEmpty()) { newTask = new Todo(details); } else { - Display.showError("Invalid format. Use: todo {task description}"); + Display.showError(ErrorMessages.INVALID_TODO); } break; case "deadline": @@ -79,7 +79,7 @@ private void addTask(String taskType, String details) { if (deadlineParts.length > 1) { newTask = new Deadline(deadlineParts[0], deadlineParts[1]); } else { - Display.showError("Invalid format. Use: deadline {task} /by {date}"); + Display.showError(ErrorMessages.INVALID_DEADLINE); } break; case "event": @@ -89,10 +89,10 @@ private void addTask(String taskType, String details) { if (timeParts.length > 1) { newTask = new Event(eventParts[0], timeParts[0], timeParts[1]); } else { - Display.showError("Invalid format. Use: event {task} /from {start} /to {end}"); + Display.showError(ErrorMessages.INVALID_EVENT); } } else { - Display.showError("Invalid format. Use: event {task} /from {start} /to {end}"); + Display.showError(ErrorMessages.INVALID_EVENT); } break; } @@ -110,10 +110,10 @@ private void markTask(String indexStr) { tasks[index].markDone(); Display.showTaskMarked(tasks[index]); } else { - Display.showError("Invalid task number."); + Display.showError(ErrorMessages.INVALID_TASK_NUMBER); } } catch (NumberFormatException e) { - Display.showError("Please provide a valid task number."); + Display.showError(ErrorMessages.INVALID_TASK_NUMBER); } } @@ -124,10 +124,10 @@ private void unmarkTask(String indexStr) { tasks[index].markNotDone(); Display.showTaskUnmarked(tasks[index]); } else { - Display.showError("Invalid task number."); + Display.showError(ErrorMessages.INVALID_TASK_NUMBER); } } catch (NumberFormatException e) { - Display.showError("Please provide a valid task number."); + Display.showError(ErrorMessages.INVALID_TASK_NUMBER); } } } @@ -217,6 +217,20 @@ public String toString() { } } +class ErrorMessages { + public static final String INVALID_COMMAND = "Oh no! Invalid command. Use: " + + "todo, deadline, event, list, mark {num}, or unmark {num}."; + public static final String TASK_LIST_FULL = "Oh no! You have reached the " + + "maximum number of tasks."; + public static final String INVALID_TODO = "Oh no! Invalid description. Use:" + + " todo {task description}"; + public static final String INVALID_DEADLINE = "Oh no! Invalid description. " + + "Use: deadline {task} /by {date}"; + public static final String INVALID_EVENT = "Oh no! Invalid description. Use:" + + " event {task} /from {start} /to {end}"; + public static final String INVALID_TASK_NUMBER = "Oh no! Invalid task number."; +} + class Display { private static final String LOGO = " _____ ____ ____ ___ _____ \n" From f8fa3b79bd130eb6c4c703dfde2cafcdfba478b4 Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Thu, 13 Feb 2025 16:03:13 +0800 Subject: [PATCH 12/25] Level 5. Handle Errors Refactor some codes before making Exception classes --- src/main/java/Eddie.java | 61 ++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 37 deletions(-) diff --git a/src/main/java/Eddie.java b/src/main/java/Eddie.java index e78775bed..1d43b725f 100644 --- a/src/main/java/Eddie.java +++ b/src/main/java/Eddie.java @@ -38,10 +38,10 @@ private void processUserInput(String input) { Display.showTaskList(tasks, taskCount); break; case "mark": - markTask(arguments); + taskStatus(arguments, true); break; case "unmark": - unmarkTask(arguments); + taskStatus(arguments, false); break; case "todo": addTask(command, arguments); @@ -103,12 +103,17 @@ private void addTask(String taskType, String details) { } } - private void markTask(String indexStr) { + private void taskStatus(String taskIndex, boolean markDone) { try { - int index = Integer.parseInt(indexStr) - 1; + int index = Integer.parseInt(taskIndex) - 1; if (index >= 0 && index < taskCount) { - tasks[index].markDone(); - Display.showTaskMarked(tasks[index]); + if(markDone){ + tasks[index].markDone(); + Display.showTaskMarked(tasks[index]); + } else { + tasks[index].markNotDone(); + Display.showTaskUnmarked(tasks[index]); + } } else { Display.showError(ErrorMessages.INVALID_TASK_NUMBER); } @@ -117,19 +122,13 @@ private void markTask(String indexStr) { } } - private void unmarkTask(String indexStr) { - try { - int index = Integer.parseInt(indexStr) - 1; - if (index >= 0 && index < taskCount) { - tasks[index].markNotDone(); - Display.showTaskUnmarked(tasks[index]); - } else { - Display.showError(ErrorMessages.INVALID_TASK_NUMBER); - } - } catch (NumberFormatException e) { - Display.showError(ErrorMessages.INVALID_TASK_NUMBER); - } - } +// private void markTask(String indexStr) { +// taskStatus(indexStr,true); +// } +// +// private void unmarkTask(String indexStr) { +// taskStatus(indexStr,false); +// } } class Task { @@ -141,30 +140,18 @@ public Task(String description) { this.isDone = false; } - public void markDone() { - this.isDone = true; - } + public void markDone() {this.isDone = true;} - public void markNotDone() { - this.isDone = false; - } + public void markNotDone() {this.isDone = false;} - public String getIcon() { - return isDone ? "[X]" : "[ ]"; - } + public String getIcon() {return isDone ? "[X]" : "[ ]";} - public String getDescription() { - return description; - } + public String getDescription() {return description;} - public String getTaskType() { - return "[ ]"; - } + public String getTaskType() {return "[ ]";} @Override - public String toString() { - return getTaskType() + getIcon() + " " + getDescription(); - } + public String toString() {return getTaskType() + getIcon() + " " + getDescription();} } class Todo extends Task { From 0053c3fd88cc94d1a69a4b129697d55b9f32df5d Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Fri, 14 Feb 2025 03:07:02 +0800 Subject: [PATCH 13/25] Refactored Add task to processUserInput switch block. created helper functions for todo, deadline and event --- src/main/java/Eddie.java | 98 ++++++++++++++++------------------------ 1 file changed, 39 insertions(+), 59 deletions(-) diff --git a/src/main/java/Eddie.java b/src/main/java/Eddie.java index 1d43b725f..7466ba5e7 100644 --- a/src/main/java/Eddie.java +++ b/src/main/java/Eddie.java @@ -44,13 +44,13 @@ private void processUserInput(String input) { taskStatus(arguments, false); break; case "todo": - addTask(command, arguments); + addToDo(arguments); break; case "deadline": - addTask(command, arguments); + addDeadLine(arguments); break; case "event": - addTask(command, arguments); + addEvent(arguments); break; default: Display.showError(ErrorMessages.INVALID_COMMAND); @@ -58,49 +58,37 @@ private void processUserInput(String input) { Display.printLine(); } - private void addTask(String taskType, String details) { - if (taskCount >= MAX_TASKS) { - Display.showError(ErrorMessages.TASK_LIST_FULL); + private void addToDo(String details) { + if (details.isEmpty()) { + Display.showError(ErrorMessages.INVALID_TODO); return; } + Task newTask = new Todo(details); + tasks[taskCount++] = newTask; + Display.showTaskAdded(newTask, taskCount); + } - Task newTask = null; - - switch (taskType) { - case "todo": - if (!details.isEmpty()) { - newTask = new Todo(details); - } else { - Display.showError(ErrorMessages.INVALID_TODO); - } - break; - case "deadline": - String[] deadlineParts = details.split(" /by ", 2); - if (deadlineParts.length > 1) { - newTask = new Deadline(deadlineParts[0], deadlineParts[1]); - } else { - Display.showError(ErrorMessages.INVALID_DEADLINE); - } - break; - case "event": - String[] eventParts = details.split(" /from ", 2); - if (eventParts.length > 1) { - String[] timeParts = eventParts[1].split(" /to ", 2); - if (timeParts.length > 1) { - newTask = new Event(eventParts[0], timeParts[0], timeParts[1]); - } else { - Display.showError(ErrorMessages.INVALID_EVENT); - } - } else { - Display.showError(ErrorMessages.INVALID_EVENT); - } - break; + private void addDeadLine(String details) { + String[] deadlineParts = details.split(" /by ", 2); + if (deadlineParts.length < 2) { + Display.showError(ErrorMessages.INVALID_DEADLINE); + return; } + Task newTask = new Deadline(deadlineParts[0], deadlineParts[1]); + tasks[taskCount++] = newTask; + Display.showTaskAdded(newTask, taskCount); + } - if (newTask != null) { - tasks[taskCount++] = newTask; - Display.showTaskAdded(newTask, taskCount); + private void addEvent(String details) { + String[] eventParts = details.split(" /from ", 2); + if (eventParts.length < 2 || !eventParts[1].contains(" /to ")) { + Display.showError(ErrorMessages.INVALID_EVENT); + return; } + String[] timeParts = eventParts[1].split(" /to ", 2); + Task newTask = new Event(eventParts[0], timeParts[0], timeParts[1]); + tasks[taskCount++] = newTask; + Display.showTaskAdded(newTask, taskCount); } private void taskStatus(String taskIndex, boolean markDone) { @@ -109,10 +97,10 @@ private void taskStatus(String taskIndex, boolean markDone) { if (index >= 0 && index < taskCount) { if(markDone){ tasks[index].markDone(); - Display.showTaskMarked(tasks[index]); + Display.showMarkedStatus(tasks[index], true); } else { tasks[index].markNotDone(); - Display.showTaskUnmarked(tasks[index]); + Display.showMarkedStatus(tasks[index], false); } } else { Display.showError(ErrorMessages.INVALID_TASK_NUMBER); @@ -121,14 +109,6 @@ private void taskStatus(String taskIndex, boolean markDone) { Display.showError(ErrorMessages.INVALID_TASK_NUMBER); } } - -// private void markTask(String indexStr) { -// taskStatus(indexStr,true); -// } -// -// private void unmarkTask(String indexStr) { -// taskStatus(indexStr,false); -// } } class Task { @@ -209,11 +189,11 @@ class ErrorMessages { "todo, deadline, event, list, mark {num}, or unmark {num}."; public static final String TASK_LIST_FULL = "Oh no! You have reached the " + "maximum number of tasks."; - public static final String INVALID_TODO = "Oh no! Invalid description. Use:" + + public static final String INVALID_TODO = "Oh no! empty description. Use:" + " todo {task description}"; - public static final String INVALID_DEADLINE = "Oh no! Invalid description. " + + public static final String INVALID_DEADLINE = "Oh no! empty description. " + "Use: deadline {task} /by {date}"; - public static final String INVALID_EVENT = "Oh no! Invalid description. Use:" + + public static final String INVALID_EVENT = "Oh no! empty description. Use:" + " event {task} /from {start} /to {end}"; public static final String INVALID_TASK_NUMBER = "Oh no! Invalid task number."; } @@ -271,12 +251,12 @@ public static void showTaskList(Task[] tasks, int count) { for (int i = 0; i < count; i++) System.out.println((i + 1) + ". " + tasks[i]); } - public static void showTaskMarked(Task task) { - System.out.println("Eddie:\nYay! Marked as done:\n " + task); - } - - public static void showTaskUnmarked(Task task) { - System.out.println("Eddie:\nMarked as not done:\n " + task); + public static void showMarkedStatus(Task task, boolean done) { + if(done) { + System.out.println("Eddie:\nYay! Marked as done:\n " + task); + } else { + System.out.println("Eddie:\nOh no! Marked as not done:\n " + task); + } } public static void showError(String msg) { From 76e13a6d177ee457e4322e27746c012f43ceacbf Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Sat, 15 Feb 2025 00:51:57 +0800 Subject: [PATCH 14/25] Level 5. Handle Errors Created Error Exception class to handle possible errors during runtime --- src/main/java/Eddie.java | 297 ++++++++++++++++++++++++++++++--------- 1 file changed, 231 insertions(+), 66 deletions(-) diff --git a/src/main/java/Eddie.java b/src/main/java/Eddie.java index 7466ba5e7..9c10fe48a 100644 --- a/src/main/java/Eddie.java +++ b/src/main/java/Eddie.java @@ -1,16 +1,26 @@ import java.util.Scanner; +/** + * The Eddie class represents a simple task management system chatbot. + * It allows users to add, list, mark, and unmark tasks through a CLI. + */ public class Eddie { private boolean isRunning = true; private static final int MAX_TASKS = 100; - private Task[] tasks = new Task[MAX_TASKS]; + private final Task[] tasks = new Task[MAX_TASKS]; private int taskCount = 0; + /** + * Initializes Eddie and starts the run loop. + */ public static void main(String[] args) { Eddie eddie = new Eddie(); eddie.run(); } + /** + * Starts the application and continuously processes user input. + */ public void run() { Display.showStartPage(); Scanner scanner = new Scanner(System.in); @@ -24,116 +34,154 @@ public void run() { scanner.close(); } + /** + * Processes user input and executes the user command through CLI. + * @param input The user's command input. + */ private void processUserInput(String input) { String[] parts = input.split(" ", 2); String command = parts[0].toLowerCase(); String arguments = (parts.length > 1) ? parts[1] : ""; - - switch (command) { - case "bye": - isRunning = false; - Display.showEndPage(); - break; - case "list": - Display.showTaskList(tasks, taskCount); - break; - case "mark": - taskStatus(arguments, true); - break; - case "unmark": - taskStatus(arguments, false); - break; - case "todo": - addToDo(arguments); - break; - case "deadline": - addDeadLine(arguments); - break; - case "event": - addEvent(arguments); - break; - default: - Display.showError(ErrorMessages.INVALID_COMMAND); + try { + switch (command) { + case "bye": + isRunning = false; + Display.showEndPage(); + break; + case "list": + Display.showTaskList(tasks, taskCount); + break; + case "mark": + taskStatus(arguments, true); + break; + case "unmark": + taskStatus(arguments, false); + break; + case "todo": + addToDo(arguments); + break; + case "deadline": + addDeadLine(arguments); + break; + case "event": + addEvent(arguments); + break; + default: + throw new EddieException(ErrorMessages.INVALID_COMMAND); + } + } catch (EddieException e) { + Display.showError(e.getMessage()); } Display.printLine(); } - private void addToDo(String details) { - if (details.isEmpty()) { - Display.showError(ErrorMessages.INVALID_TODO); - return; - } + /** + * Adds a ToDo task to the task list. + * @param details The task description. + * @throws EddieException If the details are empty or invalid. + */ + private void addToDo(String details) throws EddieException { + EddieException.checkTodo(details); Task newTask = new Todo(details); tasks[taskCount++] = newTask; Display.showTaskAdded(newTask, taskCount); } - private void addDeadLine(String details) { + /** + * Adds a Deadline task to the task list. + * @param details The task description and deadline. + * @throws EddieException If the format is incorrect. + */ + private void addDeadLine(String details) throws EddieException { + EddieException.checkDeadline(details); String[] deadlineParts = details.split(" /by ", 2); - if (deadlineParts.length < 2) { - Display.showError(ErrorMessages.INVALID_DEADLINE); - return; - } Task newTask = new Deadline(deadlineParts[0], deadlineParts[1]); tasks[taskCount++] = newTask; Display.showTaskAdded(newTask, taskCount); } - private void addEvent(String details) { + /** + * Adds an Event task to the task list. + * @param details The task description, start, and end times. + * @throws EddieException If the format is incorrect. + */ + private void addEvent(String details) throws EddieException { + EddieException.checkEvent(details); String[] eventParts = details.split(" /from ", 2); - if (eventParts.length < 2 || !eventParts[1].contains(" /to ")) { - Display.showError(ErrorMessages.INVALID_EVENT); - return; - } String[] timeParts = eventParts[1].split(" /to ", 2); Task newTask = new Event(eventParts[0], timeParts[0], timeParts[1]); tasks[taskCount++] = newTask; Display.showTaskAdded(newTask, taskCount); } - private void taskStatus(String taskIndex, boolean markDone) { - try { - int index = Integer.parseInt(taskIndex) - 1; - if (index >= 0 && index < taskCount) { - if(markDone){ - tasks[index].markDone(); - Display.showMarkedStatus(tasks[index], true); - } else { - tasks[index].markNotDone(); - Display.showMarkedStatus(tasks[index], false); - } + /** + * Marks or unmarks a task as completed. + * @param taskIndex The task number as a string. + * @param markDone True to mark as done, false to unmark. + * @throws EddieException If the task number is invalid. + */ + private void taskStatus(String taskIndex, boolean markDone) throws EddieException { + int index = EddieException.checkTaskStatus(taskIndex, taskCount); + if (markDone) { + tasks[index].markDone(); } else { - Display.showError(ErrorMessages.INVALID_TASK_NUMBER); + tasks[index].markNotDone(); } - } catch (NumberFormatException e) { - Display.showError(ErrorMessages.INVALID_TASK_NUMBER); - } + Display.showMarkedStatus(tasks[index], markDone); } } +/** + * Represents a generic task that can be marked as done or not done. + */ class Task { protected String description; protected boolean isDone; + /** + * Constructs a new Task with a given description. + * @param description The description of the task. + */ public Task(String description) { this.description = description; this.isDone = false; } + /** + * Marks the task as done. + */ public void markDone() {this.isDone = true;} + /** + * Marks the task as not done. + */ public void markNotDone() {this.isDone = false;} + /** + * Returns the task's completion status icon. + * @return "[X]" if done, "[ ]" otherwise. + */ public String getIcon() {return isDone ? "[X]" : "[ ]";} + /** + * Returns the task description. + * @return The description of the task. + */ public String getDescription() {return description;} + /** + * Returns the task type icon. + * @return A default task type icon. + */ public String getTaskType() {return "[ ]";} @Override public String toString() {return getTaskType() + getIcon() + " " + getDescription();} } +/** + * Todo task class to create todo tasks. + */ class Todo extends Task { public Todo(String description) { super(description); @@ -145,9 +193,17 @@ public String getTaskType() { } } +/** + * deadline task class to create deadline tasks. + */ class Deadline extends Task { - private String by; + private final String by; + /** + * Constructs a new Deadline task. + * @param description The task description. + * @param by The deadline for the task. + */ public Deadline(String description, String by) { super(description); this.by = by; @@ -164,9 +220,19 @@ public String toString() { } } +/** + * event task class to create events with a start and end time. + */ class Event extends Task { - private String from, to; - + private final String from; + private final String to; + + /** + * Constructs a new Event task. + * @param description The event description. + * @param from The start time of the event. + * @param to The end time of the event. + */ public Event(String description, String from, String to) { super(description); this.from = from; @@ -184,11 +250,80 @@ public String toString() { } } + +/** + * Eddie exception class for handling task-related errors in the Eddie task manager. + */ +class EddieException extends Exception { + /** + * Constructs an EddieException with a specific error message. + * @param message The error message. + */ + public EddieException(String message) { + super(message); + } + + /** + * Validates a ToDo task description. + * @param details The task description. + * @throws EddieException If the description is empty. + */ + public static void checkTodo(String details) throws EddieException { + if (details.isEmpty()) { + throw new EddieException(ErrorMessages.INVALID_TODO); + } + } + + /** + * Validates a Deadline task description. + * @param details The task description including the deadline. + * @throws EddieException If the format is incorrect. + */ + public static void checkDeadline(String details) throws EddieException { + String[] deadlineParts = details.split(" /by ", 2); + if (deadlineParts.length < 2) { + throw new EddieException(ErrorMessages.INVALID_DEADLINE); + } + } + + /** + * Validates an Event task description. + * @param details The task description including the event time. + * @throws EddieException If the format is incorrect. + */ + public static void checkEvent(String details) throws EddieException { + String[] eventParts = details.split(" /from ", 2); + if (eventParts.length < 2 || !eventParts[1].contains(" /to ")) { + throw new EddieException(ErrorMessages.INVALID_EVENT); + } + } + + /** + * Validates and parses a task index input. + * @param taskIndex The task index as a string. + * @param taskCount The total number of tasks. + * @return The parsed and validated task index. + * @throws EddieException If the task number is invalid. + */ + public static int checkTaskStatus(String taskIndex, int taskCount) throws EddieException { + try { + int index = Integer.parseInt(taskIndex) - 1; + if (index < 0 || index >= taskCount) { + throw new EddieException(ErrorMessages.INVALID_TASK_NUMBER); + } + return index; + } catch (NumberFormatException e) { + throw new EddieException(ErrorMessages.INVALID_TASK_NUMBER); + } + } +} + +/** + * Contains predefined error messages for the Eddie task manager. + */ class ErrorMessages { public static final String INVALID_COMMAND = "Oh no! Invalid command. Use: " + "todo, deadline, event, list, mark {num}, or unmark {num}."; - public static final String TASK_LIST_FULL = "Oh no! You have reached the " + - "maximum number of tasks."; public static final String INVALID_TODO = "Oh no! empty description. Use:" + " todo {task description}"; public static final String INVALID_DEADLINE = "Oh no! empty description. " + @@ -198,6 +333,11 @@ class ErrorMessages { public static final String INVALID_TASK_NUMBER = "Oh no! Invalid task number."; } +/** + * The Display class to print user interface messages + * for the Eddie task manager, including startup, shutdown, task actions, + * and error messages. + */ class Display { private static final String LOGO = " _____ ____ ____ ___ _____ \n" @@ -206,6 +346,9 @@ class Display { + " | |___ | |_| | |_| || | | |___ \n" + " |_____||____/|____/|___||_____| \n"; + /** + * Displays the startup message and user guide. + */ public static void showStartPage() { System.out.println(LOGO); printLine(); @@ -230,6 +373,9 @@ public static void showStartPage() { printLine(); } + /** + * Displays the shutdown message. + */ public static void showEndPage() { System.out.println(LOGO); printLine(); @@ -237,32 +383,51 @@ public static void showEndPage() { printLine(); } + /** + * Prints a horizontal line as a separator. + */ public static void printLine() { System.out.println("____________________________________________________________"); } + /** + * Displays a message confirming a task has been added. + * @param task The task that was added. + * @param count The total number of tasks. + */ public static void showTaskAdded(Task task, int count) { System.out.println("Eddie:\nGot it. I've added this task:\n " + task); System.out.println("Now you have " + count + " tasks in the list."); } + /** + * Displays the list of all tasks. + * @param tasks Array of tasks. + * @param count Total number of tasks. + */ public static void showTaskList(Task[] tasks, int count) { System.out.println("Eddie:\nHere are the tasks in your list:"); for (int i = 0; i < count; i++) System.out.println((i + 1) + ". " + tasks[i]); } + /** + * Displays a message when a task is marked or unmarked. + * @param task The task being updated. + * @param done True if marking as done, false if unmarking. + */ public static void showMarkedStatus(Task task, boolean done) { if(done) { - System.out.println("Eddie:\nYay! Marked as done:\n " + task); + System.out.println("Eddie:\nYay! Marked as done:\n " + task + "\nHave a Beer!!"); } else { System.out.println("Eddie:\nOh no! Marked as not done:\n " + task); } } + /** + * Displays an error message. + * @param msg The error message to display. + */ public static void showError(String msg) { System.out.println("Eddie:\nError: " + msg); } } - - - From a1fcc374366bbcab366c584a44571c5195520e28 Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Sun, 23 Feb 2025 14:00:15 +0800 Subject: [PATCH 15/25] Level 6. Delete --- src/main/java/Eddie.java | 116 ++++++++++++++++++++++++++++----------- 1 file changed, 83 insertions(+), 33 deletions(-) diff --git a/src/main/java/Eddie.java b/src/main/java/Eddie.java index 9c10fe48a..866389790 100644 --- a/src/main/java/Eddie.java +++ b/src/main/java/Eddie.java @@ -1,4 +1,5 @@ import java.util.Scanner; +import java.util.ArrayList; /** * The Eddie class represents a simple task management system chatbot. @@ -6,9 +7,7 @@ */ public class Eddie { private boolean isRunning = true; - private static final int MAX_TASKS = 100; - private final Task[] tasks = new Task[MAX_TASKS]; - private int taskCount = 0; + ArrayList tasksList = new ArrayList<>(); /** * Initializes Eddie and starts the run loop. @@ -36,6 +35,7 @@ public void run() { /** * Processes user input and executes the user command through CLI. + * * @param input The user's command input. */ private void processUserInput(String input) { @@ -49,7 +49,7 @@ private void processUserInput(String input) { Display.showEndPage(); break; case "list": - Display.showTaskList(tasks, taskCount); + Display.showTaskList(tasksList); break; case "mark": taskStatus(arguments, true); @@ -66,6 +66,9 @@ private void processUserInput(String input) { case "event": addEvent(arguments); break; + case "delete": + deleteTask(arguments); + break; default: throw new EddieException(ErrorMessages.INVALID_COMMAND); } @@ -77,18 +80,21 @@ private void processUserInput(String input) { /** * Adds a ToDo task to the task list. + * * @param details The task description. * @throws EddieException If the details are empty or invalid. */ private void addToDo(String details) throws EddieException { EddieException.checkTodo(details); Task newTask = new Todo(details); - tasks[taskCount++] = newTask; - Display.showTaskAdded(newTask, taskCount); + tasksList.add(newTask); + //tasks[taskCount++] = newTask; + Display.showTaskAdded(newTask, tasksList.size()); } /** * Adds a Deadline task to the task list. + * * @param details The task description and deadline. * @throws EddieException If the format is incorrect. */ @@ -96,12 +102,13 @@ private void addDeadLine(String details) throws EddieException { EddieException.checkDeadline(details); String[] deadlineParts = details.split(" /by ", 2); Task newTask = new Deadline(deadlineParts[0], deadlineParts[1]); - tasks[taskCount++] = newTask; - Display.showTaskAdded(newTask, taskCount); + tasksList.add(newTask); + Display.showTaskAdded(newTask, tasksList.size()); } /** * Adds an Event task to the task list. + * * @param details The task description, start, and end times. * @throws EddieException If the format is incorrect. */ @@ -110,24 +117,32 @@ private void addEvent(String details) throws EddieException { String[] eventParts = details.split(" /from ", 2); String[] timeParts = eventParts[1].split(" /to ", 2); Task newTask = new Event(eventParts[0], timeParts[0], timeParts[1]); - tasks[taskCount++] = newTask; - Display.showTaskAdded(newTask, taskCount); + tasksList.add(newTask); + Display.showTaskAdded(newTask, tasksList.size()); } /** * Marks or unmarks a task as completed. + * * @param taskIndex The task number as a string. - * @param markDone True to mark as done, false to unmark. + * @param markDone True to mark as done, false to unmark. * @throws EddieException If the task number is invalid. */ private void taskStatus(String taskIndex, boolean markDone) throws EddieException { - int index = EddieException.checkTaskStatus(taskIndex, taskCount); - if (markDone) { - tasks[index].markDone(); - } else { - tasks[index].markNotDone(); - } - Display.showMarkedStatus(tasks[index], markDone); + int index = EddieException.checkTaskStatus(taskIndex, tasksList.size()); + Task task = tasksList.get(index); + if (markDone) { + task.markDone(); + } else { + task.markNotDone(); + } + Display.showMarkedStatus(task, markDone); + } + + private void deleteTask(String taskIndex) throws EddieException { + int index = EddieException.checkTaskStatus(taskIndex, tasksList.size()); + Task removedTask = tasksList.remove(index); + Display.showTaskDeleted(removedTask, tasksList.size()); } } @@ -140,6 +155,7 @@ class Task { /** * Constructs a new Task with a given description. + * * @param description The description of the task. */ public Task(String description) { @@ -150,33 +166,48 @@ public Task(String description) { /** * Marks the task as done. */ - public void markDone() {this.isDone = true;} + public void markDone() { + this.isDone = true; + } /** * Marks the task as not done. */ - public void markNotDone() {this.isDone = false;} + public void markNotDone() { + this.isDone = false; + } /** * Returns the task's completion status icon. + * * @return "[X]" if done, "[ ]" otherwise. */ - public String getIcon() {return isDone ? "[X]" : "[ ]";} + public String getIcon() { + return isDone ? "[X]" : "[ ]"; + } /** * Returns the task description. + * * @return The description of the task. */ - public String getDescription() {return description;} + public String getDescription() { + return description; + } /** * Returns the task type icon. + * * @return A default task type icon. */ - public String getTaskType() {return "[ ]";} + public String getTaskType() { + return "[ ]"; + } @Override - public String toString() {return getTaskType() + getIcon() + " " + getDescription();} + public String toString() { + return getTaskType() + getIcon() + " " + getDescription(); + } } /** @@ -201,8 +232,9 @@ class Deadline extends Task { /** * Constructs a new Deadline task. + * * @param description The task description. - * @param by The deadline for the task. + * @param by The deadline for the task. */ public Deadline(String description, String by) { super(description); @@ -229,9 +261,10 @@ class Event extends Task { /** * Constructs a new Event task. + * * @param description The event description. - * @param from The start time of the event. - * @param to The end time of the event. + * @param from The start time of the event. + * @param to The end time of the event. */ public Event(String description, String from, String to) { super(description); @@ -257,6 +290,7 @@ public String toString() { class EddieException extends Exception { /** * Constructs an EddieException with a specific error message. + * * @param message The error message. */ public EddieException(String message) { @@ -265,6 +299,7 @@ public EddieException(String message) { /** * Validates a ToDo task description. + * * @param details The task description. * @throws EddieException If the description is empty. */ @@ -276,6 +311,7 @@ public static void checkTodo(String details) throws EddieException { /** * Validates a Deadline task description. + * * @param details The task description including the deadline. * @throws EddieException If the format is incorrect. */ @@ -288,6 +324,7 @@ public static void checkDeadline(String details) throws EddieException { /** * Validates an Event task description. + * * @param details The task description including the event time. * @throws EddieException If the format is incorrect. */ @@ -300,6 +337,7 @@ public static void checkEvent(String details) throws EddieException { /** * Validates and parses a task index input. + * * @param taskIndex The task index as a string. * @param taskCount The total number of tasks. * @return The parsed and validated task index. @@ -392,7 +430,8 @@ public static void printLine() { /** * Displays a message confirming a task has been added. - * @param task The task that was added. + * + * @param task The task that was added. * @param count The total number of tasks. */ public static void showTaskAdded(Task task, int count) { @@ -402,29 +441,40 @@ public static void showTaskAdded(Task task, int count) { /** * Displays the list of all tasks. - * @param tasks Array of tasks. - * @param count Total number of tasks. + * + * @param tasksList Array of tasks. */ - public static void showTaskList(Task[] tasks, int count) { + public static void showTaskList(ArrayList tasksList) { System.out.println("Eddie:\nHere are the tasks in your list:"); - for (int i = 0; i < count; i++) System.out.println((i + 1) + ". " + tasks[i]); + if (tasksList.isEmpty()) { + System.out.println("No tasks in your list."); + } + + for (int i = 0; i < tasksList.size(); i++) System.out.println((i + 1) + ". " + tasksList.get(i)); } /** * Displays a message when a task is marked or unmarked. + * * @param task The task being updated. * @param done True if marking as done, false if unmarking. */ public static void showMarkedStatus(Task task, boolean done) { - if(done) { + if (done) { System.out.println("Eddie:\nYay! Marked as done:\n " + task + "\nHave a Beer!!"); } else { System.out.println("Eddie:\nOh no! Marked as not done:\n " + task); } } + public static void showTaskDeleted(Task task, int count) { + System.out.println("Eddie:\nNoted. I've removed this task:\n " + task); + System.out.println("Now you have " + count + " tasks in the list."); + } + /** * Displays an error message. + * * @param msg The error message to display. */ public static void showError(String msg) { From fbea3bafc97b6fa8a07cdc44128d877eb30089d1 Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Tue, 25 Feb 2025 12:00:41 +0800 Subject: [PATCH 16/25] Level 7. Save --- src/main/java/Eddie.java | 194 ++++++++++++++++++++++++------------- src/main/java/Storage.java | 93 ++++++++++++++++++ 2 files changed, 219 insertions(+), 68 deletions(-) create mode 100644 src/main/java/Storage.java diff --git a/src/main/java/Eddie.java b/src/main/java/Eddie.java index 9c10fe48a..b6eab0a50 100644 --- a/src/main/java/Eddie.java +++ b/src/main/java/Eddie.java @@ -1,4 +1,5 @@ import java.util.Scanner; +import java.util.ArrayList; /** * The Eddie class represents a simple task management system chatbot. @@ -6,9 +7,11 @@ */ public class Eddie { private boolean isRunning = true; - private static final int MAX_TASKS = 100; - private final Task[] tasks = new Task[MAX_TASKS]; - private int taskCount = 0; + private ArrayList tasksList; + + public Eddie() { + this.tasksList = Storage.loadTasks(); // Load tasks from file at startup + } /** * Initializes Eddie and starts the run loop. @@ -36,6 +39,7 @@ public void run() { /** * Processes user input and executes the user command through CLI. + * * @param input The user's command input. */ private void processUserInput(String input) { @@ -49,7 +53,7 @@ private void processUserInput(String input) { Display.showEndPage(); break; case "list": - Display.showTaskList(tasks, taskCount); + Display.showTaskList(tasksList); break; case "mark": taskStatus(arguments, true); @@ -66,6 +70,9 @@ private void processUserInput(String input) { case "event": addEvent(arguments); break; + case "delete": + deleteTask(arguments); + break; default: throw new EddieException(ErrorMessages.INVALID_COMMAND); } @@ -77,18 +84,21 @@ private void processUserInput(String input) { /** * Adds a ToDo task to the task list. + * * @param details The task description. * @throws EddieException If the details are empty or invalid. */ private void addToDo(String details) throws EddieException { EddieException.checkTodo(details); Task newTask = new Todo(details); - tasks[taskCount++] = newTask; - Display.showTaskAdded(newTask, taskCount); + tasksList.add(newTask); + Display.showTaskAdded(newTask, tasksList.size()); + Storage.saveTasks(tasksList); // Save to file after adding } /** * Adds a Deadline task to the task list. + * * @param details The task description and deadline. * @throws EddieException If the format is incorrect. */ @@ -96,12 +106,14 @@ private void addDeadLine(String details) throws EddieException { EddieException.checkDeadline(details); String[] deadlineParts = details.split(" /by ", 2); Task newTask = new Deadline(deadlineParts[0], deadlineParts[1]); - tasks[taskCount++] = newTask; - Display.showTaskAdded(newTask, taskCount); + tasksList.add(newTask); + Display.showTaskAdded(newTask, tasksList.size()); + Storage.saveTasks(tasksList); } /** * Adds an Event task to the task list. + * * @param details The task description, start, and end times. * @throws EddieException If the format is incorrect. */ @@ -110,73 +122,79 @@ private void addEvent(String details) throws EddieException { String[] eventParts = details.split(" /from ", 2); String[] timeParts = eventParts[1].split(" /to ", 2); Task newTask = new Event(eventParts[0], timeParts[0], timeParts[1]); - tasks[taskCount++] = newTask; - Display.showTaskAdded(newTask, taskCount); + tasksList.add(newTask); + Display.showTaskAdded(newTask, tasksList.size()); + Storage.saveTasks(tasksList); } /** * Marks or unmarks a task as completed. + * * @param taskIndex The task number as a string. - * @param markDone True to mark as done, false to unmark. + * @param markDone True to mark as done, false to unmark. * @throws EddieException If the task number is invalid. */ private void taskStatus(String taskIndex, boolean markDone) throws EddieException { - int index = EddieException.checkTaskStatus(taskIndex, taskCount); - if (markDone) { - tasks[index].markDone(); - } else { - tasks[index].markNotDone(); - } - Display.showMarkedStatus(tasks[index], markDone); + int index = EddieException.checkTaskStatus(taskIndex, tasksList.size()); + Task task = tasksList.get(index); + if (markDone) { + task.markDone(); + } else { + task.markNotDone(); + } + Display.showMarkedStatus(task, markDone); + Storage.saveTasks(tasksList); + } + + private void deleteTask(String taskIndex) throws EddieException { + int index = EddieException.checkTaskStatus(taskIndex, tasksList.size()); + Task removedTask = tasksList.remove(index); + Display.showTaskDeleted(removedTask, tasksList.size()); + Storage.saveTasks(tasksList); } } /** * Represents a generic task that can be marked as done or not done. */ -class Task { +abstract class Task { protected String description; protected boolean isDone; - /** - * Constructs a new Task with a given description. - * @param description The description of the task. - */ public Task(String description) { this.description = description; this.isDone = false; } - /** - * Marks the task as done. - */ - public void markDone() {this.isDone = true;} + public Task(String description, boolean isDone) { + this.description = description; + this.isDone = isDone; + } - /** - * Marks the task as not done. - */ - public void markNotDone() {this.isDone = false;} + public void markDone() { + this.isDone = true; + } - /** - * Returns the task's completion status icon. - * @return "[X]" if done, "[ ]" otherwise. - */ - public String getIcon() {return isDone ? "[X]" : "[ ]";} + public void markNotDone() { + this.isDone = false; + } - /** - * Returns the task description. - * @return The description of the task. - */ - public String getDescription() {return description;} + public String getIcon() { + return isDone ? "[X]" : "[ ]"; + } - /** - * Returns the task type icon. - * @return A default task type icon. - */ - public String getTaskType() {return "[ ]";} + public String getDescription() { + return description; + } + + public abstract String getTaskType(); + + public abstract String toFileFormat(); @Override - public String toString() {return getTaskType() + getIcon() + " " + getDescription();} + public String toString() { + return getTaskType() + getIcon() + " " + getDescription(); + } } /** @@ -187,33 +205,47 @@ public Todo(String description) { super(description); } + public Todo(String description, boolean isDone) { + super(description, isDone); + } + @Override public String getTaskType() { return "[T]"; } + + @Override + public String toFileFormat() { + return "T | " + (isDone ? "1" : "0") + " | " + description; + } } /** * deadline task class to create deadline tasks. */ class Deadline extends Task { - private final String by; + private String by; - /** - * Constructs a new Deadline task. - * @param description The task description. - * @param by The deadline for the task. - */ public Deadline(String description, String by) { super(description); this.by = by; } + public Deadline(String description, String by, boolean isDone) { + super(description, isDone); + this.by = by; + } + @Override public String getTaskType() { return "[D]"; } + @Override + public String toFileFormat() { + return "D | " + (isDone ? "1" : "0") + " | " + description + " | " + by; + } + @Override public String toString() { return super.toString() + " (by: " + by + ")"; @@ -224,39 +256,43 @@ public String toString() { * event task class to create events with a start and end time. */ class Event extends Task { - private final String from; - private final String to; + private String from, to; - /** - * Constructs a new Event task. - * @param description The event description. - * @param from The start time of the event. - * @param to The end time of the event. - */ public Event(String description, String from, String to) { super(description); this.from = from; this.to = to; } + public Event(String description, String from, String to, boolean isDone) { + super(description, isDone); + this.from = from; + this.to = to; + } + @Override public String getTaskType() { return "[E]"; } + @Override + public String toFileFormat() { + return "E | " + (isDone ? "1" : "0") + " | " + description + " | " + from + " | " + to; + } + @Override public String toString() { return super.toString() + " (from: " + from + " to: " + to + ")"; } } - /** * Eddie exception class for handling task-related errors in the Eddie task manager. */ class EddieException extends Exception { /** * Constructs an EddieException with a specific error message. + * * @param message The error message. */ public EddieException(String message) { @@ -265,6 +301,7 @@ public EddieException(String message) { /** * Validates a ToDo task description. + * * @param details The task description. * @throws EddieException If the description is empty. */ @@ -276,6 +313,7 @@ public static void checkTodo(String details) throws EddieException { /** * Validates a Deadline task description. + * * @param details The task description including the deadline. * @throws EddieException If the format is incorrect. */ @@ -288,6 +326,7 @@ public static void checkDeadline(String details) throws EddieException { /** * Validates an Event task description. + * * @param details The task description including the event time. * @throws EddieException If the format is incorrect. */ @@ -300,6 +339,7 @@ public static void checkEvent(String details) throws EddieException { /** * Validates and parses a task index input. + * * @param taskIndex The task index as a string. * @param taskCount The total number of tasks. * @return The parsed and validated task index. @@ -331,6 +371,12 @@ class ErrorMessages { public static final String INVALID_EVENT = "Oh no! empty description. Use:" + " event {task} /from {start} /to {end}"; public static final String INVALID_TASK_NUMBER = "Oh no! Invalid task number."; + public static final String MKDIR_FAILED = "Oh no! Unable to create directory" + + " for saving task."; + public static final String SAVE_TASK_FAILED = "Oh no! Unable to save task: "; + public static final String TASK_LOAD_FAILED = "Oh no! Unable to load task: "; + public static final String TASK_TYPE_UNKNOWN = "Oh no! Unknown task type: "; + public static final String TASK_PARSING_ERROR = "Oh no! parsing task: "; } /** @@ -392,7 +438,8 @@ public static void printLine() { /** * Displays a message confirming a task has been added. - * @param task The task that was added. + * + * @param task The task that was added. * @param count The total number of tasks. */ public static void showTaskAdded(Task task, int count) { @@ -402,29 +449,40 @@ public static void showTaskAdded(Task task, int count) { /** * Displays the list of all tasks. - * @param tasks Array of tasks. - * @param count Total number of tasks. + * + * @param tasksList Array of tasks. */ - public static void showTaskList(Task[] tasks, int count) { + public static void showTaskList(ArrayList tasksList) { System.out.println("Eddie:\nHere are the tasks in your list:"); - for (int i = 0; i < count; i++) System.out.println((i + 1) + ". " + tasks[i]); + if (tasksList.isEmpty()) { + System.out.println("No tasks in your list."); + } + + for (int i = 0; i < tasksList.size(); i++) System.out.println((i + 1) + ". " + tasksList.get(i)); } /** * Displays a message when a task is marked or unmarked. + * * @param task The task being updated. * @param done True if marking as done, false if unmarking. */ public static void showMarkedStatus(Task task, boolean done) { - if(done) { + if (done) { System.out.println("Eddie:\nYay! Marked as done:\n " + task + "\nHave a Beer!!"); } else { System.out.println("Eddie:\nOh no! Marked as not done:\n " + task); } } + public static void showTaskDeleted(Task task, int count) { + System.out.println("Eddie:\nNoted. I've removed this task:\n " + task); + System.out.println("Now you have " + count + " tasks in the list."); + } + /** * Displays an error message. + * * @param msg The error message to display. */ public static void showError(String msg) { diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java new file mode 100644 index 000000000..6c942ffb5 --- /dev/null +++ b/src/main/java/Storage.java @@ -0,0 +1,93 @@ +import java.io.*; +import java.util.ArrayList; +import java.util.Scanner; + +public class Storage { + private static final String FILE_PATH = "./data/eddie.txt"; + private static final String DIRECTORY_PATH = "./data/"; + + /** + * Saves the tasks to a file. + * + * @param tasks The list of tasks to save. + */ + public static void saveTasks(ArrayList tasks) { + try { + File directory = new File(DIRECTORY_PATH); + + if (directory.exists() || directory.mkdir()) { + try (FileWriter writer = new FileWriter(FILE_PATH)) { + for (Task task : tasks) { + writer.write(task.toFileFormat() + + System.lineSeparator()); + } + } + } else { + System.out.println(ErrorMessages.MKDIR_FAILED); + } + } catch (IOException e) { + System.out.println(ErrorMessages.SAVE_TASK_FAILED + e.getMessage()); + } + } + + /** + * Loads tasks from a file. + * + * @return The list of tasks loaded from the file. + */ + public static ArrayList loadTasks() { + ArrayList tasks = new ArrayList<>(); + File file = new File(FILE_PATH); + + if (file.exists()) { + try { + Scanner scanner = new Scanner(file); + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + Task task = parseTask(line); + if (task != null) { + tasks.add(task); + } + } + scanner.close(); + } catch (FileNotFoundException e) { + System.out.println(ErrorMessages.TASK_LOAD_FAILED + + e.getMessage()); + } + } else { + System.out.println("Oh no! saved tasks found. " + + "Creating a new one in a sec."); + } + + return tasks; + } + + + /** + * Parses a line from the file and converts it into a Task object. + * + * @param line The line from the file. + * @return The corresponding Task object. + */ + private static Task parseTask(String line) { + try { + String[] parts = line.split(" \\| "); + String type = parts[0]; + boolean isDone = parts[1].equals("1"); + String description = parts[2]; + + return switch (type) { + case "T" -> new Todo(description, isDone); + case "D" -> new Deadline(description, parts[3], isDone); + case "E" -> new Event(description, parts[3], parts[4], isDone); + default -> { + System.out.println(ErrorMessages.TASK_TYPE_UNKNOWN + type); + yield null; + } + }; + } catch (Exception e) { + System.out.println(ErrorMessages.TASK_PARSING_ERROR + line); + return null; + } + } +} From 2d8efdc858c213984647bbaff1e780c01791ca14 Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Sun, 30 Mar 2025 00:01:51 +0800 Subject: [PATCH 17/25] A-MoreOOP --- data/tasks.txt | 2 + src/main/java/Eddie.java | 503 ++-------------------- src/main/java/META-INF/MANIFEST.MF | 3 + src/main/java/Storage.java | 93 ---- src/main/java/command/AddCommand.java | 55 +++ src/main/java/command/Command.java | 26 ++ src/main/java/command/DeleteCommand.java | 27 ++ src/main/java/command/EddieException.java | 8 + src/main/java/command/ExitCommand.java | 17 + src/main/java/command/ListCommand.java | 12 + src/main/java/command/MarkCommand.java | 31 ++ src/main/java/parser/Parser.java | 40 ++ src/main/java/storage/Storage.java | 100 +++++ src/main/java/task/Deadline.java | 33 ++ src/main/java/task/Event.java | 36 ++ src/main/java/task/Task.java | 75 ++++ src/main/java/task/Todo.java | 25 ++ src/main/java/tasklist/TaskList.java | 119 +++++ src/main/java/ui/ErrorMessages.java | 14 + src/main/java/ui/Ui.java | 93 ++++ 20 files changed, 752 insertions(+), 560 deletions(-) create mode 100644 data/tasks.txt create mode 100644 src/main/java/META-INF/MANIFEST.MF delete mode 100644 src/main/java/Storage.java create mode 100644 src/main/java/command/AddCommand.java create mode 100644 src/main/java/command/Command.java create mode 100644 src/main/java/command/DeleteCommand.java create mode 100644 src/main/java/command/EddieException.java create mode 100644 src/main/java/command/ExitCommand.java create mode 100644 src/main/java/command/ListCommand.java create mode 100644 src/main/java/command/MarkCommand.java create mode 100644 src/main/java/parser/Parser.java create mode 100644 src/main/java/storage/Storage.java create mode 100644 src/main/java/task/Deadline.java create mode 100644 src/main/java/task/Event.java create mode 100644 src/main/java/task/Task.java create mode 100644 src/main/java/task/Todo.java create mode 100644 src/main/java/tasklist/TaskList.java create mode 100644 src/main/java/ui/ErrorMessages.java create mode 100644 src/main/java/ui/Ui.java diff --git a/data/tasks.txt b/data/tasks.txt new file mode 100644 index 000000000..487c2c777 --- /dev/null +++ b/data/tasks.txt @@ -0,0 +1,2 @@ +T | 1 | read book +E | 1 | buy | 3pm | 5pm diff --git a/src/main/java/Eddie.java b/src/main/java/Eddie.java index b6eab0a50..4cf23ead2 100644 --- a/src/main/java/Eddie.java +++ b/src/main/java/Eddie.java @@ -1,491 +1,60 @@ -import java.util.Scanner; -import java.util.ArrayList; +import command.Command; +import command.EddieException; +import parser.Parser; +import storage.Storage; +import tasklist.TaskList; +import ui.Ui; /** - * The Eddie class represents a simple task management system chatbot. - * It allows users to add, list, mark, and unmark tasks through a CLI. + * The main class for the Eddie chatbot task manager. */ public class Eddie { - private boolean isRunning = true; - private ArrayList tasksList; - - public Eddie() { - this.tasksList = Storage.loadTasks(); // Load tasks from file at startup - } - - /** - * Initializes Eddie and starts the run loop. - */ - public static void main(String[] args) { - Eddie eddie = new Eddie(); - eddie.run(); - } + private Ui ui; + private Storage storage; + private TaskList tasks; /** - * Starts the application and continuously processes user input. + * Initializes Eddie with the default storage file path. */ - public void run() { - Display.showStartPage(); - Scanner scanner = new Scanner(System.in); - - while (isRunning) { - System.out.print("You: "); - String userInput = scanner.nextLine().trim(); - Display.printLine(); - processUserInput(userInput); - } - scanner.close(); - } + public Eddie(String filePath) { + ui = new Ui(); + storage = new Storage(filePath); - /** - * Processes user input and executes the user command through CLI. - * - * @param input The user's command input. - */ - private void processUserInput(String input) { - String[] parts = input.split(" ", 2); - String command = parts[0].toLowerCase(); - String arguments = (parts.length > 1) ? parts[1] : ""; try { - switch (command) { - case "bye": - isRunning = false; - Display.showEndPage(); - break; - case "list": - Display.showTaskList(tasksList); - break; - case "mark": - taskStatus(arguments, true); - break; - case "unmark": - taskStatus(arguments, false); - break; - case "todo": - addToDo(arguments); - break; - case "deadline": - addDeadLine(arguments); - break; - case "event": - addEvent(arguments); - break; - case "delete": - deleteTask(arguments); - break; - default: - throw new EddieException(ErrorMessages.INVALID_COMMAND); - } + tasks = new TaskList(storage.loadTask()); } catch (EddieException e) { - Display.showError(e.getMessage()); + ui.showLoadingError(); + tasks = new TaskList(); } - Display.printLine(); - } - - /** - * Adds a ToDo task to the task list. - * - * @param details The task description. - * @throws EddieException If the details are empty or invalid. - */ - private void addToDo(String details) throws EddieException { - EddieException.checkTodo(details); - Task newTask = new Todo(details); - tasksList.add(newTask); - Display.showTaskAdded(newTask, tasksList.size()); - Storage.saveTasks(tasksList); // Save to file after adding - } - - /** - * Adds a Deadline task to the task list. - * - * @param details The task description and deadline. - * @throws EddieException If the format is incorrect. - */ - private void addDeadLine(String details) throws EddieException { - EddieException.checkDeadline(details); - String[] deadlineParts = details.split(" /by ", 2); - Task newTask = new Deadline(deadlineParts[0], deadlineParts[1]); - tasksList.add(newTask); - Display.showTaskAdded(newTask, tasksList.size()); - Storage.saveTasks(tasksList); - } - - /** - * Adds an Event task to the task list. - * - * @param details The task description, start, and end times. - * @throws EddieException If the format is incorrect. - */ - private void addEvent(String details) throws EddieException { - EddieException.checkEvent(details); - String[] eventParts = details.split(" /from ", 2); - String[] timeParts = eventParts[1].split(" /to ", 2); - Task newTask = new Event(eventParts[0], timeParts[0], timeParts[1]); - tasksList.add(newTask); - Display.showTaskAdded(newTask, tasksList.size()); - Storage.saveTasks(tasksList); } /** - * Marks or unmarks a task as completed. - * - * @param taskIndex The task number as a string. - * @param markDone True to mark as done, false to unmark. - * @throws EddieException If the task number is invalid. + * Starts the Eddie chatbot. */ - private void taskStatus(String taskIndex, boolean markDone) throws EddieException { - int index = EddieException.checkTaskStatus(taskIndex, tasksList.size()); - Task task = tasksList.get(index); - if (markDone) { - task.markDone(); - } else { - task.markNotDone(); - } - Display.showMarkedStatus(task, markDone); - Storage.saveTasks(tasksList); - } - - private void deleteTask(String taskIndex) throws EddieException { - int index = EddieException.checkTaskStatus(taskIndex, tasksList.size()); - Task removedTask = tasksList.remove(index); - Display.showTaskDeleted(removedTask, tasksList.size()); - Storage.saveTasks(tasksList); - } -} - -/** - * Represents a generic task that can be marked as done or not done. - */ -abstract class Task { - protected String description; - protected boolean isDone; - - public Task(String description) { - this.description = description; - this.isDone = false; - } - - public Task(String description, boolean isDone) { - this.description = description; - this.isDone = isDone; - } - - public void markDone() { - this.isDone = true; - } - - public void markNotDone() { - this.isDone = false; - } - - public String getIcon() { - return isDone ? "[X]" : "[ ]"; - } - - public String getDescription() { - return description; - } - - public abstract String getTaskType(); - - public abstract String toFileFormat(); - - @Override - public String toString() { - return getTaskType() + getIcon() + " " + getDescription(); - } -} - -/** - * Todo task class to create todo tasks. - */ -class Todo extends Task { - public Todo(String description) { - super(description); - } - - public Todo(String description, boolean isDone) { - super(description, isDone); - } - - @Override - public String getTaskType() { - return "[T]"; - } - - @Override - public String toFileFormat() { - return "T | " + (isDone ? "1" : "0") + " | " + description; - } -} - -/** - * deadline task class to create deadline tasks. - */ -class Deadline extends Task { - private String by; - - public Deadline(String description, String by) { - super(description); - this.by = by; - } - - public Deadline(String description, String by, boolean isDone) { - super(description, isDone); - this.by = by; - } - - @Override - public String getTaskType() { - return "[D]"; - } - - @Override - public String toFileFormat() { - return "D | " + (isDone ? "1" : "0") + " | " + description + " | " + by; - } - - @Override - public String toString() { - return super.toString() + " (by: " + by + ")"; - } -} - -/** - * event task class to create events with a start and end time. - */ -class Event extends Task { - private String from, to; - - public Event(String description, String from, String to) { - super(description); - this.from = from; - this.to = to; - } - - public Event(String description, String from, String to, boolean isDone) { - super(description, isDone); - this.from = from; - this.to = to; - } - - @Override - public String getTaskType() { - return "[E]"; - } - - @Override - public String toFileFormat() { - return "E | " + (isDone ? "1" : "0") + " | " + description + " | " + from + " | " + to; - } - - @Override - public String toString() { - return super.toString() + " (from: " + from + " to: " + to + ")"; - } -} - -/** - * Eddie exception class for handling task-related errors in the Eddie task manager. - */ -class EddieException extends Exception { - /** - * Constructs an EddieException with a specific error message. - * - * @param message The error message. - */ - public EddieException(String message) { - super(message); - } - - /** - * Validates a ToDo task description. - * - * @param details The task description. - * @throws EddieException If the description is empty. - */ - public static void checkTodo(String details) throws EddieException { - if (details.isEmpty()) { - throw new EddieException(ErrorMessages.INVALID_TODO); - } - } - - /** - * Validates a Deadline task description. - * - * @param details The task description including the deadline. - * @throws EddieException If the format is incorrect. - */ - public static void checkDeadline(String details) throws EddieException { - String[] deadlineParts = details.split(" /by ", 2); - if (deadlineParts.length < 2) { - throw new EddieException(ErrorMessages.INVALID_DEADLINE); - } - } - - /** - * Validates an Event task description. - * - * @param details The task description including the event time. - * @throws EddieException If the format is incorrect. - */ - public static void checkEvent(String details) throws EddieException { - String[] eventParts = details.split(" /from ", 2); - if (eventParts.length < 2 || !eventParts[1].contains(" /to ")) { - throw new EddieException(ErrorMessages.INVALID_EVENT); - } - } + public void run() { + ui.showStartPage(); + boolean isRunning = true; - /** - * Validates and parses a task index input. - * - * @param taskIndex The task index as a string. - * @param taskCount The total number of tasks. - * @return The parsed and validated task index. - * @throws EddieException If the task number is invalid. - */ - public static int checkTaskStatus(String taskIndex, int taskCount) throws EddieException { - try { - int index = Integer.parseInt(taskIndex) - 1; - if (index < 0 || index >= taskCount) { - throw new EddieException(ErrorMessages.INVALID_TASK_NUMBER); + while (isRunning) { + String userInput = ui.readCommand(); + ui.printLine(); + try { + Command command = Parser.parse(userInput); + command.execute(tasks, ui, storage); + if (command.isExit()) { + isRunning = false; + } + } catch (EddieException e) { + ui.showError(e.getMessage()); } - return index; - } catch (NumberFormatException e) { - throw new EddieException(ErrorMessages.INVALID_TASK_NUMBER); + ui.printLine(); } } -} - -/** - * Contains predefined error messages for the Eddie task manager. - */ -class ErrorMessages { - public static final String INVALID_COMMAND = "Oh no! Invalid command. Use: " + - "todo, deadline, event, list, mark {num}, or unmark {num}."; - public static final String INVALID_TODO = "Oh no! empty description. Use:" + - " todo {task description}"; - public static final String INVALID_DEADLINE = "Oh no! empty description. " + - "Use: deadline {task} /by {date}"; - public static final String INVALID_EVENT = "Oh no! empty description. Use:" + - " event {task} /from {start} /to {end}"; - public static final String INVALID_TASK_NUMBER = "Oh no! Invalid task number."; - public static final String MKDIR_FAILED = "Oh no! Unable to create directory" + - " for saving task."; - public static final String SAVE_TASK_FAILED = "Oh no! Unable to save task: "; - public static final String TASK_LOAD_FAILED = "Oh no! Unable to load task: "; - public static final String TASK_TYPE_UNKNOWN = "Oh no! Unknown task type: "; - public static final String TASK_PARSING_ERROR = "Oh no! parsing task: "; -} - -/** - * The Display class to print user interface messages - * for the Eddie task manager, including startup, shutdown, task actions, - * and error messages. - */ -class Display { - private static final String LOGO = - " _____ ____ ____ ___ _____ \n" - + " | ____|| _ \\| _ \\|_ _|| ____| \n" - + " | _| | | | | | | || | | _| \n" - + " | |___ | |_| | |_| || | | |___ \n" - + " |_____||____/|____/|___||_____| \n"; - - /** - * Displays the startup message and user guide. - */ - public static void showStartPage() { - System.out.println(LOGO); - printLine(); - System.out.println("Eddie: Welcome to your personal task manager!"); - System.out.println("I can help you manage different types of tasks.\n"); - - System.out.println("HOW TO USE EDDIE by typing"); - System.out.println("Adding a Task!"); - System.out.println("To add a ToDo: `todo {Name of Task}`"); - System.out.println("To add a Deadline: `deadline {Name of Deadline} /by {Date or Day}`"); - System.out.println("To add an Event: `event {Name of Event} /from {Day/Date} {Time} /to {Time}`\n"); - - System.out.println("To view your Task List!"); - System.out.println("See all tasks: `list`\n"); - - System.out.println("Managing Tasks!"); - System.out.println("To mark as done: `mark 2`"); - System.out.println("To unmark: `unmark 2`\n"); - - System.out.println("Exiting the Program!"); - System.out.println("To exit: `bye`\n"); - printLine(); - } - - /** - * Displays the shutdown message. - */ - public static void showEndPage() { - System.out.println(LOGO); - printLine(); - System.out.println("Eddie:\nGoodbye! Hope to see you again soon!"); - printLine(); - } /** - * Prints a horizontal line as a separator. + * Entry point for the program. */ - public static void printLine() { - System.out.println("____________________________________________________________"); - } - - /** - * Displays a message confirming a task has been added. - * - * @param task The task that was added. - * @param count The total number of tasks. - */ - public static void showTaskAdded(Task task, int count) { - System.out.println("Eddie:\nGot it. I've added this task:\n " + task); - System.out.println("Now you have " + count + " tasks in the list."); - } - - /** - * Displays the list of all tasks. - * - * @param tasksList Array of tasks. - */ - public static void showTaskList(ArrayList tasksList) { - System.out.println("Eddie:\nHere are the tasks in your list:"); - if (tasksList.isEmpty()) { - System.out.println("No tasks in your list."); - } - - for (int i = 0; i < tasksList.size(); i++) System.out.println((i + 1) + ". " + tasksList.get(i)); - } - - /** - * Displays a message when a task is marked or unmarked. - * - * @param task The task being updated. - * @param done True if marking as done, false if unmarking. - */ - public static void showMarkedStatus(Task task, boolean done) { - if (done) { - System.out.println("Eddie:\nYay! Marked as done:\n " + task + "\nHave a Beer!!"); - } else { - System.out.println("Eddie:\nOh no! Marked as not done:\n " + task); - } - } - - public static void showTaskDeleted(Task task, int count) { - System.out.println("Eddie:\nNoted. I've removed this task:\n " + task); - System.out.println("Now you have " + count + " tasks in the list."); - } - - /** - * Displays an error message. - * - * @param msg The error message to display. - */ - public static void showError(String msg) { - System.out.println("Eddie:\nError: " + msg); + public static void main(String[] args) { + new Eddie("data/tasks.txt").run(); } } diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 000000000..372c9c8c8 --- /dev/null +++ b/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: Eddie + diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java deleted file mode 100644 index 6c942ffb5..000000000 --- a/src/main/java/Storage.java +++ /dev/null @@ -1,93 +0,0 @@ -import java.io.*; -import java.util.ArrayList; -import java.util.Scanner; - -public class Storage { - private static final String FILE_PATH = "./data/eddie.txt"; - private static final String DIRECTORY_PATH = "./data/"; - - /** - * Saves the tasks to a file. - * - * @param tasks The list of tasks to save. - */ - public static void saveTasks(ArrayList tasks) { - try { - File directory = new File(DIRECTORY_PATH); - - if (directory.exists() || directory.mkdir()) { - try (FileWriter writer = new FileWriter(FILE_PATH)) { - for (Task task : tasks) { - writer.write(task.toFileFormat() + - System.lineSeparator()); - } - } - } else { - System.out.println(ErrorMessages.MKDIR_FAILED); - } - } catch (IOException e) { - System.out.println(ErrorMessages.SAVE_TASK_FAILED + e.getMessage()); - } - } - - /** - * Loads tasks from a file. - * - * @return The list of tasks loaded from the file. - */ - public static ArrayList loadTasks() { - ArrayList tasks = new ArrayList<>(); - File file = new File(FILE_PATH); - - if (file.exists()) { - try { - Scanner scanner = new Scanner(file); - while (scanner.hasNextLine()) { - String line = scanner.nextLine(); - Task task = parseTask(line); - if (task != null) { - tasks.add(task); - } - } - scanner.close(); - } catch (FileNotFoundException e) { - System.out.println(ErrorMessages.TASK_LOAD_FAILED + - e.getMessage()); - } - } else { - System.out.println("Oh no! saved tasks found. " + - "Creating a new one in a sec."); - } - - return tasks; - } - - - /** - * Parses a line from the file and converts it into a Task object. - * - * @param line The line from the file. - * @return The corresponding Task object. - */ - private static Task parseTask(String line) { - try { - String[] parts = line.split(" \\| "); - String type = parts[0]; - boolean isDone = parts[1].equals("1"); - String description = parts[2]; - - return switch (type) { - case "T" -> new Todo(description, isDone); - case "D" -> new Deadline(description, parts[3], isDone); - case "E" -> new Event(description, parts[3], parts[4], isDone); - default -> { - System.out.println(ErrorMessages.TASK_TYPE_UNKNOWN + type); - yield null; - } - }; - } catch (Exception e) { - System.out.println(ErrorMessages.TASK_PARSING_ERROR + line); - return null; - } - } -} diff --git a/src/main/java/command/AddCommand.java b/src/main/java/command/AddCommand.java new file mode 100644 index 000000000..18e192e3a --- /dev/null +++ b/src/main/java/command/AddCommand.java @@ -0,0 +1,55 @@ +package command; + +import storage.Storage; +import tasklist.TaskList; +import ui.ErrorMessages; +import ui.Ui; +import task.Todo; +import task.Deadline; +import task.Event; + +/** + * Represents a command to add a new task todo, deadline and event. + */ +public class AddCommand extends Command { + private final String taskDetails; + private final String taskType; + + public AddCommand(String taskDetails, String taskType) { + this.taskDetails = taskDetails; + this.taskType = taskType; + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) throws EddieException { + switch (taskType) { + case "todo": + if (taskDetails.isEmpty()) { + throw new EddieException(ErrorMessages.INVALID_TODO); + } + tasks.addTask(new Todo(taskDetails)); + break; + case "deadline": + String[] deadlineParts = taskDetails.split(" /by ", 2); + if (deadlineParts.length < 2) { + throw new EddieException(ErrorMessages.INVALID_DEADLINE); + } + tasks.addTask(new Deadline(deadlineParts[0], deadlineParts[1])); + break; + case "event": + String[] eventParts = taskDetails.split(" /from ", 2); + if (eventParts.length < 2 || !eventParts[1].contains(" /to ")) { + throw new EddieException(ErrorMessages.INVALID_EVENT); + } + String[] timeParts = eventParts[1].split(" /to ", 2); + tasks.addTask(new Event(eventParts[0], timeParts[0], timeParts[1])); + break; + default: + throw new EddieException(ErrorMessages.INVALID_COMMAND); + } + + // Show confirm task to user and save tasks + ui.showTaskAdded(tasks.getLastTask(), tasks.size()); + storage.saveTasks(tasks.getAllTasks()); + } +} diff --git a/src/main/java/command/Command.java b/src/main/java/command/Command.java new file mode 100644 index 000000000..964e40e6f --- /dev/null +++ b/src/main/java/command/Command.java @@ -0,0 +1,26 @@ +package command; + +import storage.Storage; +import tasklist.TaskList; +import ui.Ui; + +/** + * Abstract base class for all user commands. + */ +public abstract class Command { + /** + * Executes the command with the provided task list, UI, and storage. + * + * @param tasks The task list to operate on. + * @param ui The UI to interact with the user. + * @param storage The storage to save and load data. + * @throws EddieException for error occurs during command execution. + */ + public abstract void execute(TaskList tasks, Ui ui, Storage storage) throws EddieException; + + public boolean isExit() { + return false; + } +} + + diff --git a/src/main/java/command/DeleteCommand.java b/src/main/java/command/DeleteCommand.java new file mode 100644 index 000000000..3f2ae53a8 --- /dev/null +++ b/src/main/java/command/DeleteCommand.java @@ -0,0 +1,27 @@ +package command; + +import storage.Storage; +import tasklist.TaskList; +import ui.Ui; +import task.Task; + +public class DeleteCommand extends Command { + private String taskIndex; + + public DeleteCommand(String taskIndex) { + this.taskIndex = taskIndex; + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + try { + int index = Integer.parseInt(taskIndex) - 1; + Task removedTask = tasks.removeTask(index); + ui.showTaskDeleted(removedTask, tasks.size()); + storage.saveTasks(tasks.getAllTasks()); + + } catch (NumberFormatException | EddieException e) { + ui.showError("Invalid task number!"); + } + } +} diff --git a/src/main/java/command/EddieException.java b/src/main/java/command/EddieException.java new file mode 100644 index 000000000..156fbfa4b --- /dev/null +++ b/src/main/java/command/EddieException.java @@ -0,0 +1,8 @@ +package command; + +public class EddieException extends Exception { + public EddieException(String message) { + super(message); + } +} + diff --git a/src/main/java/command/ExitCommand.java b/src/main/java/command/ExitCommand.java new file mode 100644 index 000000000..a0e96d65d --- /dev/null +++ b/src/main/java/command/ExitCommand.java @@ -0,0 +1,17 @@ +package command; + +import storage.Storage; +import tasklist.TaskList; +import ui.Ui; + +public class ExitCommand extends Command { + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + ui.showEndPage(); + } + + @Override + public boolean isExit() { + return true; + } +} diff --git a/src/main/java/command/ListCommand.java b/src/main/java/command/ListCommand.java new file mode 100644 index 000000000..d595b38a7 --- /dev/null +++ b/src/main/java/command/ListCommand.java @@ -0,0 +1,12 @@ +package command; + +import storage.Storage; +import tasklist.TaskList; +import ui.Ui; + +public class ListCommand extends Command { + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + ui.showTaskList(tasks.getAllTasks()); + } +} diff --git a/src/main/java/command/MarkCommand.java b/src/main/java/command/MarkCommand.java new file mode 100644 index 000000000..418bd6c60 --- /dev/null +++ b/src/main/java/command/MarkCommand.java @@ -0,0 +1,31 @@ +package command; + +import storage.Storage; +import task.Task; +import tasklist.TaskList; +import ui.Ui; + + +public class MarkCommand extends Command { + private String taskIndex; + private boolean isMarking; + + public MarkCommand(String taskIndex, boolean isMarking) { + this.taskIndex = taskIndex; + this.isMarking = isMarking; + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + try { + int index = Integer.parseInt(taskIndex) - 1; + Task task = tasks.getTask(index); + tasks.markTask(index, isMarking); + ui.showMarkedStatus(task, isMarking); + storage.saveTasks(tasks.getAllTasks()); + + } catch (NumberFormatException | EddieException e) { + ui.showError("Invalid task number!"); + } + } +} diff --git a/src/main/java/parser/Parser.java b/src/main/java/parser/Parser.java new file mode 100644 index 000000000..3f873f856 --- /dev/null +++ b/src/main/java/parser/Parser.java @@ -0,0 +1,40 @@ +package parser; + +import command.*; +import command.EddieException; + +public class Parser { + /** + * Parses the user input and returns the corresponding command. + * + * @param input The raw user input. + * @return A Command object that represents the user's action. + * @throws EddieException If the input is invalid. + */ + public static Command parse(String input) throws EddieException { + String[] parts = input.trim().split(" ", 2); + String command = parts[0].toLowerCase(); + String arguments = (parts.length > 1) ? parts[1] : ""; + + switch (command) { + case "todo": + return new AddCommand(arguments, "todo"); + case "deadline": + return new AddCommand(arguments, "deadline"); + case "event": + return new AddCommand(arguments, "event"); + case "list": + return new ListCommand(); + case "mark": + return new MarkCommand(arguments, true); + case "unmark": + return new MarkCommand(arguments, false); + case "delete": + return new DeleteCommand(arguments); + case "bye": + return new ExitCommand(); + default: + throw new EddieException("Unknown command! Try: todo, deadline, event, list, mark {num}, unmark {num}, delete {num}, or bye."); + } + } +} diff --git a/src/main/java/storage/Storage.java b/src/main/java/storage/Storage.java new file mode 100644 index 000000000..d1d0f12c7 --- /dev/null +++ b/src/main/java/storage/Storage.java @@ -0,0 +1,100 @@ +package storage; + +import task.Task; +import task.Todo; +import task.Deadline; +import task.Event; +import tasklist.TaskList; +import command.EddieException; +import ui.ErrorMessages; + +import java.io.*; +import java.util.ArrayList; + +public class Storage { + private final String filePath; + + public Storage(String filePath) { + this.filePath = filePath; + } + + /** + * Loads tasks from the storage file. + */ + public ArrayList loadTask() throws EddieException { + ArrayList tasks = new ArrayList<>(); + File file = new File(filePath); + + if (!file.exists()) { + createFile(); + return tasks; + } + + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + String line; + while ((line = reader.readLine()) != null) { + tasks.add(parseTask(line)); + } + } catch (IOException e) { + throw new EddieException(ErrorMessages.TASK_LOAD_FAILED + e.getMessage()); + } + + return tasks; + } + + /** + * Saves tasks to the storage file. + */ + public void saveTasks(ArrayList tasks) { + try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) { + for (Task task : tasks) { + writer.write(task.toFileFormat()); + writer.newLine(); + } + } catch (IOException e) { + System.out.println(ErrorMessages.SAVE_TASK_FAILED + e.getMessage()); + } + } + + /** + * Parses a line from the file into a Task object. + */ + private Task parseTask(String line) throws EddieException { + try { + String[] parts = line.split(" \\| "); + String type = parts[0]; + boolean isDone = parts[1].equals("1"); + String description = parts[2]; + + switch (type) { + case "T": + return new Todo(description, isDone); + case "D": + return new Deadline(description, parts[3], isDone); + case "E": + return new Event(description, parts[3], parts[4], isDone); + default: + throw new EddieException(ErrorMessages.TASK_TYPE_UNKNOWN + type); + } + } catch (Exception e) { + throw new EddieException(ErrorMessages.TASK_PARSING_ERROR + line); + } + } + + /** + * Creates the storage file and parent directories if they don't exist. + */ + private void createFile() throws EddieException { + File file = new File(filePath); + File parent = file.getParentFile(); + if (!parent.exists() && !parent.mkdirs()) { + throw new EddieException(ErrorMessages.MKDIR_FAILED); + } + + try { + file.createNewFile(); + } catch (IOException e) { + throw new EddieException(ErrorMessages.SAVE_TASK_FAILED + e.getMessage()); + } + } +} diff --git a/src/main/java/task/Deadline.java b/src/main/java/task/Deadline.java new file mode 100644 index 000000000..4a5379c30 --- /dev/null +++ b/src/main/java/task/Deadline.java @@ -0,0 +1,33 @@ +package task; + +/** + * Represents a deadline task. + */ +public class Deadline extends Task { + private String by; + + public Deadline(String description, String by) { + super(description); + this.by = by; + } + + public Deadline(String description, String by, boolean isDone) { + super(description, isDone); + this.by = by; + } + + @Override + public String getTaskType() { + return "[D]"; + } + + @Override + public String toFileFormat() { + return "D | " + (isDone ? "1" : "0") + " | " + description + " | " + by; + } + + @Override + public String toString() { + return super.toString() + " (by: " + by + ")"; + } +} diff --git a/src/main/java/task/Event.java b/src/main/java/task/Event.java new file mode 100644 index 000000000..e0cedf6d0 --- /dev/null +++ b/src/main/java/task/Event.java @@ -0,0 +1,36 @@ +package task; + +/** + * Represents an event task with a start and end time. + */ +public class Event extends Task { + private String from; + private String to; + + public Event(String description, String from, String to) { + super(description); + this.from = from; + this.to = to; + } + + public Event(String description, String from, String to, boolean isDone) { + super(description, isDone); + this.from = from; + this.to = to; + } + + @Override + public String getTaskType() { + return "[E]"; + } + + @Override + public String toFileFormat() { + return "E | " + (isDone ? "1" : "0") + " | " + description + " | " + from + " | " + to; + } + + @Override + public String toString() { + return super.toString() + " (from: " + from + " to: " + to + ")"; + } +} diff --git a/src/main/java/task/Task.java b/src/main/java/task/Task.java new file mode 100644 index 000000000..e1ff862af --- /dev/null +++ b/src/main/java/task/Task.java @@ -0,0 +1,75 @@ +package task; + +/** + * Task class that can be marked as done or not done. + */ +public abstract class Task { + protected String description; + protected boolean isDone; + + /** + * Constructs a new Task with description. + * + * @param description The description of the task. + */ + public Task(String description) { + this.description = description; + this.isDone = false; + } + + public Task(String description, boolean isDone) { + this.description = description; + this.isDone = isDone; + } + + /** + * Marks the task as done. + */ + public void markDone() { + this.isDone = true; + } + + /** + * Marks the task as not done. + */ + public void markNotDone() { + this.isDone = false; + } + + /** + * Returns the task's completion status icon. + * + * @return "[X]" if done, "[ ]" otherwise. + */ + public String getIcon() { + return isDone ? "[X]" : "[ ]"; + } + + /** + * Returns the task description. + * + * @return The description of the task. + */ + public String getDescription() { + return description; + } + + /** + * Returns the task type icon. + * + * @return A default task type icon. + */ + public abstract String getTaskType(); + + /** + * Converts the task into a file format. + * + * @return A string representation suitable for file storage. + */ + public abstract String toFileFormat(); + + @Override + public String toString() { + return getTaskType() + getIcon() + " " + getDescription(); + } +} diff --git a/src/main/java/task/Todo.java b/src/main/java/task/Todo.java new file mode 100644 index 000000000..f4929bbbd --- /dev/null +++ b/src/main/java/task/Todo.java @@ -0,0 +1,25 @@ +package task; + +/** + * Represents a To-Do task. + */ +public class Todo extends Task { + + public Todo(String description) { + super(description); + } + + public Todo(String description, boolean isDone) { + super(description, isDone); + } + + @Override + public String getTaskType() { + return "[T]"; + } + + @Override + public String toFileFormat() { + return "T | " + (isDone ? "1" : "0") + " | " + description; + } +} diff --git a/src/main/java/tasklist/TaskList.java b/src/main/java/tasklist/TaskList.java new file mode 100644 index 000000000..8b28c1828 --- /dev/null +++ b/src/main/java/tasklist/TaskList.java @@ -0,0 +1,119 @@ +package tasklist; + +import task.Task; +import command.EddieException; + +import java.util.ArrayList; + +/** + * Manages a list of tasks. + */ +public class TaskList { + private ArrayList tasks; + + /** + * Constructs an empty TaskList. + */ + public TaskList() { + this.tasks = new ArrayList<>(); + } + + /** + * Constructs a TaskList with preloaded tasks. + * + * @param tasks The initial list of tasks. + */ + public TaskList(ArrayList tasks) { + this.tasks = tasks; + } + + /** + * Adds a new task to the list. + * + * @param task The task to add. + */ + public void addTask(Task task) { + tasks.add(task); + } + + /** + * Retrieves a task by its index. + * + * @param index The index of the task. + * @return The task at the given index. + */ + public Task getTask(int index) { + return tasks.get(index); + } + + /** + * Removes a task by its index. + * + * @param index The index of the task to remove. + * @return The removed task. + */ + public Task removeTask(int index) throws EddieException { + if (index < 0 || index >= tasks.size()) { + throw new EddieException("Invalid task number."); + } + return tasks.remove(index); + } + + /** + * Marks or unmarks a task as done. + * + * @param index The index of the task. + * @param isDone True to mark as done, false to unmark. + */ + public void markTask(int index, boolean isDone) throws EddieException { + if (index < 0 || index >= tasks.size()) { + throw new EddieException("Invalid task number."); + } + Task task = tasks.get(index); + if (isDone) { + task.markDone(); + } else { + task.markNotDone(); + } + } + + /** + * Returns the total number of tasks. + * + * @return The size of the task list. + */ + public int size() { + return tasks.size(); + } + + /** + * Returns the last added task. + * + * @return The most recent task. + */ + public Task getLastTask() { + return tasks.get(tasks.size() - 1); + } + + /** + * Returns all tasks as a list. + * + * @return The list of tasks. + */ + public ArrayList getAllTasks() { + return tasks; + } + + /** + * Returns a formatted list of all tasks. + * + * @return A string representation of all tasks. + */ + public String getTaskListString() { + StringBuilder list = new StringBuilder(); + for (int i = 0; i < tasks.size(); i++) { + list.append((i + 1)).append(". ").append(tasks.get(i)).append("\n"); + } + return list.toString(); + } +} diff --git a/src/main/java/ui/ErrorMessages.java b/src/main/java/ui/ErrorMessages.java new file mode 100644 index 000000000..361c1a8a9 --- /dev/null +++ b/src/main/java/ui/ErrorMessages.java @@ -0,0 +1,14 @@ +package ui; + +public class ErrorMessages { + public static final String INVALID_COMMAND = "Oh no! Invalid command. Use: todo, deadline, event, list, mark {num}, or unmark {num}."; + public static final String INVALID_TODO = "Oh no! empty description. Use: todo {task description}"; + public static final String INVALID_DEADLINE = "Oh no! empty description. Use: deadline {task} /by {date}"; + public static final String INVALID_EVENT = "Oh no! empty description. Use: event {task} /from {start} /to {end}"; + public static final String INVALID_TASK_NUMBER = "Oh no! Invalid task number."; + public static final String MKDIR_FAILED = "Oh no! Unable to create directory for saving task."; + public static final String SAVE_TASK_FAILED = "Oh no! Unable to save task: "; + public static final String TASK_LOAD_FAILED = "Oh no! Unable to load task: "; + public static final String TASK_TYPE_UNKNOWN = "Oh no! Unknown task type: "; + public static final String TASK_PARSING_ERROR = "Oh no! parsing task: "; +} diff --git a/src/main/java/ui/Ui.java b/src/main/java/ui/Ui.java new file mode 100644 index 000000000..c0a46f499 --- /dev/null +++ b/src/main/java/ui/Ui.java @@ -0,0 +1,93 @@ +package ui; + +import task.Task; +import java.util.ArrayList; +import java.util.Scanner; + +public class Ui { + private static final String LOGO = + " _____ ____ ____ ___ _____ \n" + + " | ____|| _ \\| _ \\|_ _|| ____| \n" + + " | _| | | | | | | || | | _| \n" + + " | |___ | |_| | |_| || | | |___ \n" + + " |_____||____/|____/|___||_____| \n"; + + private final Scanner scanner; + + public Ui() { + this.scanner = new Scanner(System.in); + } + + public void showStartPage() { + System.out.println(LOGO); + printLine(); + System.out.println("Eddie: Welcome to your personal task manager!"); + System.out.println("I can help you manage different types of tasks.\n"); + + System.out.println("HOW TO USE EDDIE:"); + System.out.println("To add a ToDo: `todo {task}`"); + System.out.println("To add a Deadline: `deadline {task} /by {date}`"); + System.out.println("To add an Event: `event {task} /from {start} /to {end}`\n"); + + System.out.println("Other Commands:"); + System.out.println("View all tasks: `list`"); + System.out.println("Mark as done: `mark 2`"); + System.out.println("Unmark: `unmark 2`"); + System.out.println("Delete: `delete 2`"); + System.out.println("Exit: `bye`"); + printLine(); + } + + public void showEndPage() { + printLine(); + System.out.println("Eddie: Goodbye! Hope to see you again soon!"); + printLine(); + } + + public void showTaskAdded(Task task, int count) { + System.out.println("Eddie:\nGot it. I've added this task:\n " + task); + System.out.println("Now you have " + count + " tasks in the list."); + } + + public void showTaskDeleted(Task task, int count) { + System.out.println("Eddie:\nNoted. I've removed this task:\n " + task); + System.out.println("Now you have " + count + " tasks in the list."); + } + + public void showMarkedStatus(Task task, boolean done) { + if (done) { + System.out.println("Eddie:\nYay! Marked as done:\n " + task + "\nHave a Beer!!"); + } else { + System.out.println("Eddie:\nOh no! Marked as not done:\n " + task); + } + } + + public void showTaskList(ArrayList tasks) { + System.out.println("Eddie:\nHere are the tasks in your list:"); + if (tasks.isEmpty()) { + System.out.println("No tasks in your list."); + return; + } + + for (int i = 0; i < tasks.size(); i++) { + System.out.println((i + 1) + ". " + tasks.get(i)); + } + } + + public void showError(String msg) { + System.out.println("Eddie:\nError: " + msg); + } + + public void printLine() { + System.out.println("____________________________________________________________"); + } + + public void showLoadingError() { + System.out.println("Error loading saved tasks. Starting with an empty task list."); + } + + public String readCommand() { + System.out.print("You: "); + return scanner.nextLine().trim(); + } +} From 9d97e232e00da9006cd05dd2e6f7efcf13967d70 Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Sun, 30 Mar 2025 13:53:17 +0800 Subject: [PATCH 18/25] Level 8. Dates and Times --- data/tasks.txt | 5 +++-- src/main/java/command/AddCommand.java | 25 +++++++++++++++++++++---- src/main/java/storage/Storage.java | 22 ++++++++-------------- src/main/java/task/Deadline.java | 18 ++++++++++-------- src/main/java/task/Event.java | 20 +++++++++++--------- 5 files changed, 53 insertions(+), 37 deletions(-) diff --git a/data/tasks.txt b/data/tasks.txt index 487c2c777..adff0b7a5 100644 --- a/data/tasks.txt +++ b/data/tasks.txt @@ -1,2 +1,3 @@ -T | 1 | read book -E | 1 | buy | 3pm | 5pm +T | 0 | read +D | 0 | submit assignment | 2025-04-01 1800 +E | 0 | group meeting | 2025-04-02 1000 | 2025-04-02 1200 diff --git a/src/main/java/command/AddCommand.java b/src/main/java/command/AddCommand.java index 18e192e3a..71d0d3701 100644 --- a/src/main/java/command/AddCommand.java +++ b/src/main/java/command/AddCommand.java @@ -8,6 +8,10 @@ import task.Deadline; import task.Event; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + /** * Represents a command to add a new task todo, deadline and event. */ @@ -31,18 +35,31 @@ public void execute(TaskList tasks, Ui ui, Storage storage) throws EddieExceptio break; case "deadline": String[] deadlineParts = taskDetails.split(" /by ", 2); - if (deadlineParts.length < 2) { + if (deadlineParts.length < 2 || deadlineParts[0].trim().isEmpty()) { + throw new EddieException(ErrorMessages.INVALID_DEADLINE); + } + try { + DateTimeFormatter inputFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm"); + LocalDateTime by = LocalDateTime.parse(deadlineParts[1].trim(), inputFormat); + tasks.addTask(new Deadline(deadlineParts[0].trim(), by)); + } catch (DateTimeParseException e) { throw new EddieException(ErrorMessages.INVALID_DEADLINE); } - tasks.addTask(new Deadline(deadlineParts[0], deadlineParts[1])); break; case "event": String[] eventParts = taskDetails.split(" /from ", 2); - if (eventParts.length < 2 || !eventParts[1].contains(" /to ")) { + if (eventParts.length < 2 || !eventParts[1].contains(" /to ") || eventParts[0].trim().isEmpty()) { throw new EddieException(ErrorMessages.INVALID_EVENT); } String[] timeParts = eventParts[1].split(" /to ", 2); - tasks.addTask(new Event(eventParts[0], timeParts[0], timeParts[1])); + try { + DateTimeFormatter inputFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm"); + LocalDateTime from = LocalDateTime.parse(timeParts[0].trim(), inputFormat); + LocalDateTime to = LocalDateTime.parse(timeParts[1].trim(), inputFormat); + tasks.addTask(new Event(eventParts[0].trim(), from, to)); + } catch (DateTimeParseException e) { + throw new EddieException(ErrorMessages.INVALID_EVENT); + } break; default: throw new EddieException(ErrorMessages.INVALID_COMMAND); diff --git a/src/main/java/storage/Storage.java b/src/main/java/storage/Storage.java index d1d0f12c7..1f831486a 100644 --- a/src/main/java/storage/Storage.java +++ b/src/main/java/storage/Storage.java @@ -9,18 +9,18 @@ import ui.ErrorMessages; import java.io.*; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; public class Storage { private final String filePath; + private static final DateTimeFormatter dateTimeFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm"); public Storage(String filePath) { this.filePath = filePath; } - /** - * Loads tasks from the storage file. - */ public ArrayList loadTask() throws EddieException { ArrayList tasks = new ArrayList<>(); File file = new File(filePath); @@ -42,9 +42,6 @@ public ArrayList loadTask() throws EddieException { return tasks; } - /** - * Saves tasks to the storage file. - */ public void saveTasks(ArrayList tasks) { try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) { for (Task task : tasks) { @@ -56,9 +53,6 @@ public void saveTasks(ArrayList tasks) { } } - /** - * Parses a line from the file into a Task object. - */ private Task parseTask(String line) throws EddieException { try { String[] parts = line.split(" \\| "); @@ -70,9 +64,12 @@ private Task parseTask(String line) throws EddieException { case "T": return new Todo(description, isDone); case "D": - return new Deadline(description, parts[3], isDone); + LocalDateTime by = LocalDateTime.parse(parts[3], dateTimeFormat); + return new Deadline(description, by, isDone); case "E": - return new Event(description, parts[3], parts[4], isDone); + LocalDateTime from = LocalDateTime.parse(parts[3], dateTimeFormat); + LocalDateTime to = LocalDateTime.parse(parts[4], dateTimeFormat); + return new Event(description, from, to, isDone); default: throw new EddieException(ErrorMessages.TASK_TYPE_UNKNOWN + type); } @@ -81,9 +78,6 @@ private Task parseTask(String line) throws EddieException { } } - /** - * Creates the storage file and parent directories if they don't exist. - */ private void createFile() throws EddieException { File file = new File(filePath); File parent = file.getParentFile(); diff --git a/src/main/java/task/Deadline.java b/src/main/java/task/Deadline.java index 4a5379c30..33d5a2d3d 100644 --- a/src/main/java/task/Deadline.java +++ b/src/main/java/task/Deadline.java @@ -1,17 +1,19 @@ package task; -/** - * Represents a deadline task. - */ +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + public class Deadline extends Task { - private String by; + private final LocalDateTime by; + private static final DateTimeFormatter displayFormat = DateTimeFormatter.ofPattern("MMM d yyyy, h:mma"); + private static final DateTimeFormatter saveFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm"); - public Deadline(String description, String by) { + public Deadline(String description, LocalDateTime by) { super(description); this.by = by; } - public Deadline(String description, String by, boolean isDone) { + public Deadline(String description, LocalDateTime by, boolean isDone) { super(description, isDone); this.by = by; } @@ -23,11 +25,11 @@ public String getTaskType() { @Override public String toFileFormat() { - return "D | " + (isDone ? "1" : "0") + " | " + description + " | " + by; + return "D | " + (isDone ? "1" : "0") + " | " + description + " | " + by.format(saveFormat); } @Override public String toString() { - return super.toString() + " (by: " + by + ")"; + return super.toString() + " (by: " + by.format(displayFormat) + ")"; } } diff --git a/src/main/java/task/Event.java b/src/main/java/task/Event.java index e0cedf6d0..b8db42d2e 100644 --- a/src/main/java/task/Event.java +++ b/src/main/java/task/Event.java @@ -1,19 +1,21 @@ package task; -/** - * Represents an event task with a start and end time. - */ +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + public class Event extends Task { - private String from; - private String to; + private final LocalDateTime from; + private final LocalDateTime to; + private static final DateTimeFormatter displayFormat = DateTimeFormatter.ofPattern("MMM d yyyy, h:mma"); + private static final DateTimeFormatter saveFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm"); - public Event(String description, String from, String to) { + public Event(String description, LocalDateTime from, LocalDateTime to) { super(description); this.from = from; this.to = to; } - public Event(String description, String from, String to, boolean isDone) { + public Event(String description, LocalDateTime from, LocalDateTime to, boolean isDone) { super(description, isDone); this.from = from; this.to = to; @@ -26,11 +28,11 @@ public String getTaskType() { @Override public String toFileFormat() { - return "E | " + (isDone ? "1" : "0") + " | " + description + " | " + from + " | " + to; + return "E | " + (isDone ? "1" : "0") + " | " + description + " | " + from.format(saveFormat) + " | " + to.format(saveFormat); } @Override public String toString() { - return super.toString() + " (from: " + from + " to: " + to + ")"; + return super.toString() + " (from: " + from.format(displayFormat) + " to: " + to.format(displayFormat) + ")"; } } From a7cd70aff061334bf2b973e9e60abf3eb0552f64 Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Mon, 31 Mar 2025 00:05:01 +0800 Subject: [PATCH 19/25] Level 9. Find --- data/tasks.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/data/tasks.txt b/data/tasks.txt index adff0b7a5..0b8ad1d57 100644 --- a/data/tasks.txt +++ b/data/tasks.txt @@ -1,3 +1,4 @@ T | 0 | read D | 0 | submit assignment | 2025-04-01 1800 E | 0 | group meeting | 2025-04-02 1000 | 2025-04-02 1200 +T | 0 | read book From 08c89bfab4aa2884403f1a0c1bb7f476efee6e93 Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Mon, 31 Mar 2025 00:06:32 +0800 Subject: [PATCH 20/25] Level 9. Find --- src/main/java/command/FindCommand.java | 29 ++++++++++++++++++++++++++ src/main/java/parser/Parser.java | 2 ++ src/main/java/tasklist/TaskList.java | 11 ++++++++++ src/main/java/ui/Ui.java | 13 ++++++++++++ 4 files changed, 55 insertions(+) create mode 100644 src/main/java/command/FindCommand.java diff --git a/src/main/java/command/FindCommand.java b/src/main/java/command/FindCommand.java new file mode 100644 index 000000000..cbb748971 --- /dev/null +++ b/src/main/java/command/FindCommand.java @@ -0,0 +1,29 @@ +package command; + +import storage.Storage; +import tasklist.TaskList; +import ui.Ui; +import task.Task; + +import java.util.ArrayList; +import java.util.List; + +public class FindCommand extends Command { + private final String keyword; + + public FindCommand(String keyword) { + this.keyword = keyword; + } + + @Override + public void execute (TaskList tasks, Ui ui, Storage storage) { + List matchedTasks = new ArrayList<>(); + + for (Task task: tasks.getAllTasks()) { + if (task.getDescription().toLowerCase().contains(keyword.toLowerCase())) { + matchedTasks.add(task); + } + } + ui.showMatchingTasks(matchedTasks); + } +} diff --git a/src/main/java/parser/Parser.java b/src/main/java/parser/Parser.java index 3f873f856..bca3de501 100644 --- a/src/main/java/parser/Parser.java +++ b/src/main/java/parser/Parser.java @@ -31,6 +31,8 @@ public static Command parse(String input) throws EddieException { return new MarkCommand(arguments, false); case "delete": return new DeleteCommand(arguments); + case "find": + return new FindCommand(arguments); case "bye": return new ExitCommand(); default: diff --git a/src/main/java/tasklist/TaskList.java b/src/main/java/tasklist/TaskList.java index 8b28c1828..0f7d84f57 100644 --- a/src/main/java/tasklist/TaskList.java +++ b/src/main/java/tasklist/TaskList.java @@ -4,6 +4,7 @@ import command.EddieException; import java.util.ArrayList; +import java.util.List; /** * Manages a list of tasks. @@ -116,4 +117,14 @@ public String getTaskListString() { } return list.toString(); } + + public List findTasks(String Keyword){ + List tasks = new ArrayList<>(); + for (Task task : tasks) { + if (task.getDescription().toLowerCase().contains(Keyword.toLowerCase())) { + tasks.add(task); + } + } + return tasks; + } } diff --git a/src/main/java/ui/Ui.java b/src/main/java/ui/Ui.java index c0a46f499..5d7dc40d3 100644 --- a/src/main/java/ui/Ui.java +++ b/src/main/java/ui/Ui.java @@ -2,6 +2,7 @@ import task.Task; import java.util.ArrayList; +import java.util.List; import java.util.Scanner; public class Ui { @@ -90,4 +91,16 @@ public String readCommand() { System.out.print("You: "); return scanner.nextLine().trim(); } + + public void showMatchingTasks(List matchedTasks) { + System.out.println("Eddie:\nHere are the tasks matching your list:"); + if (matchedTasks.isEmpty()) { + System.out.println("No tasks matching your list."); + } + int index = 1; + for (Task task : matchedTasks) { + System.out.println(index + ". " + task); + index++; + } + } } From 205be7fa95ecce7b23b869fd818accd14103ffe9 Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Mon, 31 Mar 2025 00:45:06 +0800 Subject: [PATCH 21/25] A-JavaDoc: JavaDoc --- src/main/java/command/FindCommand.java | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/main/java/command/FindCommand.java b/src/main/java/command/FindCommand.java index cbb748971..8548c3840 100644 --- a/src/main/java/command/FindCommand.java +++ b/src/main/java/command/FindCommand.java @@ -8,22 +8,39 @@ import java.util.ArrayList; import java.util.List; +/** + * Finds and displays tasks that descriptions contain a given keyword. + */ public class FindCommand extends Command { private final String keyword; + /** + * Constructs a FindCommand with the specified keyword to search for. + * + * @param keyword The keyword used to search task descriptions. + */ public FindCommand(String keyword) { this.keyword = keyword; } + /** + * Executes the find command by searching task list for tasks that contain the same keyword + * in their description, and displays the matching tasks using the UI. + * + * @param tasks The TaskList containing the user's tasks. + * @param ui The Ui instance to handle user interaction. + * @param storage The Storage instance (not used here, but required by method signature). + */ @Override - public void execute (TaskList tasks, Ui ui, Storage storage) { + public void execute(TaskList tasks, Ui ui, Storage storage) { List matchedTasks = new ArrayList<>(); - for (Task task: tasks.getAllTasks()) { + for (Task task : tasks.getAllTasks()) { if (task.getDescription().toLowerCase().contains(keyword.toLowerCase())) { matchedTasks.add(task); } } + ui.showMatchingTasks(matchedTasks); } } From 0929cc2c07a97773d7f9aa6a5da2312613caf882 Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Mon, 31 Mar 2025 18:59:41 +0800 Subject: [PATCH 22/25] A-UserGuide --- data/tasks.txt | 3 + docs/README.md | 155 +++++++++++++++++++++++++++++++++++---- src/main/java/ui/Ui.java | 3 +- 3 files changed, 147 insertions(+), 14 deletions(-) diff --git a/data/tasks.txt b/data/tasks.txt index 0b8ad1d57..e515d27d8 100644 --- a/data/tasks.txt +++ b/data/tasks.txt @@ -2,3 +2,6 @@ T | 0 | read D | 0 | submit assignment | 2025-04-01 1800 E | 0 | group meeting | 2025-04-02 1000 | 2025-04-02 1200 T | 0 | read book +T | 0 | read book +D | 0 | return book | 2025-04-01 1800 +E | 0 | group project meeting | 2025-04-02 1400 | 2025-04-02 1600 diff --git a/docs/README.md b/docs/README.md index 47b9f984f..f6debb189 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,30 +1,159 @@ -# Duke User Guide +# Eddie Task Manager! +``` + _____ ____ ____ ___ _____ +| ____|| _ \ | _ \ |_ _|| ____| +| |_ | | | || | | | | | | |_ +| _| | | | || | | | | | | |_| +| |___ | |_| || |_| | | | | |___ +|_____||____/ |____/ |___||_____| + +Eddie: Welcome to your personal task manager! +I can help you manage different types of tasks. +``` + +# Eddie User Guide + +## Introduction -// Update the title above to match the actual product name +**Eddie** is a command-line based chatbot designed to help you organize your tasks. Whether it’s a **Todo**, a **Deadline**, or an **Event** Eddie has you covered! Eddie understands natural-like commands and can **add, list, delete, mark, unmark, find** and even **remember your tasks between sessions** with **date parsing** and **search** features! -// Product screenshot goes here +--- +# Features +## Adding Tasks -// Product intro goes here +### Add ToDo, Deadline, or Event Tasks + +- `todo {description}` – Adds a ToDo task +- `deadline {description} /by {yyyy-MM-dd HHmm}` – Adds a Deadline +- `event {description} /from {yyyy-MM-dd HHmm} /to {yyyy-MM-dd HHmm}` – Adds an Event -## Adding deadlines // Describe the action and its outcome. -// Give examples of usage +Example: adding tasks +``` +____________________________________________________________ +You: todo read book +____________________________________________________________ +Eddie: +Got it. I've added this task: + [T][ ] read book +Now you have 1 task in the list. +____________________________________________________________ +``` +``` +____________________________________________________________ +You: deadline return book /by 2025-04-01 1800 +____________________________________________________________ +Eddie: +Got it. I've added this task: + [D][ ] return book (by: Apr 1 2025, 6:00pm) +Now you have 2 tasks in the list. +____________________________________________________________ +``` +``` +__________________________________________________________________________________ +You: event group project meeting /from 2025-04-02 1400 /to 2025-04-02 1600 +__________________________________________________________________________________ +Eddie: +Got it. I've added this task: + [E][ ] group project meeting (from: Apr 2 2025, 2:00pm to: Apr 2 2025, 4:00pm) +Now you have 3 tasks in the list. +__________________________________________________________________________________ +``` + +--- + +### List All Tasks + +- `list` – Shows all tasks currently tracked. + +#### Example: +``` +__________________________________________________________________________________ +You: list +__________________________________________________________________________________ +Eddie: +Here are the tasks in your list: +1. [T][ ] read book +2. [D][ ] return book (by: Apr 1 2025, 6:00pm) +3. [E][ ] group project meeting (from: Apr 2 2025, 2:00pm to: Apr 2 2025, 4:00pm) +__________________________________________________________________________________ +``` + +--- -Example: `keyword (optional arguments)` +### Mark/Unmark Tasks -// A description of the expected outcome goes here +- `mark {task number}` – Mark a task as done +- `unmark {task number}` – Mark a task as not done +#### Example: ``` -expected output +____________________________________________________________ +You: mark 1 +____________________________________________________________ +Eddie: +Oh no! Marked as not done: + [T][ ] read book +____________________________________________________________ +You: unmark 1 +____________________________________________________________ +Eddie: +Oh no! Marked as not done: + [T][ ] read book ``` -## Feature ABC +--- + +### Delete a Task + +- `delete {task number}` – Deletes the selected task from the list. + +#### Example: +``` +____________________________________________________________ +You: delete 2 +____________________________________________________________ +Eddie: +Noted. I've removed this task: + [D][ ] return book (by: Apr 1 2025, 6:00pm) +Now you have 2 tasks in the list. +____________________________________________________________ +``` + +--- + +### Find Tasks + +- `find {keyword}` – Search and display tasks that match the keyword. + +#### Example: +``` +____________________________________________________________ +You: find book +____________________________________________________________ +Eddie: +Here are the tasks matching your list: +1. [T][ ] read book +2. [D][ ] return book (by: Apr 1 2025, 6:00pm) +____________________________________________________________ +``` + +--- + +### Storage + +Eddie saves your task list in a text file at `data/tasks.txt`, and loads it every time you start the app. + +--- -// Feature details +## How to Use +1. Clone this repo and build the project in your IDE +2. Run `Eddie.java`. +3. Interact with Eddie through the terminal using the supported commands above. +4. Exit using the command `bye`. -## Feature XYZ +--- -// Feature details \ No newline at end of file diff --git a/src/main/java/ui/Ui.java b/src/main/java/ui/Ui.java index 5d7dc40d3..c7e824b5f 100644 --- a/src/main/java/ui/Ui.java +++ b/src/main/java/ui/Ui.java @@ -35,6 +35,7 @@ public void showStartPage() { System.out.println("Mark as done: `mark 2`"); System.out.println("Unmark: `unmark 2`"); System.out.println("Delete: `delete 2`"); + System.out.println("Find tasks: `find {keyword}`"); System.out.println("Exit: `bye`"); printLine(); } @@ -80,7 +81,7 @@ public void showError(String msg) { } public void printLine() { - System.out.println("____________________________________________________________"); + System.out.println("_____________________________________________________________________"); } public void showLoadingError() { From db618cb3f6e0709a1a6f9eb8b3a271fb55a5462f Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Mon, 31 Mar 2025 19:01:33 +0800 Subject: [PATCH 23/25] A-UserGuide updated --- docs/README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index f6debb189..05a89fa7c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -28,8 +28,6 @@ I can help you manage different types of tasks. - `event {description} /from {yyyy-MM-dd HHmm} /to {yyyy-MM-dd HHmm}` – Adds an Event -// Describe the action and its outcome. - Example: adding tasks ``` ____________________________________________________________ @@ -102,6 +100,7 @@ ____________________________________________________________ Eddie: Oh no! Marked as not done: [T][ ] read book +____________________________________________________________ ``` --- From 26414e0a668c20045dccf821e31f96e0580f191f Mon Sep 17 00:00:00 2001 From: EdwinTun98 <143373951+EdwinTun98@users.noreply.github.com> Date: Mon, 31 Mar 2025 19:04:05 +0800 Subject: [PATCH 24/25] Create _config.yml added theme --- docs/_config.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/_config.yml diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 000000000..bad826676 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-midnight From efd9e144515003d74759e9f96c2a1ca2f0d2214b Mon Sep 17 00:00:00 2001 From: EdwinTun98 Date: Mon, 31 Mar 2025 19:08:33 +0800 Subject: [PATCH 25/25] A-UserGuide updated 2 --- docs/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index 05a89fa7c..dc50d4d66 100644 --- a/docs/README.md +++ b/docs/README.md @@ -92,8 +92,9 @@ ____________________________________________________________ You: mark 1 ____________________________________________________________ Eddie: -Oh no! Marked as not done: - [T][ ] read book +Yay! Marked as done: + [T][X] read book +Have a Beer!! ____________________________________________________________ You: unmark 1 ____________________________________________________________