From 356f7d26b810c175c65988a7a3a9135e358acfa2 Mon Sep 17 00:00:00 2001 From: TeddYE Date: Sun, 23 Jan 2022 17:30:22 +0800 Subject: [PATCH 01/32] Duke class: implement level 1 functionalities Let's implement a skeletal version of Duke that starts by greeting the user, simply echoes commands entered by the user, and exits when the user types bye. --- src/main/java/Duke.java | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 5d313334cc..bad3db45e0 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,10 +1,28 @@ +import java.util.Scanner; + public class Duke { + public static final String WELCOME_MESSAGE = "Hello! I'm Duke\nWhat can I do for you"; + public static final String GOODBYE_MESSAGE = "Bye. Hope to see you again soon!"; + public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); + Scanner sc = new Scanner(System.in); + boolean isExit = false; + + System.out.println(WELCOME_MESSAGE); + while (true) { + String userInput = sc.nextLine(); + switch (userInput) { + case "bye": + isExit = true; + System.out.println(GOODBYE_MESSAGE); + break; + default: + System.out.println(userInput); + break; + } + if (isExit) { + break; + } + } } } From 5741e288c50ac97ab437fbe9ba348dfb322bf791 Mon Sep 17 00:00:00 2001 From: TeddYE Date: Sun, 23 Jan 2022 18:10:08 +0800 Subject: [PATCH 02/32] Duke class: Implement level 2 functionalities Let's add the ability to store whatever text entered by the user and display them back to the user when requested. --- src/main/java/Duke.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index bad3db45e0..61a50e1c0e 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,8 +1,10 @@ +import java.util.ArrayList; import java.util.Scanner; public class Duke { - public static final String WELCOME_MESSAGE = "Hello! I'm Duke\nWhat can I do for you"; - public static final String GOODBYE_MESSAGE = "Bye. Hope to see you again soon!"; + private static final String WELCOME_MESSAGE = "Hello! I'm Duke\nWhat can I do for you"; + private static final String GOODBYE_MESSAGE = "Bye. Hope to see you again soon!"; + private static final ArrayList TO_DO_LIST = new ArrayList<>(); public static void main(String[] args) { Scanner sc = new Scanner(System.in); @@ -16,8 +18,14 @@ public static void main(String[] args) { isExit = true; System.out.println(GOODBYE_MESSAGE); break; + case "list": + for (int i = 0; i < TO_DO_LIST.size(); i++) { + System.out.println(String.format("%d. %s", i + 1, TO_DO_LIST.get(i))); + } + break; default: - System.out.println(userInput); + TO_DO_LIST.add(userInput); + System.out.println(String.format("added: %s", userInput)); break; } if (isExit) { From ad6aed9cefd0703f91b2d5738d49792aa1512b3d Mon Sep 17 00:00:00 2001 From: TeddYE Date: Sun, 23 Jan 2022 18:23:44 +0800 Subject: [PATCH 03/32] Duke class: remove redundant codes Let's, * move the conditional break in the infinite loop into the loop condition * remove String.format() --- src/main/java/Duke.java | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 61a50e1c0e..2646458500 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -11,25 +11,22 @@ public static void main(String[] args) { boolean isExit = false; System.out.println(WELCOME_MESSAGE); - while (true) { + while (!isExit) { String userInput = sc.nextLine(); switch (userInput) { - case "bye": - isExit = true; - System.out.println(GOODBYE_MESSAGE); - break; - case "list": - for (int i = 0; i < TO_DO_LIST.size(); i++) { - System.out.println(String.format("%d. %s", i + 1, TO_DO_LIST.get(i))); - } - break; - default: - TO_DO_LIST.add(userInput); - System.out.println(String.format("added: %s", userInput)); - break; - } - if (isExit) { - break; + case "bye": + isExit = true; + System.out.println(GOODBYE_MESSAGE); + break; + case "list": + for (int i = 0; i < TO_DO_LIST.size(); i++) { + System.out.printf("%d. %s%n", i + 1, TO_DO_LIST.get(i)); + } + break; + default: + TO_DO_LIST.add(userInput); + System.out.printf("added: %s%n", userInput); + break; } } } From 44b496ef69733ca45426672c41bde96fd136ab89 Mon Sep 17 00:00:00 2001 From: TeddYE Date: Mon, 24 Jan 2022 12:00:23 +0800 Subject: [PATCH 04/32] Duke class: Implement Level-3 functionalities Lets, * add Task class to represent tasks * add the ability to mark tasks as done and the ability to change the status back to not done --- src/main/java/Duke.java | 26 +++++++++++++++++++++----- src/main/java/Task.java | 26 ++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 src/main/java/Task.java diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 2646458500..89ab3f7414 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,10 +1,11 @@ +import java.lang.annotation.Target; import java.util.ArrayList; import java.util.Scanner; public class Duke { - private static final String WELCOME_MESSAGE = "Hello! I'm Duke\nWhat can I do for you"; + private static final String WELCOME_MESSAGE = "Hello! I'm Duke \n" + "What can I do for you"; private static final String GOODBYE_MESSAGE = "Bye. Hope to see you again soon!"; - private static final ArrayList TO_DO_LIST = new ArrayList<>(); + private static final ArrayList TO_DO_LIST = new ArrayList<>(); public static void main(String[] args) { Scanner sc = new Scanner(System.in); @@ -12,7 +13,7 @@ public static void main(String[] args) { System.out.println(WELCOME_MESSAGE); while (!isExit) { - String userInput = sc.nextLine(); + String userInput = sc.next(); switch (userInput) { case "bye": isExit = true; @@ -20,11 +21,26 @@ public static void main(String[] args) { break; case "list": for (int i = 0; i < TO_DO_LIST.size(); i++) { - System.out.printf("%d. %s%n", i + 1, TO_DO_LIST.get(i)); + System.out.printf("%d.%s%n", i + 1, TO_DO_LIST.get(i)); } break; + case "mark": + int markIndex = sc.nextInt() - 1; + Task markTask = TO_DO_LIST.get(markIndex); + markTask.setIsDone(true); + System.out.printf("Nice! I've marked this task as done: \n" + + " %s\n", markTask); + break; + case "unmark": + int unmarkIndex = sc.nextInt() - 1; + Task unmarkTask = TO_DO_LIST.get(unmarkIndex); + unmarkTask.setIsDone(false); + System.out.printf("Ok, I've marked this task as not done yet: \n" + + " %s\n", unmarkTask); + break; default: - TO_DO_LIST.add(userInput); + Task t = new Task(userInput); + TO_DO_LIST.add(t); System.out.printf("added: %s%n", userInput); break; } diff --git a/src/main/java/Task.java b/src/main/java/Task.java new file mode 100644 index 0000000000..4cc54f1e71 --- /dev/null +++ b/src/main/java/Task.java @@ -0,0 +1,26 @@ +public class Task { + protected String description; + protected boolean isDone; + + public Task(String description) { + this.description = description; + this.isDone = false; + } + + public String getDescription() { + return this.description; + } + + public String getStatusIcon() { + return (isDone ? "X" : " "); + } + + public void setIsDone(boolean isDone) { + this.isDone = isDone; + } + + @Override + public String toString() { + return String.format("[%s] %s", this.getStatusIcon(), this.getDescription()); + } +} From ae02dd360cf8a8e8a0bb83cb681d79be226c6668 Mon Sep 17 00:00:00 2001 From: TeddYE Date: Mon, 24 Jan 2022 16:30:31 +0800 Subject: [PATCH 05/32] Duke class: implement Level-4 functionalities As there are multiple types of tasks that have some similarity between them, implement classes Todo, Deadline and Event classes to inherit from a Task class. Let's, * add support for tracking three types of task --- src/main/java/Duke.java | 57 +++++++++++++++++++++++--------- src/main/java/Task.java | 26 --------------- src/main/java/task/Deadline.java | 19 +++++++++++ src/main/java/task/Event.java | 19 +++++++++++ src/main/java/task/Task.java | 56 +++++++++++++++++++++++++++++++ src/main/java/task/ToDo.java | 7 ++++ 6 files changed, 142 insertions(+), 42 deletions(-) delete mode 100644 src/main/java/Task.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 diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 89ab3f7414..944ffc1173 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,11 +1,13 @@ -import java.lang.annotation.Target; -import java.util.ArrayList; +import task.Deadline; +import task.Event; +import task.Task; +import task.ToDo; + import java.util.Scanner; public class Duke { private static final String WELCOME_MESSAGE = "Hello! I'm Duke \n" + "What can I do for you"; private static final String GOODBYE_MESSAGE = "Bye. Hope to see you again soon!"; - private static final ArrayList TO_DO_LIST = new ArrayList<>(); public static void main(String[] args) { Scanner sc = new Scanner(System.in); @@ -13,35 +15,58 @@ public static void main(String[] args) { System.out.println(WELCOME_MESSAGE); while (!isExit) { - String userInput = sc.next(); - switch (userInput) { + String userCommand = sc.next(); + switch (userCommand) { case "bye": isExit = true; System.out.println(GOODBYE_MESSAGE); break; case "list": - for (int i = 0; i < TO_DO_LIST.size(); i++) { - System.out.printf("%d.%s%n", i + 1, TO_DO_LIST.get(i)); + for (int i = 0; i < Task.getTasks().size(); i++) { + System.out.printf("%d.%s%n", i + 1, Task.getTasks().get(i)); } break; case "mark": int markIndex = sc.nextInt() - 1; - Task markTask = TO_DO_LIST.get(markIndex); + Task markTask = Task.getTasks().get(markIndex); markTask.setIsDone(true); - System.out.printf("Nice! I've marked this task as done: \n" + - " %s\n", markTask); + System.out.printf("Nice! I've marked this task as done: \n" + + " %s\n", markTask); break; case "unmark": int unmarkIndex = sc.nextInt() - 1; - Task unmarkTask = TO_DO_LIST.get(unmarkIndex); + Task unmarkTask = Task.getTasks().get(unmarkIndex); unmarkTask.setIsDone(false); - System.out.printf("Ok, I've marked this task as not done yet: \n" + - " %s\n", unmarkTask); + System.out.printf("Ok, I've marked this task as not done yet: \n" + + " %s\n", unmarkTask); + break; + case "todo": + String toDoDescription = sc.nextLine().trim(); + Task newToDo = new ToDo(toDoDescription); + Task.addTask(newToDo); + System.out.printf("Got it. I've added this task:\n" + "%s\n" + "%s\n", + newToDo, Task.taskCountToString()); + break; + case "deadline": + String deadlineTempInput = sc.nextLine(); + String deadlineDescription = deadlineTempInput.split("/by", 2)[0].trim(); + String deadlineDueDate = deadlineTempInput.split("/by", 2)[1].trim(); + Task newDeadline = new Deadline(deadlineDescription, deadlineDueDate); + Task.addTask(newDeadline); + System.out.printf("Got it. I've added this task:\n" + "%s\n" + "%s\n", + newDeadline, Task.taskCountToString()); + break; + case "event": + String eventTempInput = sc.nextLine(); + String eventDescription = eventTempInput.split("/at", 2)[0].trim(); + String eventDateTime = eventTempInput.split("/at", 2)[1].trim(); + Task newEvent = new Event(eventDescription.toString(), eventDateTime.toString()); + Task.addTask(newEvent); + System.out.printf("Got it. I've added this task:\n" + "%s\n" + "%s\n", + newEvent, Task.taskCountToString()); break; default: - Task t = new Task(userInput); - TO_DO_LIST.add(t); - System.out.printf("added: %s%n", userInput); + System.out.printf("Unknown command.\n"); break; } } diff --git a/src/main/java/Task.java b/src/main/java/Task.java deleted file mode 100644 index 4cc54f1e71..0000000000 --- a/src/main/java/Task.java +++ /dev/null @@ -1,26 +0,0 @@ -public class Task { - protected String description; - protected boolean isDone; - - public Task(String description) { - this.description = description; - this.isDone = false; - } - - public String getDescription() { - return this.description; - } - - public String getStatusIcon() { - return (isDone ? "X" : " "); - } - - public void setIsDone(boolean isDone) { - this.isDone = isDone; - } - - @Override - public String toString() { - return String.format("[%s] %s", this.getStatusIcon(), this.getDescription()); - } -} diff --git a/src/main/java/task/Deadline.java b/src/main/java/task/Deadline.java new file mode 100644 index 0000000000..7c8f0e9249 --- /dev/null +++ b/src/main/java/task/Deadline.java @@ -0,0 +1,19 @@ +package task; + +public class Deadline extends Task{ + protected String deadline; + + public Deadline(String description, String deadline) { + super(description, "D"); + this.deadline = deadline; + } + + public String getDeadline() { + return this.deadline; + } + + @Override + public String toString() { + return super.toString() + String.format(" (by: %s)", this.getDeadline()); + } +} diff --git a/src/main/java/task/Event.java b/src/main/java/task/Event.java new file mode 100644 index 0000000000..d6c16587ab --- /dev/null +++ b/src/main/java/task/Event.java @@ -0,0 +1,19 @@ +package task; + +public class Event extends Task{ + protected String eventTime; + + public Event(String description, String eventTime) { + super(description, "E"); + this.eventTime = eventTime; + } + + public String getEventTime() { + return this.eventTime; + } + + @Override + public String toString() { + return super.toString() + String.format(" (at: %s)", this.getEventTime()); + } +} diff --git a/src/main/java/task/Task.java b/src/main/java/task/Task.java new file mode 100644 index 0000000000..e458e0a92d --- /dev/null +++ b/src/main/java/task/Task.java @@ -0,0 +1,56 @@ +package task; + +import java.util.ArrayList; + +public abstract class Task { + protected String description; + protected String taskType; + protected boolean isDone; + + protected static final ArrayList TASKS = new ArrayList<>(); + + public Task(String description, String taskType) { + this.description = description; + this.taskType = taskType; + this.isDone = false; + } + + public static ArrayList getTasks() { + return Task.TASKS; + } + + public static void addTask(Task newTask) { + Task.TASKS.add(newTask); + } + + public static Task getTask(int taskIndex) { + return Task.TASKS.get(taskIndex); + } + + public static int getTaskCount() { + return Task.TASKS.size(); + } + + public static String taskCountToString() { + return String.format("Now you have %d task(s) in the list.", Task.getTaskCount()); + } + + public String getDescription() { + return this.description; + } + + public String getTaskType() { return this.taskType; } + + public String getStatusIcon() { + return (isDone ? "X" : " "); + } + + public void setIsDone(boolean isDone) { + this.isDone = isDone; + } + + @Override + public String toString() { + return String.format("[%s][%s] %s", this.getTaskType(), this.getStatusIcon(), this.getDescription()); + } +} \ No newline at end of file diff --git a/src/main/java/task/ToDo.java b/src/main/java/task/ToDo.java new file mode 100644 index 0000000000..f9de2495c5 --- /dev/null +++ b/src/main/java/task/ToDo.java @@ -0,0 +1,7 @@ +package task; + +public class ToDo extends Task{ + public ToDo(String description) { + super(description, "T"); + } +} From bee688affdb632e9a92a587ff8f6790c0bf54ddd Mon Sep 17 00:00:00 2001 From: TeddYE Date: Mon, 24 Jan 2022 16:39:47 +0800 Subject: [PATCH 06/32] Update i/o files for testing Use the input/output redirection technique to semi-automate the testing of Duke. --- text-ui-test/EXPECTED.TXT | 32 ++++++++++++++++++++++++++------ text-ui-test/input.txt | 9 +++++++++ 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 657e74f6e7..c4b860178d 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,7 +1,27 @@ -Hello from - ____ _ -| _ \ _ _| | _____ -| | | | | | | |/ / _ \ -| |_| | |_| | < __/ -|____/ \__,_|_|\_\___| +Hello! I'm Duke +What can I do for you +Got it. I've added this task: +[T][ ] borrow book +Now you have 1 task(s) in the list. +Got it. I've added this task: +[D][ ] return book (by:Sunday) +Now you have 2 task(s) in the list. +Got it. I've added this task: +[E][ ] project meeting (at:Mon 2-4pm) +Now you have 3 task(s) in the list. +1.[T][ ] borrow book +2.[D][ ] return book (by:Sunday) +3.[E][ ] project meeting (at:Mon 2-4pm) +Nice! I've marked this task as done: + [D][X] return book (by:Sunday) +1.[T][ ] borrow book +2.[D][X] return book (by:Sunday) +3.[E][ ] project meeting (at:Mon 2-4pm) +Ok, I've marked this task as not done yet: + [D][ ] return book (by:Sunday) +1.[T][ ] borrow book +2.[D][ ] return book (by:Sunday) +3.[E][ ] project meeting (at:Mon 2-4pm) +Bye. Hope to see you again soon! + diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index e69de29bb2..00f7a31730 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -0,0 +1,9 @@ +todo borrow book +deadline return book /by Sunday +event project meeting /at Mon 2-4pm +list +mark 2 +list +unmark 2 +list +bye \ No newline at end of file From 6fe8ceb448cb7ec7296dfffc6ad71e79b06b22ab Mon Sep 17 00:00:00 2001 From: TeddYE Date: Sat, 29 Jan 2022 15:02:47 +0800 Subject: [PATCH 07/32] Duke class: implement level-5 functionalities Teach Duke to deal with errors such as incorrect inputs entered by the user. Let's * add DukeException class --- src/main/java/Duke.java | 90 +++++++++++++++++++++++--------- src/main/java/DukeException.java | 5 ++ 2 files changed, 71 insertions(+), 24 deletions(-) create mode 100644 src/main/java/DukeException.java diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 944ffc1173..43841795e4 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -9,7 +9,7 @@ public class Duke { private static final String WELCOME_MESSAGE = "Hello! I'm Duke \n" + "What can I do for you"; private static final String GOODBYE_MESSAGE = "Bye. Hope to see you again soon!"; - public static void main(String[] args) { + public static void main(String[] args) throws DukeException { Scanner sc = new Scanner(System.in); boolean isExit = false; @@ -28,45 +28,87 @@ public static void main(String[] args) { break; case "mark": int markIndex = sc.nextInt() - 1; - Task markTask = Task.getTasks().get(markIndex); - markTask.setIsDone(true); - System.out.printf("Nice! I've marked this task as done: \n" - + " %s\n", markTask); - break; + try { + Task markTask = Task.getTasks().get(markIndex); + markTask.setIsDone(true); + System.out.printf("Nice! I've marked this task as done: \n" + + " %s\n", markTask); + break; + } catch (IndexOutOfBoundsException indexErr) { + DukeException e = new DukeException("☹ OOPS!!! Invalid index."); + System.out.println(e.getMessage()); + } case "unmark": int unmarkIndex = sc.nextInt() - 1; - Task unmarkTask = Task.getTasks().get(unmarkIndex); - unmarkTask.setIsDone(false); - System.out.printf("Ok, I've marked this task as not done yet: \n" - + " %s\n", unmarkTask); - break; + try { + Task unmarkTask = Task.getTasks().get(unmarkIndex); + unmarkTask.setIsDone(false); + System.out.printf("Ok, I've marked this task as not done yet: \n" + + " %s\n", unmarkTask); + break; + } catch (IndexOutOfBoundsException indexErr) { + DukeException e = new DukeException("☹ OOPS!!! Invalid index."); + System.out.println(e.getMessage()); + } case "todo": String toDoDescription = sc.nextLine().trim(); - Task newToDo = new ToDo(toDoDescription); - Task.addTask(newToDo); - System.out.printf("Got it. I've added this task:\n" + "%s\n" + "%s\n", - newToDo, Task.taskCountToString()); + if (toDoDescription.equals("")) { + DukeException e = new DukeException("☹ OOPS!!! The description of a todo cannot be empty."); + System.out.println(e.getMessage()); + } else { + Task newToDo = new ToDo(toDoDescription); + Task.addTask(newToDo); + System.out.printf("Got it. I've added this task:\n" + "%s\n" + "%s\n", + newToDo, Task.taskCountToString()); + } break; case "deadline": String deadlineTempInput = sc.nextLine(); + if(!deadlineTempInput.contains("/by")) { + DukeException e = new DukeException("The additional info doesn't fit the input format."); + System.out.println(e.getMessage()); + break; + } String deadlineDescription = deadlineTempInput.split("/by", 2)[0].trim(); String deadlineDueDate = deadlineTempInput.split("/by", 2)[1].trim(); - Task newDeadline = new Deadline(deadlineDescription, deadlineDueDate); - Task.addTask(newDeadline); - System.out.printf("Got it. I've added this task:\n" + "%s\n" + "%s\n", - newDeadline, Task.taskCountToString()); + if (deadlineDescription.equals("")) { + DukeException e = new DukeException("☹ OOPS!!! The description of a deadline cannot be empty."); + System.out.println(e.getMessage()); + } else if (deadlineDueDate.equals("")) { + DukeException e = new DukeException("☹ OOPS!!! The due date of a deadline cannot be empty."); + System.out.println(e.getMessage()); + } else { + Task newDeadline = new Deadline(deadlineDescription, deadlineDueDate); + Task.addTask(newDeadline); + System.out.printf("Got it. I've added this task:\n" + "%s\n" + "%s\n", + newDeadline, Task.taskCountToString()); + } break; case "event": String eventTempInput = sc.nextLine(); + if(!eventTempInput.contains("/at")) { + DukeException e = new DukeException("The additional info doesn't fit the input format."); + System.out.println(e.getMessage()); + break; + } String eventDescription = eventTempInput.split("/at", 2)[0].trim(); String eventDateTime = eventTempInput.split("/at", 2)[1].trim(); - Task newEvent = new Event(eventDescription.toString(), eventDateTime.toString()); - Task.addTask(newEvent); - System.out.printf("Got it. I've added this task:\n" + "%s\n" + "%s\n", - newEvent, Task.taskCountToString()); + if (eventDescription.equals("")) { + DukeException e = new DukeException("☹ OOPS!!! The description of an event cannot be empty."); + System.out.println(e.getMessage()); + } else if (eventDateTime.equals("")) { + DukeException e = new DukeException("☹ OOPS!!! The date/time of an event cannot be empty."); + System.out.println(e.getMessage()); + } else { + Task newEvent = new Event(eventDescription, eventDateTime); + Task.addTask(newEvent); + System.out.printf("Got it. I've added this task:\n" + "%s\n" + "%s\n", + newEvent, Task.taskCountToString()); + } break; default: - System.out.printf("Unknown command.\n"); + DukeException e = new DukeException("☹ OOPS!!! I'm sorry, but I don't know what that means :-("); + System.out.println(e.getMessage()); break; } } diff --git a/src/main/java/DukeException.java b/src/main/java/DukeException.java new file mode 100644 index 0000000000..520e7f7b1e --- /dev/null +++ b/src/main/java/DukeException.java @@ -0,0 +1,5 @@ +public class DukeException extends Exception{ + public DukeException (String errorMessage){ + super(errorMessage); + } +} From 3910a1f307a6356050a17a62bffb8a7913762c87 Mon Sep 17 00:00:00 2001 From: TeddYE Date: Sat, 29 Jan 2022 15:10:35 +0800 Subject: [PATCH 08/32] Duke class: implement level-6 functionalities Let's * Add support for deleting tasks from the list --- src/main/java/Duke.java | 19 +++++++++++++++++-- src/main/java/task/Task.java | 2 ++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 43841795e4..9e87e67f23 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -32,24 +32,39 @@ public static void main(String[] args) throws DukeException { Task markTask = Task.getTasks().get(markIndex); markTask.setIsDone(true); System.out.printf("Nice! I've marked this task as done: \n" - + " %s\n", markTask); + + " %s\n", markTask); break; } catch (IndexOutOfBoundsException indexErr) { DukeException e = new DukeException("☹ OOPS!!! Invalid index."); System.out.println(e.getMessage()); } + break; case "unmark": int unmarkIndex = sc.nextInt() - 1; try { Task unmarkTask = Task.getTasks().get(unmarkIndex); unmarkTask.setIsDone(false); System.out.printf("Ok, I've marked this task as not done yet: \n" - + " %s\n", unmarkTask); + + " %s\n", unmarkTask); break; } catch (IndexOutOfBoundsException indexErr) { DukeException e = new DukeException("☹ OOPS!!! Invalid index."); System.out.println(e.getMessage()); } + break; + case "delete": + int deleteIndex = sc.nextInt() - 1; + try { + Task deleteTask = Task.getTasks().get(deleteIndex); + Task.deleteTask(deleteIndex); + System.out.printf("Noted. I've removed this task: \n" + " %s\n" + + "%s\n", deleteTask, Task.taskCountToString()); + break; + } catch (IndexOutOfBoundsException indexErr) { + DukeException e = new DukeException("☹ OOPS!!! Invalid index."); + System.out.println(e.getMessage()); + } + break; case "todo": String toDoDescription = sc.nextLine().trim(); if (toDoDescription.equals("")) { diff --git a/src/main/java/task/Task.java b/src/main/java/task/Task.java index e458e0a92d..c2c236efe7 100644 --- a/src/main/java/task/Task.java +++ b/src/main/java/task/Task.java @@ -23,6 +23,8 @@ public static void addTask(Task newTask) { Task.TASKS.add(newTask); } + public static void deleteTask(int taskIndex) { Task.TASKS.remove(taskIndex); } + public static Task getTask(int taskIndex) { return Task.TASKS.get(taskIndex); } From 8874be8c183df0b97530b58d072f184a4eb3e18d Mon Sep 17 00:00:00 2001 From: TeddYE Date: Sat, 29 Jan 2022 15:42:11 +0800 Subject: [PATCH 09/32] Implement A-Enums functionalities Let's: * use enum for types of tasks --- src/main/java/Duke.java | 8 ++++---- src/main/java/enums/TaskType.java | 16 ++++++++++++++++ src/main/java/task/ToDo.java | 7 ------- src/main/java/{task => tasks}/Deadline.java | 6 ++++-- src/main/java/{task => tasks}/Event.java | 6 ++++-- src/main/java/{task => tasks}/Task.java | 9 +++++---- src/main/java/tasks/ToDo.java | 9 +++++++++ text-ui-test/EXPECTED.TXT | 16 ++++++++-------- 8 files changed, 50 insertions(+), 27 deletions(-) create mode 100644 src/main/java/enums/TaskType.java delete mode 100644 src/main/java/task/ToDo.java rename src/main/java/{task => tasks}/Deadline.java (81%) rename src/main/java/{task => tasks}/Event.java (81%) rename src/main/java/{task => tasks}/Task.java (87%) create mode 100644 src/main/java/tasks/ToDo.java diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 9e87e67f23..a865017e5b 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,7 +1,7 @@ -import task.Deadline; -import task.Event; -import task.Task; -import task.ToDo; +import tasks.Deadline; +import tasks.Event; +import tasks.Task; +import tasks.ToDo; import java.util.Scanner; diff --git a/src/main/java/enums/TaskType.java b/src/main/java/enums/TaskType.java new file mode 100644 index 0000000000..ead6143a94 --- /dev/null +++ b/src/main/java/enums/TaskType.java @@ -0,0 +1,16 @@ +package enums; + +public enum TaskType { + TODO("T"), DEADLINE("D"), Event("E"); + + private String icon; + + private TaskType(String icon) { + this.icon = icon; + } + + @Override + public String toString() { + return icon; + } +} diff --git a/src/main/java/task/ToDo.java b/src/main/java/task/ToDo.java deleted file mode 100644 index f9de2495c5..0000000000 --- a/src/main/java/task/ToDo.java +++ /dev/null @@ -1,7 +0,0 @@ -package task; - -public class ToDo extends Task{ - public ToDo(String description) { - super(description, "T"); - } -} diff --git a/src/main/java/task/Deadline.java b/src/main/java/tasks/Deadline.java similarity index 81% rename from src/main/java/task/Deadline.java rename to src/main/java/tasks/Deadline.java index 7c8f0e9249..d9e49e27d5 100644 --- a/src/main/java/task/Deadline.java +++ b/src/main/java/tasks/Deadline.java @@ -1,10 +1,12 @@ -package task; +package tasks; + +import enums.TaskType; public class Deadline extends Task{ protected String deadline; public Deadline(String description, String deadline) { - super(description, "D"); + super(description, TaskType.DEADLINE); this.deadline = deadline; } diff --git a/src/main/java/task/Event.java b/src/main/java/tasks/Event.java similarity index 81% rename from src/main/java/task/Event.java rename to src/main/java/tasks/Event.java index d6c16587ab..9b9fc76301 100644 --- a/src/main/java/task/Event.java +++ b/src/main/java/tasks/Event.java @@ -1,10 +1,12 @@ -package task; +package tasks; + +import enums.TaskType; public class Event extends Task{ protected String eventTime; public Event(String description, String eventTime) { - super(description, "E"); + super(description, TaskType.Event); this.eventTime = eventTime; } diff --git a/src/main/java/task/Task.java b/src/main/java/tasks/Task.java similarity index 87% rename from src/main/java/task/Task.java rename to src/main/java/tasks/Task.java index c2c236efe7..b217a69831 100644 --- a/src/main/java/task/Task.java +++ b/src/main/java/tasks/Task.java @@ -1,15 +1,16 @@ -package task; +package tasks; +import enums.TaskType; import java.util.ArrayList; public abstract class Task { protected String description; - protected String taskType; + protected TaskType taskType; protected boolean isDone; protected static final ArrayList TASKS = new ArrayList<>(); - public Task(String description, String taskType) { + public Task(String description, TaskType taskType) { this.description = description; this.taskType = taskType; this.isDone = false; @@ -41,7 +42,7 @@ public String getDescription() { return this.description; } - public String getTaskType() { return this.taskType; } + public TaskType getTaskType() { return this.taskType; } public String getStatusIcon() { return (isDone ? "X" : " "); diff --git a/src/main/java/tasks/ToDo.java b/src/main/java/tasks/ToDo.java new file mode 100644 index 0000000000..f78553cc04 --- /dev/null +++ b/src/main/java/tasks/ToDo.java @@ -0,0 +1,9 @@ +package tasks; + +import enums.TaskType; + +public class ToDo extends Task{ + public ToDo(String description) { + super(description, TaskType.TODO); + } +} diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index c4b860178d..6fc3058184 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,23 +1,23 @@ Hello! I'm Duke What can I do for you -Got it. I've added this task: +Got it. I've added this tasks: [T][ ] borrow book -Now you have 1 task(s) in the list. -Got it. I've added this task: +Now you have 1 tasks(s) in the list. +Got it. I've added this tasks: [D][ ] return book (by:Sunday) -Now you have 2 task(s) in the list. -Got it. I've added this task: +Now you have 2 tasks(s) in the list. +Got it. I've added this tasks: [E][ ] project meeting (at:Mon 2-4pm) -Now you have 3 task(s) in the list. +Now you have 3 tasks(s) in the list. 1.[T][ ] borrow book 2.[D][ ] return book (by:Sunday) 3.[E][ ] project meeting (at:Mon 2-4pm) -Nice! I've marked this task as done: +Nice! I've marked this tasks as done: [D][X] return book (by:Sunday) 1.[T][ ] borrow book 2.[D][X] return book (by:Sunday) 3.[E][ ] project meeting (at:Mon 2-4pm) -Ok, I've marked this task as not done yet: +Ok, I've marked this tasks as not done yet: [D][ ] return book (by:Sunday) 1.[T][ ] borrow book 2.[D][ ] return book (by:Sunday) From 042bfe30f84be2b7780fdaaf98dbe99e9700706c Mon Sep 17 00:00:00 2001 From: TeddYE Date: Sun, 30 Jan 2022 22:51:46 +0800 Subject: [PATCH 10/32] Add parser class to parse the user input into different commands Let's: * add abstract class for different commands --- src/main/Duke.java | 22 ++++ src/main/{java => }/DukeException.java | 2 + src/main/commands/CBye.java | 17 +++ src/main/commands/CDeadline.java | 32 ++++++ src/main/commands/CDelete.java | 30 ++++++ src/main/commands/CEvent.java | 33 ++++++ src/main/commands/CList.java | 22 ++++ src/main/commands/CMark.java | 30 ++++++ src/main/commands/CTodo.java | 26 +++++ src/main/commands/CUnmark.java | 30 ++++++ src/main/commands/Command.java | 22 ++++ src/main/enums/CommandType.java | 12 +++ src/main/{java => }/enums/TaskType.java | 6 +- src/main/io/Parser.java | 102 ++++++++++++++++++ src/main/java/Duke.java | 131 ------------------------ src/main/java/tasks/Deadline.java | 21 ---- src/main/tasks/Deadline.java | 21 ++++ src/main/{java => }/tasks/Event.java | 4 +- src/main/{java => }/tasks/Task.java | 4 +- src/main/{java => }/tasks/ToDo.java | 4 +- 20 files changed, 411 insertions(+), 160 deletions(-) create mode 100644 src/main/Duke.java rename src/main/{java => }/DukeException.java (89%) create mode 100644 src/main/commands/CBye.java create mode 100644 src/main/commands/CDeadline.java create mode 100644 src/main/commands/CDelete.java create mode 100644 src/main/commands/CEvent.java create mode 100644 src/main/commands/CList.java create mode 100644 src/main/commands/CMark.java create mode 100644 src/main/commands/CTodo.java create mode 100644 src/main/commands/CUnmark.java create mode 100644 src/main/commands/Command.java create mode 100644 src/main/enums/CommandType.java rename src/main/{java => }/enums/TaskType.java (73%) create mode 100644 src/main/io/Parser.java delete mode 100644 src/main/java/Duke.java delete mode 100644 src/main/java/tasks/Deadline.java create mode 100644 src/main/tasks/Deadline.java rename src/main/{java => }/tasks/Event.java (89%) rename src/main/{java => }/tasks/Task.java (96%) rename src/main/{java => }/tasks/ToDo.java (71%) diff --git a/src/main/Duke.java b/src/main/Duke.java new file mode 100644 index 0000000000..3c2e21b8a2 --- /dev/null +++ b/src/main/Duke.java @@ -0,0 +1,22 @@ +package main; + +import main.commands.Command; +import main.io.Parser; + +import java.util.Scanner; + +public class Duke { + private static final String WELCOME_MESSAGE = "Hello! I'm Duke \n" + "What can I do for you"; + + public static void main(String[] args) throws DukeException { + Scanner sc = new Scanner(System.in); + Parser parser = new Parser(); + + System.out.println(WELCOME_MESSAGE); + + while (!Command.getIsExit()) { + Command newCommand = parser.parse(sc.nextLine()); + newCommand.runCommand(); + } + } +} diff --git a/src/main/java/DukeException.java b/src/main/DukeException.java similarity index 89% rename from src/main/java/DukeException.java rename to src/main/DukeException.java index 520e7f7b1e..0fa0925e55 100644 --- a/src/main/java/DukeException.java +++ b/src/main/DukeException.java @@ -1,3 +1,5 @@ +package main; + public class DukeException extends Exception{ public DukeException (String errorMessage){ super(errorMessage); diff --git a/src/main/commands/CBye.java b/src/main/commands/CBye.java new file mode 100644 index 0000000000..5a59e330a5 --- /dev/null +++ b/src/main/commands/CBye.java @@ -0,0 +1,17 @@ +package main.commands; + +import main.enums.CommandType; + +public class CBye extends Command{ + private static final String GOODBYE_MESSAGE = "Bye. Hope to see you again soon!"; + + public CBye() { + super(CommandType.BYE); + } + + @Override + public void runCommand() { + Command.exitDuke(); + System.out.println(GOODBYE_MESSAGE); + } +} diff --git a/src/main/commands/CDeadline.java b/src/main/commands/CDeadline.java new file mode 100644 index 0000000000..0872587f9e --- /dev/null +++ b/src/main/commands/CDeadline.java @@ -0,0 +1,32 @@ +package main.commands; + +import main.enums.CommandType; +import main.tasks.Deadline; +import main.tasks.Task; + +public class CDeadline extends Command { + protected String description; + protected String dueDate; + + public CDeadline(String description, String dueDate) { + super(CommandType.DEADLINE); + this.description = description; + this.dueDate = dueDate; + } + + public String getDueDate() { + return this.dueDate; + } + + public String getDescription() { + return this.description; + } + + @Override + public void runCommand() { + Task newDeadline = new Deadline(this.getDescription(), this.getDueDate()); + Task.addTask(newDeadline); + System.out.printf("Got it. I've added this task:\n" + "%s\n" + "%s\n", + newDeadline, Task.taskCountToString()); + } +} diff --git a/src/main/commands/CDelete.java b/src/main/commands/CDelete.java new file mode 100644 index 0000000000..54d3348548 --- /dev/null +++ b/src/main/commands/CDelete.java @@ -0,0 +1,30 @@ +package main.commands; + +import main.DukeException; +import main.enums.CommandType; +import main.tasks.Task; + +public class CDelete extends Command{ + protected int deleteIndex; + + public CDelete(int deleteIndex) { + super(CommandType.DELETE); + this.deleteIndex = deleteIndex; + } + + public int getDeleteIndex() { + return this.deleteIndex; + } + + @Override + public void runCommand() throws DukeException { + try { + Task deleteTask = Task.getTasks().get(this.getDeleteIndex()); + Task.deleteTask(this.getDeleteIndex()); + System.out.printf("Noted. I've removed this task: \n" + " %s\n" + + "%s\n", deleteTask, Task.taskCountToString()); + } catch (IndexOutOfBoundsException e) { + throw new DukeException("Please check that you have entered the correct index."); + } + } +} diff --git a/src/main/commands/CEvent.java b/src/main/commands/CEvent.java new file mode 100644 index 0000000000..5a81766717 --- /dev/null +++ b/src/main/commands/CEvent.java @@ -0,0 +1,33 @@ +package main.commands; + +import main.enums.CommandType; +import main.tasks.Event; +import main.tasks.Task; + +public class CEvent extends Command { + protected String description; + protected String dateTime; + + public CEvent(String description, String dateTime) { + super(CommandType.EVENT); + this.description = description; + this.dateTime = dateTime; + } + + public String getDateTime() { + return this.dateTime; + } + + public String getDescription() { + return this.description; + } + + + @Override + public void runCommand() { + Task newEvent = new Event(this.getDescription(), this.getDateTime()); + Task.addTask(newEvent); + System.out.printf("Got it. I've added this task:\n" + "%s\n" + "%s\n", + newEvent, Task.taskCountToString()); + } +} diff --git a/src/main/commands/CList.java b/src/main/commands/CList.java new file mode 100644 index 0000000000..4cc94a7c20 --- /dev/null +++ b/src/main/commands/CList.java @@ -0,0 +1,22 @@ +package main.commands; + +import main.enums.CommandType; +import main.tasks.Task; + +public class CList extends Command{ + public CList() { + super(CommandType.LIST); + } + + @Override + public void runCommand() { + int n = Task.getTasks().size(); + if (n == 0) { + System.out.println("The list is currently empty."); + } else { + for (int i = 0; i < n; i++) { + System.out.printf("%d.%s%n", i + 1, Task.getTasks().get(i)); + } + } + } +} diff --git a/src/main/commands/CMark.java b/src/main/commands/CMark.java new file mode 100644 index 0000000000..031503011f --- /dev/null +++ b/src/main/commands/CMark.java @@ -0,0 +1,30 @@ +package main.commands; + +import main.DukeException; +import main.enums.CommandType; +import main.tasks.Task; + +public class CMark extends Command{ + protected int markIndex; + + public CMark(int markIndex) { + super(CommandType.MARK); + this.markIndex = markIndex; + } + + public int getMarkIndex() { + return this.markIndex; + } + + @Override + public void runCommand() throws DukeException { + try { + Task markTask = Task.getTasks().get(this.getMarkIndex()); + markTask.setIsDone(true); + System.out.printf("Nice! I've marked this task as done: \n" + + " %s\n", markTask); + } catch (IndexOutOfBoundsException e) { + throw new DukeException("Please check that you have entered the correct index."); + } + } +} diff --git a/src/main/commands/CTodo.java b/src/main/commands/CTodo.java new file mode 100644 index 0000000000..e78cccd2a8 --- /dev/null +++ b/src/main/commands/CTodo.java @@ -0,0 +1,26 @@ +package main.commands; + +import main.enums.CommandType; +import main.tasks.Task; +import main.tasks.ToDo; + +public class CTodo extends Command{ + protected String description; + + public CTodo(String description) { + super(CommandType.TODO); + this.description = description; + } + + public String getDescription() { + return this.description; + } + + @Override + public void runCommand() { + Task newToDo = new ToDo(this.getDescription()); + Task.addTask(newToDo); + System.out.printf("Got it. I've added this task:\n" + "%s\n" + "%s\n", + newToDo, Task.taskCountToString()); + } +} diff --git a/src/main/commands/CUnmark.java b/src/main/commands/CUnmark.java new file mode 100644 index 0000000000..3c26cbc8b4 --- /dev/null +++ b/src/main/commands/CUnmark.java @@ -0,0 +1,30 @@ +package main.commands; + +import main.DukeException; +import main.enums.CommandType; +import main.tasks.Task; + +public class CUnmark extends Command{ + protected int unmarkIndex; + + public CUnmark(int unmarkIndex) { + super(CommandType.UNMARK); + this.unmarkIndex = unmarkIndex; + } + + public int getUnmarkIndex() { + return this.unmarkIndex; + } + + @Override + public void runCommand() throws DukeException { + try { + Task unmarkTask = Task.getTasks().get(this.getUnmarkIndex()); + unmarkTask.setIsDone(false); + System.out.printf("Ok, I've marked this task as not done yet: \n" + + " %s\n", unmarkTask); + } catch (IndexOutOfBoundsException e) { + throw new DukeException("Please check that you have entered the correct index."); + } + } +} diff --git a/src/main/commands/Command.java b/src/main/commands/Command.java new file mode 100644 index 0000000000..9ca5b11907 --- /dev/null +++ b/src/main/commands/Command.java @@ -0,0 +1,22 @@ +package main.commands; + +import main.DukeException; +import main.enums.CommandType; + +public abstract class Command { + protected CommandType commandType; + + protected static boolean isExit = false; + + public Command(CommandType commandType) { + this.commandType = commandType; + } + + public static boolean getIsExit() { return Command.isExit; } + + public static void exitDuke() { Command.isExit = true; } + + public CommandType getCommandType() { return this.commandType; } + + public abstract void runCommand() throws DukeException; +} diff --git a/src/main/enums/CommandType.java b/src/main/enums/CommandType.java new file mode 100644 index 0000000000..42fb5665d8 --- /dev/null +++ b/src/main/enums/CommandType.java @@ -0,0 +1,12 @@ +package main.enums; + +public enum CommandType { + BYE, + DEADLINE, + DELETE, + EVENT, + LIST, + MARK, + TODO, + UNMARK; +} diff --git a/src/main/java/enums/TaskType.java b/src/main/enums/TaskType.java similarity index 73% rename from src/main/java/enums/TaskType.java rename to src/main/enums/TaskType.java index ead6143a94..49064b8674 100644 --- a/src/main/java/enums/TaskType.java +++ b/src/main/enums/TaskType.java @@ -1,7 +1,9 @@ -package enums; +package main.enums; public enum TaskType { - TODO("T"), DEADLINE("D"), Event("E"); + TODO("T"), + DEADLINE("D"), + Event("E"); private String icon; diff --git a/src/main/io/Parser.java b/src/main/io/Parser.java new file mode 100644 index 0000000000..1aef8341c2 --- /dev/null +++ b/src/main/io/Parser.java @@ -0,0 +1,102 @@ +package main.io; + +import main.commands.Command; +import main.commands.CBye; +import main.commands.CMark; +import main.commands.CDelete; +import main.commands.CList; +import main.commands.CTodo; +import main.commands.CDeadline; +import main.commands.CEvent; +import main.commands.CUnmark; +import main.DukeException; + +import java.util.Arrays; + +public class Parser { + public Command parse(String userInput) throws DukeException { + String[] inputArray = userInput.split(" "); + String userCommand = inputArray[0]; + Command newCommand; + + switch (userCommand) { + case "bye": + newCommand = new CBye(); + break; + case "list": + newCommand = new CList(); + break; + case "mark": + try { + int markIndex = Integer.parseInt(inputArray[1]) - 1; + newCommand = new CMark(markIndex); + } catch (IndexOutOfBoundsException e) { + throw new DukeException("Please specify the task you wish to mark."); + } catch (NumberFormatException e) { + throw new DukeException("Invalid index format."); + } + break; + case "unmark": + try { + int unmarkIndex = Integer.parseInt(inputArray[1]) - 1; + newCommand = new CUnmark(unmarkIndex); + } catch (IndexOutOfBoundsException e) { + throw new DukeException("Please specify the task you wish to unmark."); + } catch (NumberFormatException e) { + throw new DukeException("Invalid index format."); + } + break; + case "delete": + try { + int deleteIndex = Integer.parseInt(inputArray[1]) - 1; + newCommand = new CDelete(deleteIndex); + } catch (IndexOutOfBoundsException e) { + throw new DukeException("Please specify the task you wish to delete."); + } catch (NumberFormatException e) { + throw new DukeException("Invalid index format."); + } + break; + case "todo": + String todoDescription = String.join(" ", + Arrays.copyOfRange(inputArray, 1, inputArray.length)); + if (todoDescription.equals("")) { + throw new DukeException("Please specify the description of the todo task."); + } + newCommand = new CTodo(todoDescription); + break; + case "deadline": + if (!userInput.contains("/by")) { + throw new DukeException("Please specify the due date using the /by keyword."); + } else { + int byIndex = Arrays.asList(inputArray).indexOf("/by"); + String deadlineDescription = String.join(" ", + Arrays.copyOfRange(inputArray, 1, byIndex)); + String dueDate = String.join(" ", + Arrays.copyOfRange(inputArray, byIndex + 1, inputArray.length)); + if (deadlineDescription.equals("") || dueDate.equals("")) { + throw new DukeException("Please specify the description/due date of the deadline task."); + } + newCommand = new CDeadline(deadlineDescription, dueDate); + } + break; + case "event": + if (!userInput.contains("/at")) { + throw new DukeException("Please specify the date time using the /at keyword."); + } else { + int byIndex = Arrays.asList(inputArray).indexOf("/at"); + String eventDescription = String.join(" ", + Arrays.copyOfRange(inputArray, 1, byIndex)); + String dateTime= String.join(" ", + Arrays.copyOfRange(inputArray, byIndex + 1, inputArray.length)); + if (eventDescription.equals("") || dateTime.equals("")) { + throw new DukeException("Please specify the description/date time of the event task."); + } + newCommand = new CEvent(eventDescription, dateTime); + } + break; + default: + throw new DukeException("Sorry. I do not understand your input."); + } + return newCommand; + } +} diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java deleted file mode 100644 index a865017e5b..0000000000 --- a/src/main/java/Duke.java +++ /dev/null @@ -1,131 +0,0 @@ -import tasks.Deadline; -import tasks.Event; -import tasks.Task; -import tasks.ToDo; - -import java.util.Scanner; - -public class Duke { - private static final String WELCOME_MESSAGE = "Hello! I'm Duke \n" + "What can I do for you"; - private static final String GOODBYE_MESSAGE = "Bye. Hope to see you again soon!"; - - public static void main(String[] args) throws DukeException { - Scanner sc = new Scanner(System.in); - boolean isExit = false; - - System.out.println(WELCOME_MESSAGE); - while (!isExit) { - String userCommand = sc.next(); - switch (userCommand) { - case "bye": - isExit = true; - System.out.println(GOODBYE_MESSAGE); - break; - case "list": - for (int i = 0; i < Task.getTasks().size(); i++) { - System.out.printf("%d.%s%n", i + 1, Task.getTasks().get(i)); - } - break; - case "mark": - int markIndex = sc.nextInt() - 1; - try { - Task markTask = Task.getTasks().get(markIndex); - markTask.setIsDone(true); - System.out.printf("Nice! I've marked this task as done: \n" - + " %s\n", markTask); - break; - } catch (IndexOutOfBoundsException indexErr) { - DukeException e = new DukeException("☹ OOPS!!! Invalid index."); - System.out.println(e.getMessage()); - } - break; - case "unmark": - int unmarkIndex = sc.nextInt() - 1; - try { - Task unmarkTask = Task.getTasks().get(unmarkIndex); - unmarkTask.setIsDone(false); - System.out.printf("Ok, I've marked this task as not done yet: \n" - + " %s\n", unmarkTask); - break; - } catch (IndexOutOfBoundsException indexErr) { - DukeException e = new DukeException("☹ OOPS!!! Invalid index."); - System.out.println(e.getMessage()); - } - break; - case "delete": - int deleteIndex = sc.nextInt() - 1; - try { - Task deleteTask = Task.getTasks().get(deleteIndex); - Task.deleteTask(deleteIndex); - System.out.printf("Noted. I've removed this task: \n" + " %s\n" - + "%s\n", deleteTask, Task.taskCountToString()); - break; - } catch (IndexOutOfBoundsException indexErr) { - DukeException e = new DukeException("☹ OOPS!!! Invalid index."); - System.out.println(e.getMessage()); - } - break; - case "todo": - String toDoDescription = sc.nextLine().trim(); - if (toDoDescription.equals("")) { - DukeException e = new DukeException("☹ OOPS!!! The description of a todo cannot be empty."); - System.out.println(e.getMessage()); - } else { - Task newToDo = new ToDo(toDoDescription); - Task.addTask(newToDo); - System.out.printf("Got it. I've added this task:\n" + "%s\n" + "%s\n", - newToDo, Task.taskCountToString()); - } - break; - case "deadline": - String deadlineTempInput = sc.nextLine(); - if(!deadlineTempInput.contains("/by")) { - DukeException e = new DukeException("The additional info doesn't fit the input format."); - System.out.println(e.getMessage()); - break; - } - String deadlineDescription = deadlineTempInput.split("/by", 2)[0].trim(); - String deadlineDueDate = deadlineTempInput.split("/by", 2)[1].trim(); - if (deadlineDescription.equals("")) { - DukeException e = new DukeException("☹ OOPS!!! The description of a deadline cannot be empty."); - System.out.println(e.getMessage()); - } else if (deadlineDueDate.equals("")) { - DukeException e = new DukeException("☹ OOPS!!! The due date of a deadline cannot be empty."); - System.out.println(e.getMessage()); - } else { - Task newDeadline = new Deadline(deadlineDescription, deadlineDueDate); - Task.addTask(newDeadline); - System.out.printf("Got it. I've added this task:\n" + "%s\n" + "%s\n", - newDeadline, Task.taskCountToString()); - } - break; - case "event": - String eventTempInput = sc.nextLine(); - if(!eventTempInput.contains("/at")) { - DukeException e = new DukeException("The additional info doesn't fit the input format."); - System.out.println(e.getMessage()); - break; - } - String eventDescription = eventTempInput.split("/at", 2)[0].trim(); - String eventDateTime = eventTempInput.split("/at", 2)[1].trim(); - if (eventDescription.equals("")) { - DukeException e = new DukeException("☹ OOPS!!! The description of an event cannot be empty."); - System.out.println(e.getMessage()); - } else if (eventDateTime.equals("")) { - DukeException e = new DukeException("☹ OOPS!!! The date/time of an event cannot be empty."); - System.out.println(e.getMessage()); - } else { - Task newEvent = new Event(eventDescription, eventDateTime); - Task.addTask(newEvent); - System.out.printf("Got it. I've added this task:\n" + "%s\n" + "%s\n", - newEvent, Task.taskCountToString()); - } - break; - default: - DukeException e = new DukeException("☹ OOPS!!! I'm sorry, but I don't know what that means :-("); - System.out.println(e.getMessage()); - break; - } - } - } -} diff --git a/src/main/java/tasks/Deadline.java b/src/main/java/tasks/Deadline.java deleted file mode 100644 index d9e49e27d5..0000000000 --- a/src/main/java/tasks/Deadline.java +++ /dev/null @@ -1,21 +0,0 @@ -package tasks; - -import enums.TaskType; - -public class Deadline extends Task{ - protected String deadline; - - public Deadline(String description, String deadline) { - super(description, TaskType.DEADLINE); - this.deadline = deadline; - } - - public String getDeadline() { - return this.deadline; - } - - @Override - public String toString() { - return super.toString() + String.format(" (by: %s)", this.getDeadline()); - } -} diff --git a/src/main/tasks/Deadline.java b/src/main/tasks/Deadline.java new file mode 100644 index 0000000000..bbf9472192 --- /dev/null +++ b/src/main/tasks/Deadline.java @@ -0,0 +1,21 @@ +package main.tasks; + +import main.enums.TaskType; + +public class Deadline extends Task{ + protected String dueDate; + + public Deadline(String description, String dueDate) { + super(description, TaskType.DEADLINE); + this.dueDate = dueDate; + } + + public String getDueDate() { + return this.dueDate; + } + + @Override + public String toString() { + return super.toString() + String.format(" (by: %s)", this.getDueDate()); + } +} diff --git a/src/main/java/tasks/Event.java b/src/main/tasks/Event.java similarity index 89% rename from src/main/java/tasks/Event.java rename to src/main/tasks/Event.java index 9b9fc76301..1f85362864 100644 --- a/src/main/java/tasks/Event.java +++ b/src/main/tasks/Event.java @@ -1,6 +1,6 @@ -package tasks; +package main.tasks; -import enums.TaskType; +import main.enums.TaskType; public class Event extends Task{ protected String eventTime; diff --git a/src/main/java/tasks/Task.java b/src/main/tasks/Task.java similarity index 96% rename from src/main/java/tasks/Task.java rename to src/main/tasks/Task.java index b217a69831..c503b5f910 100644 --- a/src/main/java/tasks/Task.java +++ b/src/main/tasks/Task.java @@ -1,6 +1,6 @@ -package tasks; +package main.tasks; -import enums.TaskType; +import main.enums.TaskType; import java.util.ArrayList; public abstract class Task { diff --git a/src/main/java/tasks/ToDo.java b/src/main/tasks/ToDo.java similarity index 71% rename from src/main/java/tasks/ToDo.java rename to src/main/tasks/ToDo.java index f78553cc04..676ae45fbd 100644 --- a/src/main/java/tasks/ToDo.java +++ b/src/main/tasks/ToDo.java @@ -1,6 +1,6 @@ -package tasks; +package main.tasks; -import enums.TaskType; +import main.enums.TaskType; public class ToDo extends Task{ public ToDo(String description) { From 256377e90ebaea4cd28757a276ac6ef3847231c6 Mon Sep 17 00:00:00 2001 From: TeddYE Date: Tue, 1 Feb 2022 10:34:27 +0800 Subject: [PATCH 11/32] Duke class: implement level-7 functionalities Let's: * add Storage class to facilitate reading and writing of list to file --- data/duke.txt | 2 + duke.txt | 1 + src/main/Duke.java | 7 +++ src/main/commands/CDelete.java | 2 +- src/main/commands/CList.java | 4 +- src/main/commands/CMark.java | 2 +- src/main/commands/CUnmark.java | 2 +- src/main/io/Storage.java | 101 +++++++++++++++++++++++++++++++++ src/main/tasks/Deadline.java | 10 ++++ src/main/tasks/Event.java | 10 ++++ src/main/tasks/Task.java | 17 +++++- src/main/tasks/ToDo.java | 4 ++ 12 files changed, 155 insertions(+), 7 deletions(-) create mode 100644 data/duke.txt create mode 100644 duke.txt create mode 100644 src/main/io/Storage.java diff --git a/data/duke.txt b/data/duke.txt new file mode 100644 index 0000000000..ec62750b72 --- /dev/null +++ b/data/duke.txt @@ -0,0 +1,2 @@ +T~1~1 +D~0~1~1 diff --git a/duke.txt b/duke.txt new file mode 100644 index 0000000000..055934e2c0 --- /dev/null +++ b/duke.txt @@ -0,0 +1 @@ +T|0|1 diff --git a/src/main/Duke.java b/src/main/Duke.java index 3c2e21b8a2..96b5bd46a2 100644 --- a/src/main/Duke.java +++ b/src/main/Duke.java @@ -2,7 +2,9 @@ import main.commands.Command; import main.io.Parser; +import main.io.Storage; +import java.io.IOException; import java.util.Scanner; public class Duke { @@ -11,6 +13,9 @@ public class Duke { public static void main(String[] args) throws DukeException { Scanner sc = new Scanner(System.in); Parser parser = new Parser(); + Storage storage = new Storage("data", "duke.txt"); + + storage.readFile(); System.out.println(WELCOME_MESSAGE); @@ -18,5 +23,7 @@ public static void main(String[] args) throws DukeException { Command newCommand = parser.parse(sc.nextLine()); newCommand.runCommand(); } + + storage.writeFile(); } } diff --git a/src/main/commands/CDelete.java b/src/main/commands/CDelete.java index 54d3348548..50291c81c8 100644 --- a/src/main/commands/CDelete.java +++ b/src/main/commands/CDelete.java @@ -19,7 +19,7 @@ public int getDeleteIndex() { @Override public void runCommand() throws DukeException { try { - Task deleteTask = Task.getTasks().get(this.getDeleteIndex()); + Task deleteTask = Task.getTask(this.getDeleteIndex()); Task.deleteTask(this.getDeleteIndex()); System.out.printf("Noted. I've removed this task: \n" + " %s\n" + "%s\n", deleteTask, Task.taskCountToString()); diff --git a/src/main/commands/CList.java b/src/main/commands/CList.java index 4cc94a7c20..44d537df9a 100644 --- a/src/main/commands/CList.java +++ b/src/main/commands/CList.java @@ -10,12 +10,12 @@ public CList() { @Override public void runCommand() { - int n = Task.getTasks().size(); + int n = Task.getTasksCount(); if (n == 0) { System.out.println("The list is currently empty."); } else { for (int i = 0; i < n; i++) { - System.out.printf("%d.%s%n", i + 1, Task.getTasks().get(i)); + System.out.printf("%d.%s%n", i + 1, Task.getTask(i)); } } } diff --git a/src/main/commands/CMark.java b/src/main/commands/CMark.java index 031503011f..b6cae343eb 100644 --- a/src/main/commands/CMark.java +++ b/src/main/commands/CMark.java @@ -19,7 +19,7 @@ public int getMarkIndex() { @Override public void runCommand() throws DukeException { try { - Task markTask = Task.getTasks().get(this.getMarkIndex()); + Task markTask = Task.getTask(this.getMarkIndex()); markTask.setIsDone(true); System.out.printf("Nice! I've marked this task as done: \n" + " %s\n", markTask); diff --git a/src/main/commands/CUnmark.java b/src/main/commands/CUnmark.java index 3c26cbc8b4..5cd37877eb 100644 --- a/src/main/commands/CUnmark.java +++ b/src/main/commands/CUnmark.java @@ -19,7 +19,7 @@ public int getUnmarkIndex() { @Override public void runCommand() throws DukeException { try { - Task unmarkTask = Task.getTasks().get(this.getUnmarkIndex()); + Task unmarkTask = Task.getTask(this.getUnmarkIndex()); unmarkTask.setIsDone(false); System.out.printf("Ok, I've marked this task as not done yet: \n" + " %s\n", unmarkTask); diff --git a/src/main/io/Storage.java b/src/main/io/Storage.java new file mode 100644 index 0000000000..10d4b178ec --- /dev/null +++ b/src/main/io/Storage.java @@ -0,0 +1,101 @@ +package main.io; + +import main.tasks.Deadline; +import main.tasks.Event; +import main.tasks.Task; +import main.tasks.ToDo; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Scanner; + +public class Storage { + protected String filename; + protected String dirname; + + public Storage(String dirname, String filename) { + this.filename = filename; + this.dirname = dirname; + this.createFile(); + } + + private String getCurrentDirectory() { + return System.getProperty("user.dir"); + } + + private String getDirname() { return this.dirname; } + + private String getFilename() { return this.filename; } + + private Path getDirPath() { + return Paths.get(this.getCurrentDirectory(), this.getDirname()); + } + + private Path getFilePath() { + return Paths.get(this.getCurrentDirectory(), + String.format("%s/%s", this.getDirname(), this.getFilename())); + } + + private void createFile(){ + try { + if (!Files.exists(this.getDirPath())) { + Files.createDirectories(this.getDirPath()); + } + if (!Files.exists(this.getFilePath())) { + Files.createFile(this.getFilePath()); + } + } catch (IOException e) { + System.out.printf("Error while trying to create save file: ", e.getMessage()); + } + } + + public void readFile() { + try { + File dukeFile = new File(String.format("%s/%s", this.getDirname(), this.getFilename())); + Scanner dukeReader = new Scanner(dukeFile); + while (dukeReader.hasNextLine()) { + String taskString = dukeReader.nextLine(); + String[] taskStringArray = taskString.split("~"); + this.addToTasks(taskStringArray); + } + dukeReader.close(); + } catch (IOException e) { + System.out.printf("Error while trying to read save file: ", e.getMessage()); + } + } + + public void addToTasks(String[] taskStringArray) { + String type = taskStringArray[0]; + boolean isDone = taskStringArray[1].equals("1"); + String description = taskStringArray[2]; + switch (type) { + case "T": + Task.addTask(new ToDo(description, isDone)); + break; + case "D": + Task.addTask(new Deadline(description, taskStringArray[3], isDone)); + break; + case "E": + Task.addTask(new Event(description, taskStringArray[3], isDone)); + break; + } + } + + public void writeFile() { + try { + FileWriter dukeWriter = new FileWriter(String.format("%s/%s", this.getDirname(), this.getFilename())); + for (int i = 0; i < Task.getTasksCount(); i++) { + if (i != Task.getTasksCount()) { + dukeWriter.write(Task.getTask(i).toStoreString() + "\n"); + } + } + dukeWriter.close(); + } catch (IOException e) { + System.out.printf("Error while trying to write save file: ", e.getMessage()); + } + } +} diff --git a/src/main/tasks/Deadline.java b/src/main/tasks/Deadline.java index bbf9472192..dc09d519f7 100644 --- a/src/main/tasks/Deadline.java +++ b/src/main/tasks/Deadline.java @@ -10,10 +10,20 @@ public Deadline(String description, String dueDate) { this.dueDate = dueDate; } + public Deadline(String description, String dueDate, boolean isDone) { + super(description, TaskType.DEADLINE, isDone); + this.dueDate = dueDate; + } + public String getDueDate() { return this.dueDate; } + @Override + public String toStoreString() { + return super.toStoreString() + "~" + this.getDueDate(); + } + @Override public String toString() { return super.toString() + String.format(" (by: %s)", this.getDueDate()); diff --git a/src/main/tasks/Event.java b/src/main/tasks/Event.java index 1f85362864..4db136ed15 100644 --- a/src/main/tasks/Event.java +++ b/src/main/tasks/Event.java @@ -10,10 +10,20 @@ public Event(String description, String eventTime) { this.eventTime = eventTime; } + public Event(String description, String eventTime, boolean isDone) { + super(description, TaskType.Event, isDone); + this.eventTime = eventTime; + } + public String getEventTime() { return this.eventTime; } + @Override + public String toStoreString() { + return super.toStoreString() + "~" + this.getEventTime(); + } + @Override public String toString() { return super.toString() + String.format(" (at: %s)", this.getEventTime()); diff --git a/src/main/tasks/Task.java b/src/main/tasks/Task.java index c503b5f910..8ca87e2ed5 100644 --- a/src/main/tasks/Task.java +++ b/src/main/tasks/Task.java @@ -16,6 +16,12 @@ public Task(String description, TaskType taskType) { this.isDone = false; } + public Task(String description, TaskType taskType, boolean isDone) { + this.description = description; + this.taskType = taskType; + this.isDone = isDone; + } + public static ArrayList getTasks() { return Task.TASKS; } @@ -30,12 +36,12 @@ public static Task getTask(int taskIndex) { return Task.TASKS.get(taskIndex); } - public static int getTaskCount() { + public static int getTasksCount() { return Task.TASKS.size(); } public static String taskCountToString() { - return String.format("Now you have %d task(s) in the list.", Task.getTaskCount()); + return String.format("Now you have %d task(s) in the list.", Task.getTasksCount()); } public String getDescription() { @@ -52,6 +58,13 @@ public void setIsDone(boolean isDone) { this.isDone = isDone; } + public String toStoreString() { + return String.format("%s~%d~%s", + this.getTaskType(), + this.getStatusIcon() == "X" ? 1 : 0, + this.getDescription()); + } + @Override public String toString() { return String.format("[%s][%s] %s", this.getTaskType(), this.getStatusIcon(), this.getDescription()); diff --git a/src/main/tasks/ToDo.java b/src/main/tasks/ToDo.java index 676ae45fbd..66c011f7e5 100644 --- a/src/main/tasks/ToDo.java +++ b/src/main/tasks/ToDo.java @@ -6,4 +6,8 @@ public class ToDo extends Task{ public ToDo(String description) { super(description, TaskType.TODO); } + + public ToDo(String description, boolean isDone) { + super(description, TaskType.TODO, isDone); + } } From 0762e161b3c0dc48903721a8df002895baf23920 Mon Sep 17 00:00:00 2001 From: TeddYE Date: Tue, 1 Feb 2022 12:04:08 +0800 Subject: [PATCH 12/32] Implement level-8 functionalities Teach duke to understand date and time. Let's * update due date and event time to LocalDateTime instead of String --- data/duke.txt | 2 +- src/main/Duke.java | 1 - src/main/io/Parser.java | 46 +++++++++++++++++++++++------------- src/main/io/Storage.java | 20 ++++++++++++---- src/main/tasks/Deadline.java | 14 +++++++---- src/main/tasks/Event.java | 14 +++++++---- 6 files changed, 65 insertions(+), 32 deletions(-) diff --git a/data/duke.txt b/data/duke.txt index ec62750b72..53395bf98d 100644 --- a/data/duke.txt +++ b/data/duke.txt @@ -1,2 +1,2 @@ T~1~1 -D~0~1~1 +D~0~1~1990-10-20T12:34 diff --git a/src/main/Duke.java b/src/main/Duke.java index 96b5bd46a2..ebf42f1b02 100644 --- a/src/main/Duke.java +++ b/src/main/Duke.java @@ -4,7 +4,6 @@ import main.io.Parser; import main.io.Storage; -import java.io.IOException; import java.util.Scanner; public class Duke { diff --git a/src/main/io/Parser.java b/src/main/io/Parser.java index 1aef8341c2..6e82ce7691 100644 --- a/src/main/io/Parser.java +++ b/src/main/io/Parser.java @@ -13,6 +13,10 @@ import java.util.Arrays; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + public class Parser { public Command parse(String userInput) throws DukeException { String[] inputArray = userInput.split(" "); @@ -68,30 +72,40 @@ public Command parse(String userInput) throws DukeException { if (!userInput.contains("/by")) { throw new DukeException("Please specify the due date using the /by keyword."); } else { - int byIndex = Arrays.asList(inputArray).indexOf("/by"); - String deadlineDescription = String.join(" ", - Arrays.copyOfRange(inputArray, 1, byIndex)); - String dueDate = String.join(" ", - Arrays.copyOfRange(inputArray, byIndex + 1, inputArray.length)); - if (deadlineDescription.equals("") || dueDate.equals("")) { - throw new DukeException("Please specify the description/due date of the deadline task."); + try { + int byIndex = Arrays.asList(inputArray).indexOf("/by"); + String deadlineDescription = String.join(" ", + Arrays.copyOfRange(inputArray, 1, byIndex)); + String dueDate = String.join(" ", + Arrays.copyOfRange(inputArray, byIndex + 1, inputArray.length)); + LocalDateTime.parse(dueDate, DateTimeFormatter.ofPattern("yyyy-MM-dd kkmm")); + if (deadlineDescription.equals("") || dueDate.equals("")) { + throw new DukeException("Please specify the description/due date of the deadline task."); + } + newCommand = new CDeadline(deadlineDescription, dueDate); + } catch (DateTimeParseException e){ + throw new DukeException("Please provide the date time in this format YYYY-MM-DD 0000"); } - newCommand = new CDeadline(deadlineDescription, dueDate); } break; case "event": if (!userInput.contains("/at")) { throw new DukeException("Please specify the date time using the /at keyword."); } else { - int byIndex = Arrays.asList(inputArray).indexOf("/at"); - String eventDescription = String.join(" ", - Arrays.copyOfRange(inputArray, 1, byIndex)); - String dateTime= String.join(" ", - Arrays.copyOfRange(inputArray, byIndex + 1, inputArray.length)); - if (eventDescription.equals("") || dateTime.equals("")) { - throw new DukeException("Please specify the description/date time of the event task."); + try { + int byIndex = Arrays.asList(inputArray).indexOf("/at"); + String eventDescription = String.join(" ", + Arrays.copyOfRange(inputArray, 1, byIndex)); + String dateTime = String.join(" ", + Arrays.copyOfRange(inputArray, byIndex + 1, inputArray.length)); + LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern("yyyy-MM-dd kkmm")); + if (eventDescription.equals("") || dateTime.equals("")) { + throw new DukeException("Please specify the description/date time of the event task."); + } + newCommand = new CEvent(eventDescription, dateTime); + } catch (DateTimeParseException e){ + throw new DukeException("Please provide the date time in this format YYYY-MM-DD 0000"); } - newCommand = new CEvent(eventDescription, dateTime); } break; default: diff --git a/src/main/io/Storage.java b/src/main/io/Storage.java index 10d4b178ec..69c4b7d6e0 100644 --- a/src/main/io/Storage.java +++ b/src/main/io/Storage.java @@ -1,5 +1,6 @@ package main.io; +import main.DukeException; import main.tasks.Deadline; import main.tasks.Event; import main.tasks.Task; @@ -11,6 +12,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.time.format.DateTimeParseException; import java.util.Scanner; public class Storage { @@ -63,12 +65,14 @@ public void readFile() { this.addToTasks(taskStringArray); } dukeReader.close(); - } catch (IOException e) { + } catch (IOException e) { System.out.printf("Error while trying to read save file: ", e.getMessage()); + } catch (DukeException e) { + System.out.println(e.getMessage()); } } - public void addToTasks(String[] taskStringArray) { + public void addToTasks(String[] taskStringArray) throws DukeException { String type = taskStringArray[0]; boolean isDone = taskStringArray[1].equals("1"); String description = taskStringArray[2]; @@ -77,10 +81,18 @@ public void addToTasks(String[] taskStringArray) { Task.addTask(new ToDo(description, isDone)); break; case "D": - Task.addTask(new Deadline(description, taskStringArray[3], isDone)); + try { + Task.addTask(new Deadline(description, taskStringArray[3], isDone)); + } catch (DateTimeParseException e){ + throw new DukeException("Save file date time not in this format YYYY-MM-DD 0000"); + } break; case "E": - Task.addTask(new Event(description, taskStringArray[3], isDone)); + try { + Task.addTask(new Event(description, taskStringArray[3], isDone)); + } catch (DateTimeParseException e){ + throw new DukeException("Save file date time not in this format YYYY-MM-DD 0000"); + } break; } } diff --git a/src/main/tasks/Deadline.java b/src/main/tasks/Deadline.java index dc09d519f7..6edd45f137 100644 --- a/src/main/tasks/Deadline.java +++ b/src/main/tasks/Deadline.java @@ -2,20 +2,23 @@ import main.enums.TaskType; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + public class Deadline extends Task{ - protected String dueDate; + protected LocalDateTime dueDate; public Deadline(String description, String dueDate) { super(description, TaskType.DEADLINE); - this.dueDate = dueDate; + this.dueDate = LocalDateTime.parse(dueDate, DateTimeFormatter.ofPattern("yyyy-MM-dd kkmm")); } public Deadline(String description, String dueDate, boolean isDone) { super(description, TaskType.DEADLINE, isDone); - this.dueDate = dueDate; + this.dueDate = LocalDateTime.parse(dueDate, DateTimeFormatter.ofPattern("yyyy-MM-dd kkmm")); } - public String getDueDate() { + public LocalDateTime getDueDate() { return this.dueDate; } @@ -26,6 +29,7 @@ public String toStoreString() { @Override public String toString() { - return super.toString() + String.format(" (by: %s)", this.getDueDate()); + return super.toString() + String.format(" (by: %s)", + this.getDueDate().format(DateTimeFormatter.ofPattern("dd/MMM/yyyy HH:mm"))); } } diff --git a/src/main/tasks/Event.java b/src/main/tasks/Event.java index 4db136ed15..60b7c12f0b 100644 --- a/src/main/tasks/Event.java +++ b/src/main/tasks/Event.java @@ -2,20 +2,23 @@ import main.enums.TaskType; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + public class Event extends Task{ - protected String eventTime; + protected LocalDateTime eventTime; public Event(String description, String eventTime) { super(description, TaskType.Event); - this.eventTime = eventTime; + this.eventTime = LocalDateTime.parse(eventTime, DateTimeFormatter.ofPattern("yyyy-MM-dd kkmm")); } public Event(String description, String eventTime, boolean isDone) { super(description, TaskType.Event, isDone); - this.eventTime = eventTime; + this.eventTime = LocalDateTime.parse(eventTime, DateTimeFormatter.ofPattern("yyyy-MM-dd kkmm")); } - public String getEventTime() { + public LocalDateTime getEventTime() { return this.eventTime; } @@ -26,6 +29,7 @@ public String toStoreString() { @Override public String toString() { - return super.toString() + String.format(" (at: %s)", this.getEventTime()); + return super.toString() + String.format(" (at: %s)", + this.getEventTime().format(DateTimeFormatter.ofPattern("dd/MMM/yyyy HH:mm"))); } } From 325bed9b0202d36da4f3c2db0bc47214222110be Mon Sep 17 00:00:00 2001 From: TeddYE Date: Tue, 1 Feb 2022 13:20:50 +0800 Subject: [PATCH 13/32] Refactor the code to extract out closely related code as classes Let's: * add TaskList class * add Ui class --- data/duke.txt | 3 +-- src/main/Duke.java | 28 +++++++++++++++------ src/main/TaskList.java | 33 +++++++++++++++++++++++++ src/main/Ui.java | 42 ++++++++++++++++++++++++++++++++ src/main/commands/CBye.java | 7 +++--- src/main/commands/CDeadline.java | 9 ++++--- src/main/commands/CDelete.java | 11 +++++---- src/main/commands/CEvent.java | 9 ++++--- src/main/commands/CList.java | 15 ++++-------- src/main/commands/CMark.java | 9 ++++--- src/main/commands/CTodo.java | 9 ++++--- src/main/commands/CUnmark.java | 9 ++++--- src/main/commands/Command.java | 4 ++- src/main/io/Storage.java | 21 ++++++++-------- src/main/tasks/Deadline.java | 6 ++--- src/main/tasks/Event.java | 6 ++--- src/main/tasks/Task.java | 24 ------------------ 17 files changed, 157 insertions(+), 88 deletions(-) create mode 100644 src/main/TaskList.java create mode 100644 src/main/Ui.java diff --git a/data/duke.txt b/data/duke.txt index 53395bf98d..56b54e18a4 100644 --- a/data/duke.txt +++ b/data/duke.txt @@ -1,2 +1 @@ -T~1~1 -D~0~1~1990-10-20T12:34 +D~0~1~1111-11-11 1111 diff --git a/src/main/Duke.java b/src/main/Duke.java index ebf42f1b02..bbb2118e0d 100644 --- a/src/main/Duke.java +++ b/src/main/Duke.java @@ -9,20 +9,34 @@ public class Duke { private static final String WELCOME_MESSAGE = "Hello! I'm Duke \n" + "What can I do for you"; - public static void main(String[] args) throws DukeException { + private Storage storage; + private TaskList taskList; + private Ui ui; + private Parser parser; + + public Duke(String dirname, String filename) { + this.storage = new Storage(dirname, filename); + this.taskList = new TaskList(); + this.ui = new Ui(); + this.parser = new Parser(); + } + + public void run() throws DukeException{ Scanner sc = new Scanner(System.in); - Parser parser = new Parser(); - Storage storage = new Storage("data", "duke.txt"); - storage.readFile(); + this.storage.readFile(this.taskList); System.out.println(WELCOME_MESSAGE); while (!Command.getIsExit()) { - Command newCommand = parser.parse(sc.nextLine()); - newCommand.runCommand(); + Command newCommand = this.parser.parse(sc.nextLine()); + newCommand.runCommand(this.ui, this.taskList); } - storage.writeFile(); + storage.writeFile(this.taskList); + } + + public static void main(String[] args) throws DukeException { + new Duke("data", "duke.txt").run(); } } diff --git a/src/main/TaskList.java b/src/main/TaskList.java new file mode 100644 index 0000000000..9190eee9b4 --- /dev/null +++ b/src/main/TaskList.java @@ -0,0 +1,33 @@ +package main; + +import main.tasks.Task; + +import java.util.ArrayList; + +public class TaskList { + private ArrayList Tasks; + + public TaskList() { + this.Tasks = new ArrayList<>(); + } + + public Task getTask(int taskIndex) { + return this.Tasks.get(taskIndex); + } + + public void addTask(Task newTask) { + this.Tasks.add(newTask); + } + + public void deleteTask(int taskIndex) { + this.Tasks.remove(taskIndex); + } + + public int getTasksCount() { + return this.Tasks.size(); + } + + public String taskCountToString() { + return String.format("Now you have %d task(s) in the list.", this.getTasksCount()); + } +} diff --git a/src/main/Ui.java b/src/main/Ui.java new file mode 100644 index 0000000000..6a5d754169 --- /dev/null +++ b/src/main/Ui.java @@ -0,0 +1,42 @@ +package main; + +import main.tasks.Task; + +public class Ui { + private static final String GOODBYE_MESSAGE = "Bye. Hope to see you again soon!"; + + public void respondBye() { + System.out.println(Ui.GOODBYE_MESSAGE); + } + + public void respondList(TaskList taskList) { + int n = taskList.getTasksCount(); + if (n == 0) { + System.out.println("The list is currently empty."); + } else { + for (int i = 0; i < n; i++) { + System.out.printf("%d.%s%n", i + 1, taskList.getTask(i)); + } + } + } + + public void respondMark(Task markTask) { + System.out.printf("Nice! I've marked this task as done: \n" + + " %s\n", markTask); + } + + public void respondUnmark(Task unmarkTask) { + System.out.printf("Nice! I've marked this task as done: \n" + + " %s\n", unmarkTask); + } + + public void respondAddTask(Task newTask, TaskList taskList) { + System.out.printf("Got it. I've added this task:\n" + "%s\n" + "%s\n", + newTask, taskList.taskCountToString()); + } + + public void respondDeleteTask(Task deleteTask, TaskList taskList) { + System.out.printf("Noted. I've removed this task: \n" + " %s\n" + + "%s\n", deleteTask, taskList.taskCountToString()); + } +} diff --git a/src/main/commands/CBye.java b/src/main/commands/CBye.java index 5a59e330a5..17d133bff4 100644 --- a/src/main/commands/CBye.java +++ b/src/main/commands/CBye.java @@ -1,17 +1,18 @@ package main.commands; +import main.TaskList; +import main.Ui; import main.enums.CommandType; public class CBye extends Command{ - private static final String GOODBYE_MESSAGE = "Bye. Hope to see you again soon!"; public CBye() { super(CommandType.BYE); } @Override - public void runCommand() { + public void runCommand(Ui ui, TaskList taskList) { Command.exitDuke(); - System.out.println(GOODBYE_MESSAGE); + ui.respondBye(); } } diff --git a/src/main/commands/CDeadline.java b/src/main/commands/CDeadline.java index 0872587f9e..b1bae7ef55 100644 --- a/src/main/commands/CDeadline.java +++ b/src/main/commands/CDeadline.java @@ -1,5 +1,7 @@ package main.commands; +import main.TaskList; +import main.Ui; import main.enums.CommandType; import main.tasks.Deadline; import main.tasks.Task; @@ -23,10 +25,9 @@ public String getDescription() { } @Override - public void runCommand() { + public void runCommand(Ui ui, TaskList taskList) { Task newDeadline = new Deadline(this.getDescription(), this.getDueDate()); - Task.addTask(newDeadline); - System.out.printf("Got it. I've added this task:\n" + "%s\n" + "%s\n", - newDeadline, Task.taskCountToString()); + taskList.addTask(newDeadline); + ui.respondAddTask(newDeadline, taskList); } } diff --git a/src/main/commands/CDelete.java b/src/main/commands/CDelete.java index 50291c81c8..717686b01d 100644 --- a/src/main/commands/CDelete.java +++ b/src/main/commands/CDelete.java @@ -1,6 +1,8 @@ package main.commands; import main.DukeException; +import main.TaskList; +import main.Ui; import main.enums.CommandType; import main.tasks.Task; @@ -17,12 +19,11 @@ public int getDeleteIndex() { } @Override - public void runCommand() throws DukeException { + public void runCommand(Ui ui, TaskList taskList) throws DukeException { try { - Task deleteTask = Task.getTask(this.getDeleteIndex()); - Task.deleteTask(this.getDeleteIndex()); - System.out.printf("Noted. I've removed this task: \n" + " %s\n" - + "%s\n", deleteTask, Task.taskCountToString()); + Task deleteTask = taskList.getTask(this.getDeleteIndex()); + taskList.deleteTask(this.getDeleteIndex()); + ui.respondDeleteTask(deleteTask, taskList); } catch (IndexOutOfBoundsException e) { throw new DukeException("Please check that you have entered the correct index."); } diff --git a/src/main/commands/CEvent.java b/src/main/commands/CEvent.java index 5a81766717..2f7ce7418b 100644 --- a/src/main/commands/CEvent.java +++ b/src/main/commands/CEvent.java @@ -1,5 +1,7 @@ package main.commands; +import main.TaskList; +import main.Ui; import main.enums.CommandType; import main.tasks.Event; import main.tasks.Task; @@ -24,10 +26,9 @@ public String getDescription() { @Override - public void runCommand() { + public void runCommand(Ui ui, TaskList taskList) { Task newEvent = new Event(this.getDescription(), this.getDateTime()); - Task.addTask(newEvent); - System.out.printf("Got it. I've added this task:\n" + "%s\n" + "%s\n", - newEvent, Task.taskCountToString()); + taskList.addTask(newEvent); + ui.respondAddTask(newEvent, taskList); } } diff --git a/src/main/commands/CList.java b/src/main/commands/CList.java index 44d537df9a..04e34a3fb4 100644 --- a/src/main/commands/CList.java +++ b/src/main/commands/CList.java @@ -1,22 +1,17 @@ package main.commands; +import main.TaskList; +import main.Ui; import main.enums.CommandType; import main.tasks.Task; -public class CList extends Command{ +public class CList extends Command { public CList() { super(CommandType.LIST); } @Override - public void runCommand() { - int n = Task.getTasksCount(); - if (n == 0) { - System.out.println("The list is currently empty."); - } else { - for (int i = 0; i < n; i++) { - System.out.printf("%d.%s%n", i + 1, Task.getTask(i)); - } - } + public void runCommand(Ui ui, TaskList taskList) { + ui.respondList(taskList); } } diff --git a/src/main/commands/CMark.java b/src/main/commands/CMark.java index b6cae343eb..920dbf5094 100644 --- a/src/main/commands/CMark.java +++ b/src/main/commands/CMark.java @@ -1,6 +1,8 @@ package main.commands; import main.DukeException; +import main.TaskList; +import main.Ui; import main.enums.CommandType; import main.tasks.Task; @@ -17,12 +19,11 @@ public int getMarkIndex() { } @Override - public void runCommand() throws DukeException { + public void runCommand(Ui ui, TaskList taskList) throws DukeException { try { - Task markTask = Task.getTask(this.getMarkIndex()); + Task markTask = taskList.getTask(this.getMarkIndex()); markTask.setIsDone(true); - System.out.printf("Nice! I've marked this task as done: \n" - + " %s\n", markTask); + ui.respondMark(markTask); } catch (IndexOutOfBoundsException e) { throw new DukeException("Please check that you have entered the correct index."); } diff --git a/src/main/commands/CTodo.java b/src/main/commands/CTodo.java index e78cccd2a8..fdbc5c4aaf 100644 --- a/src/main/commands/CTodo.java +++ b/src/main/commands/CTodo.java @@ -1,5 +1,7 @@ package main.commands; +import main.TaskList; +import main.Ui; import main.enums.CommandType; import main.tasks.Task; import main.tasks.ToDo; @@ -17,10 +19,9 @@ public String getDescription() { } @Override - public void runCommand() { + public void runCommand(Ui ui, TaskList taskList) { Task newToDo = new ToDo(this.getDescription()); - Task.addTask(newToDo); - System.out.printf("Got it. I've added this task:\n" + "%s\n" + "%s\n", - newToDo, Task.taskCountToString()); + taskList.addTask(newToDo); + ui.respondAddTask(newToDo, taskList); } } diff --git a/src/main/commands/CUnmark.java b/src/main/commands/CUnmark.java index 5cd37877eb..3d7745c709 100644 --- a/src/main/commands/CUnmark.java +++ b/src/main/commands/CUnmark.java @@ -1,6 +1,8 @@ package main.commands; import main.DukeException; +import main.TaskList; +import main.Ui; import main.enums.CommandType; import main.tasks.Task; @@ -17,12 +19,11 @@ public int getUnmarkIndex() { } @Override - public void runCommand() throws DukeException { + public void runCommand(Ui ui, TaskList taskList) throws DukeException { try { - Task unmarkTask = Task.getTask(this.getUnmarkIndex()); + Task unmarkTask = taskList.getTask(this.getUnmarkIndex()); unmarkTask.setIsDone(false); - System.out.printf("Ok, I've marked this task as not done yet: \n" - + " %s\n", unmarkTask); + ui.respondUnmark(unmarkTask); } catch (IndexOutOfBoundsException e) { throw new DukeException("Please check that you have entered the correct index."); } diff --git a/src/main/commands/Command.java b/src/main/commands/Command.java index 9ca5b11907..c3fccd4c15 100644 --- a/src/main/commands/Command.java +++ b/src/main/commands/Command.java @@ -1,6 +1,8 @@ package main.commands; import main.DukeException; +import main.TaskList; +import main.Ui; import main.enums.CommandType; public abstract class Command { @@ -18,5 +20,5 @@ public Command(CommandType commandType) { public CommandType getCommandType() { return this.commandType; } - public abstract void runCommand() throws DukeException; + public abstract void runCommand(Ui ui, TaskList taskList) throws DukeException; } diff --git a/src/main/io/Storage.java b/src/main/io/Storage.java index 69c4b7d6e0..58b75bdf38 100644 --- a/src/main/io/Storage.java +++ b/src/main/io/Storage.java @@ -1,6 +1,7 @@ package main.io; import main.DukeException; +import main.TaskList; import main.tasks.Deadline; import main.tasks.Event; import main.tasks.Task; @@ -55,14 +56,14 @@ private void createFile(){ } } - public void readFile() { + public void readFile(TaskList taskList) { try { File dukeFile = new File(String.format("%s/%s", this.getDirname(), this.getFilename())); Scanner dukeReader = new Scanner(dukeFile); while (dukeReader.hasNextLine()) { String taskString = dukeReader.nextLine(); String[] taskStringArray = taskString.split("~"); - this.addToTasks(taskStringArray); + this.addToTasks(taskStringArray, taskList); } dukeReader.close(); } catch (IOException e) { @@ -72,24 +73,24 @@ public void readFile() { } } - public void addToTasks(String[] taskStringArray) throws DukeException { + public void addToTasks(String[] taskStringArray, TaskList taskList) throws DukeException { String type = taskStringArray[0]; boolean isDone = taskStringArray[1].equals("1"); String description = taskStringArray[2]; switch (type) { case "T": - Task.addTask(new ToDo(description, isDone)); + taskList.addTask(new ToDo(description, isDone)); break; case "D": try { - Task.addTask(new Deadline(description, taskStringArray[3], isDone)); + taskList.addTask(new Deadline(description, taskStringArray[3], isDone)); } catch (DateTimeParseException e){ throw new DukeException("Save file date time not in this format YYYY-MM-DD 0000"); } break; case "E": try { - Task.addTask(new Event(description, taskStringArray[3], isDone)); + taskList.addTask(new Event(description, taskStringArray[3], isDone)); } catch (DateTimeParseException e){ throw new DukeException("Save file date time not in this format YYYY-MM-DD 0000"); } @@ -97,12 +98,12 @@ public void addToTasks(String[] taskStringArray) throws DukeException { } } - public void writeFile() { + public void writeFile(TaskList taskList) { try { FileWriter dukeWriter = new FileWriter(String.format("%s/%s", this.getDirname(), this.getFilename())); - for (int i = 0; i < Task.getTasksCount(); i++) { - if (i != Task.getTasksCount()) { - dukeWriter.write(Task.getTask(i).toStoreString() + "\n"); + for (int i = 0; i < taskList.getTasksCount(); i++) { + if (i != taskList.getTasksCount()) { + dukeWriter.write(taskList.getTask(i).toStoreString() + "\n"); } } dukeWriter.close(); diff --git a/src/main/tasks/Deadline.java b/src/main/tasks/Deadline.java index 6edd45f137..5582257f76 100644 --- a/src/main/tasks/Deadline.java +++ b/src/main/tasks/Deadline.java @@ -10,12 +10,12 @@ public class Deadline extends Task{ public Deadline(String description, String dueDate) { super(description, TaskType.DEADLINE); - this.dueDate = LocalDateTime.parse(dueDate, DateTimeFormatter.ofPattern("yyyy-MM-dd kkmm")); + this.dueDate = LocalDateTime.parse(dueDate, DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm")); } public Deadline(String description, String dueDate, boolean isDone) { super(description, TaskType.DEADLINE, isDone); - this.dueDate = LocalDateTime.parse(dueDate, DateTimeFormatter.ofPattern("yyyy-MM-dd kkmm")); + this.dueDate = LocalDateTime.parse(dueDate, DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm")); } public LocalDateTime getDueDate() { @@ -24,7 +24,7 @@ public LocalDateTime getDueDate() { @Override public String toStoreString() { - return super.toStoreString() + "~" + this.getDueDate(); + return super.toStoreString() + "~" + this.getDueDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm")); } @Override diff --git a/src/main/tasks/Event.java b/src/main/tasks/Event.java index 60b7c12f0b..839ef28530 100644 --- a/src/main/tasks/Event.java +++ b/src/main/tasks/Event.java @@ -10,12 +10,12 @@ public class Event extends Task{ public Event(String description, String eventTime) { super(description, TaskType.Event); - this.eventTime = LocalDateTime.parse(eventTime, DateTimeFormatter.ofPattern("yyyy-MM-dd kkmm")); + this.eventTime = LocalDateTime.parse(eventTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm")); } public Event(String description, String eventTime, boolean isDone) { super(description, TaskType.Event, isDone); - this.eventTime = LocalDateTime.parse(eventTime, DateTimeFormatter.ofPattern("yyyy-MM-dd kkmm")); + this.eventTime = LocalDateTime.parse(eventTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm")); } public LocalDateTime getEventTime() { @@ -24,7 +24,7 @@ public LocalDateTime getEventTime() { @Override public String toStoreString() { - return super.toStoreString() + "~" + this.getEventTime(); + return super.toStoreString() + "~" + this.getEventTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm")); } @Override diff --git a/src/main/tasks/Task.java b/src/main/tasks/Task.java index 8ca87e2ed5..645b4cd4d4 100644 --- a/src/main/tasks/Task.java +++ b/src/main/tasks/Task.java @@ -8,8 +8,6 @@ public abstract class Task { protected TaskType taskType; protected boolean isDone; - protected static final ArrayList TASKS = new ArrayList<>(); - public Task(String description, TaskType taskType) { this.description = description; this.taskType = taskType; @@ -22,28 +20,6 @@ public Task(String description, TaskType taskType, boolean isDone) { this.isDone = isDone; } - public static ArrayList getTasks() { - return Task.TASKS; - } - - public static void addTask(Task newTask) { - Task.TASKS.add(newTask); - } - - public static void deleteTask(int taskIndex) { Task.TASKS.remove(taskIndex); } - - public static Task getTask(int taskIndex) { - return Task.TASKS.get(taskIndex); - } - - public static int getTasksCount() { - return Task.TASKS.size(); - } - - public static String taskCountToString() { - return String.format("Now you have %d task(s) in the list.", Task.getTasksCount()); - } - public String getDescription() { return this.description; } From c0f4f9e745d00fbeff8b0f9848cddb3c114d9439 Mon Sep 17 00:00:00 2001 From: TeddYE Date: Tue, 1 Feb 2022 13:24:17 +0800 Subject: [PATCH 14/32] Organize the classes into suitable java packages --- src/main/{ => duke}/Duke.java | 8 ++++---- src/main/{ => duke}/DukeException.java | 2 +- src/main/{ => duke}/TaskList.java | 4 ++-- src/main/{ => duke}/Ui.java | 4 ++-- src/main/{ => duke}/commands/CBye.java | 8 ++++---- src/main/{ => duke}/commands/CDeadline.java | 12 +++++------ src/main/{ => duke}/commands/CDelete.java | 12 +++++------ src/main/{ => duke}/commands/CEvent.java | 12 +++++------ src/main/{ => duke}/commands/CList.java | 9 ++++----- src/main/{ => duke}/commands/CMark.java | 12 +++++------ src/main/{ => duke}/commands/CTodo.java | 12 +++++------ src/main/{ => duke}/commands/CUnmark.java | 12 +++++------ src/main/{ => duke}/commands/Command.java | 10 +++++----- src/main/{ => duke}/enums/CommandType.java | 2 +- src/main/{ => duke}/enums/TaskType.java | 2 +- src/main/{ => duke}/io/Parser.java | 22 ++++++++++----------- src/main/{ => duke}/io/Storage.java | 13 ++++++------ src/main/{ => duke}/tasks/Deadline.java | 4 ++-- src/main/{ => duke}/tasks/Event.java | 4 ++-- src/main/{ => duke}/tasks/Task.java | 5 ++--- src/main/{ => duke}/tasks/ToDo.java | 4 ++-- 21 files changed, 85 insertions(+), 88 deletions(-) rename src/main/{ => duke}/Duke.java (90%) rename src/main/{ => duke}/DukeException.java (87%) rename src/main/{ => duke}/TaskList.java (92%) rename src/main/{ => duke}/Ui.java (96%) rename src/main/{ => duke}/commands/CBye.java (66%) rename src/main/{ => duke}/commands/CDeadline.java (79%) rename src/main/{ => duke}/commands/CDelete.java (80%) rename src/main/{ => duke}/commands/CEvent.java (79%) rename src/main/{ => duke}/commands/CList.java (64%) rename src/main/{ => duke}/commands/CMark.java (79%) rename src/main/{ => duke}/commands/CTodo.java (73%) rename src/main/{ => duke}/commands/CUnmark.java (79%) rename src/main/{ => duke}/commands/Command.java (77%) rename src/main/{ => duke}/enums/CommandType.java (82%) rename src/main/{ => duke}/enums/TaskType.java (90%) rename src/main/{ => duke}/io/Parser.java (93%) rename src/main/{ => duke}/io/Storage.java (95%) rename src/main/{ => duke}/tasks/Deadline.java (94%) rename src/main/{ => duke}/tasks/Event.java (94%) rename src/main/{ => duke}/tasks/Task.java (93%) rename src/main/{ => duke}/tasks/ToDo.java (80%) diff --git a/src/main/Duke.java b/src/main/duke/Duke.java similarity index 90% rename from src/main/Duke.java rename to src/main/duke/Duke.java index bbb2118e0d..e9aff81a7f 100644 --- a/src/main/Duke.java +++ b/src/main/duke/Duke.java @@ -1,8 +1,8 @@ -package main; +package main.duke; -import main.commands.Command; -import main.io.Parser; -import main.io.Storage; +import main.duke.commands.Command; +import main.duke.io.Parser; +import main.duke.io.Storage; import java.util.Scanner; diff --git a/src/main/DukeException.java b/src/main/duke/DukeException.java similarity index 87% rename from src/main/DukeException.java rename to src/main/duke/DukeException.java index 0fa0925e55..35e9a6ebc4 100644 --- a/src/main/DukeException.java +++ b/src/main/duke/DukeException.java @@ -1,4 +1,4 @@ -package main; +package main.duke; public class DukeException extends Exception{ public DukeException (String errorMessage){ diff --git a/src/main/TaskList.java b/src/main/duke/TaskList.java similarity index 92% rename from src/main/TaskList.java rename to src/main/duke/TaskList.java index 9190eee9b4..62e2b4aac4 100644 --- a/src/main/TaskList.java +++ b/src/main/duke/TaskList.java @@ -1,6 +1,6 @@ -package main; +package main.duke; -import main.tasks.Task; +import main.duke.tasks.Task; import java.util.ArrayList; diff --git a/src/main/Ui.java b/src/main/duke/Ui.java similarity index 96% rename from src/main/Ui.java rename to src/main/duke/Ui.java index 6a5d754169..5430d7b194 100644 --- a/src/main/Ui.java +++ b/src/main/duke/Ui.java @@ -1,6 +1,6 @@ -package main; +package main.duke; -import main.tasks.Task; +import main.duke.tasks.Task; public class Ui { private static final String GOODBYE_MESSAGE = "Bye. Hope to see you again soon!"; diff --git a/src/main/commands/CBye.java b/src/main/duke/commands/CBye.java similarity index 66% rename from src/main/commands/CBye.java rename to src/main/duke/commands/CBye.java index 17d133bff4..c90270154f 100644 --- a/src/main/commands/CBye.java +++ b/src/main/duke/commands/CBye.java @@ -1,8 +1,8 @@ -package main.commands; +package main.duke.commands; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; public class CBye extends Command{ diff --git a/src/main/commands/CDeadline.java b/src/main/duke/commands/CDeadline.java similarity index 79% rename from src/main/commands/CDeadline.java rename to src/main/duke/commands/CDeadline.java index b1bae7ef55..b0694a5a1a 100644 --- a/src/main/commands/CDeadline.java +++ b/src/main/duke/commands/CDeadline.java @@ -1,10 +1,10 @@ -package main.commands; +package main.duke.commands; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; -import main.tasks.Deadline; -import main.tasks.Task; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; +import main.duke.tasks.Deadline; +import main.duke.tasks.Task; public class CDeadline extends Command { protected String description; diff --git a/src/main/commands/CDelete.java b/src/main/duke/commands/CDelete.java similarity index 80% rename from src/main/commands/CDelete.java rename to src/main/duke/commands/CDelete.java index 717686b01d..61b82e41ea 100644 --- a/src/main/commands/CDelete.java +++ b/src/main/duke/commands/CDelete.java @@ -1,10 +1,10 @@ -package main.commands; +package main.duke.commands; -import main.DukeException; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; -import main.tasks.Task; +import main.duke.DukeException; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; +import main.duke.tasks.Task; public class CDelete extends Command{ protected int deleteIndex; diff --git a/src/main/commands/CEvent.java b/src/main/duke/commands/CEvent.java similarity index 79% rename from src/main/commands/CEvent.java rename to src/main/duke/commands/CEvent.java index 2f7ce7418b..a39c0ea315 100644 --- a/src/main/commands/CEvent.java +++ b/src/main/duke/commands/CEvent.java @@ -1,10 +1,10 @@ -package main.commands; +package main.duke.commands; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; -import main.tasks.Event; -import main.tasks.Task; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; +import main.duke.tasks.Event; +import main.duke.tasks.Task; public class CEvent extends Command { protected String description; diff --git a/src/main/commands/CList.java b/src/main/duke/commands/CList.java similarity index 64% rename from src/main/commands/CList.java rename to src/main/duke/commands/CList.java index 04e34a3fb4..914e4f1154 100644 --- a/src/main/commands/CList.java +++ b/src/main/duke/commands/CList.java @@ -1,9 +1,8 @@ -package main.commands; +package main.duke.commands; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; -import main.tasks.Task; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; public class CList extends Command { public CList() { diff --git a/src/main/commands/CMark.java b/src/main/duke/commands/CMark.java similarity index 79% rename from src/main/commands/CMark.java rename to src/main/duke/commands/CMark.java index 920dbf5094..ed44f0cece 100644 --- a/src/main/commands/CMark.java +++ b/src/main/duke/commands/CMark.java @@ -1,10 +1,10 @@ -package main.commands; +package main.duke.commands; -import main.DukeException; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; -import main.tasks.Task; +import main.duke.DukeException; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; +import main.duke.tasks.Task; public class CMark extends Command{ protected int markIndex; diff --git a/src/main/commands/CTodo.java b/src/main/duke/commands/CTodo.java similarity index 73% rename from src/main/commands/CTodo.java rename to src/main/duke/commands/CTodo.java index fdbc5c4aaf..e424da5f6e 100644 --- a/src/main/commands/CTodo.java +++ b/src/main/duke/commands/CTodo.java @@ -1,10 +1,10 @@ -package main.commands; +package main.duke.commands; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; -import main.tasks.Task; -import main.tasks.ToDo; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; +import main.duke.tasks.Task; +import main.duke.tasks.ToDo; public class CTodo extends Command{ protected String description; diff --git a/src/main/commands/CUnmark.java b/src/main/duke/commands/CUnmark.java similarity index 79% rename from src/main/commands/CUnmark.java rename to src/main/duke/commands/CUnmark.java index 3d7745c709..cf8210a76f 100644 --- a/src/main/commands/CUnmark.java +++ b/src/main/duke/commands/CUnmark.java @@ -1,10 +1,10 @@ -package main.commands; +package main.duke.commands; -import main.DukeException; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; -import main.tasks.Task; +import main.duke.DukeException; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; +import main.duke.tasks.Task; public class CUnmark extends Command{ protected int unmarkIndex; diff --git a/src/main/commands/Command.java b/src/main/duke/commands/Command.java similarity index 77% rename from src/main/commands/Command.java rename to src/main/duke/commands/Command.java index c3fccd4c15..0be66aa607 100644 --- a/src/main/commands/Command.java +++ b/src/main/duke/commands/Command.java @@ -1,9 +1,9 @@ -package main.commands; +package main.duke.commands; -import main.DukeException; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; +import main.duke.DukeException; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; public abstract class Command { protected CommandType commandType; diff --git a/src/main/enums/CommandType.java b/src/main/duke/enums/CommandType.java similarity index 82% rename from src/main/enums/CommandType.java rename to src/main/duke/enums/CommandType.java index 42fb5665d8..409eed63ff 100644 --- a/src/main/enums/CommandType.java +++ b/src/main/duke/enums/CommandType.java @@ -1,4 +1,4 @@ -package main.enums; +package main.duke.enums; public enum CommandType { BYE, diff --git a/src/main/enums/TaskType.java b/src/main/duke/enums/TaskType.java similarity index 90% rename from src/main/enums/TaskType.java rename to src/main/duke/enums/TaskType.java index 49064b8674..e9fb6f1def 100644 --- a/src/main/enums/TaskType.java +++ b/src/main/duke/enums/TaskType.java @@ -1,4 +1,4 @@ -package main.enums; +package main.duke.enums; public enum TaskType { TODO("T"), diff --git a/src/main/io/Parser.java b/src/main/duke/io/Parser.java similarity index 93% rename from src/main/io/Parser.java rename to src/main/duke/io/Parser.java index 6e82ce7691..927c0a6857 100644 --- a/src/main/io/Parser.java +++ b/src/main/duke/io/Parser.java @@ -1,15 +1,15 @@ -package main.io; +package main.duke.io; -import main.commands.Command; -import main.commands.CBye; -import main.commands.CMark; -import main.commands.CDelete; -import main.commands.CList; -import main.commands.CTodo; -import main.commands.CDeadline; -import main.commands.CEvent; -import main.commands.CUnmark; -import main.DukeException; +import main.duke.commands.Command; +import main.duke.commands.CBye; +import main.duke.commands.CMark; +import main.duke.commands.CDelete; +import main.duke.commands.CList; +import main.duke.commands.CTodo; +import main.duke.commands.CDeadline; +import main.duke.commands.CEvent; +import main.duke.commands.CUnmark; +import main.duke.DukeException; import java.util.Arrays; diff --git a/src/main/io/Storage.java b/src/main/duke/io/Storage.java similarity index 95% rename from src/main/io/Storage.java rename to src/main/duke/io/Storage.java index 58b75bdf38..6260ffbc3d 100644 --- a/src/main/io/Storage.java +++ b/src/main/duke/io/Storage.java @@ -1,11 +1,10 @@ -package main.io; +package main.duke.io; -import main.DukeException; -import main.TaskList; -import main.tasks.Deadline; -import main.tasks.Event; -import main.tasks.Task; -import main.tasks.ToDo; +import main.duke.DukeException; +import main.duke.TaskList; +import main.duke.tasks.Deadline; +import main.duke.tasks.Event; +import main.duke.tasks.ToDo; import java.io.File; import java.io.FileWriter; diff --git a/src/main/tasks/Deadline.java b/src/main/duke/tasks/Deadline.java similarity index 94% rename from src/main/tasks/Deadline.java rename to src/main/duke/tasks/Deadline.java index 5582257f76..daaba2299d 100644 --- a/src/main/tasks/Deadline.java +++ b/src/main/duke/tasks/Deadline.java @@ -1,6 +1,6 @@ -package main.tasks; +package main.duke.tasks; -import main.enums.TaskType; +import main.duke.enums.TaskType; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; diff --git a/src/main/tasks/Event.java b/src/main/duke/tasks/Event.java similarity index 94% rename from src/main/tasks/Event.java rename to src/main/duke/tasks/Event.java index 839ef28530..65cdb5a86b 100644 --- a/src/main/tasks/Event.java +++ b/src/main/duke/tasks/Event.java @@ -1,6 +1,6 @@ -package main.tasks; +package main.duke.tasks; -import main.enums.TaskType; +import main.duke.enums.TaskType; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; diff --git a/src/main/tasks/Task.java b/src/main/duke/tasks/Task.java similarity index 93% rename from src/main/tasks/Task.java rename to src/main/duke/tasks/Task.java index 645b4cd4d4..8bcfc1a921 100644 --- a/src/main/tasks/Task.java +++ b/src/main/duke/tasks/Task.java @@ -1,7 +1,6 @@ -package main.tasks; +package main.duke.tasks; -import main.enums.TaskType; -import java.util.ArrayList; +import main.duke.enums.TaskType; public abstract class Task { protected String description; diff --git a/src/main/tasks/ToDo.java b/src/main/duke/tasks/ToDo.java similarity index 80% rename from src/main/tasks/ToDo.java rename to src/main/duke/tasks/ToDo.java index 66c011f7e5..ccb8e25cea 100644 --- a/src/main/tasks/ToDo.java +++ b/src/main/duke/tasks/ToDo.java @@ -1,6 +1,6 @@ -package main.tasks; +package main.duke.tasks; -import main.enums.TaskType; +import main.duke.enums.TaskType; public class ToDo extends Task{ public ToDo(String description) { From 96e5e0a5284921f838d099bf71de59e04d8d498c Mon Sep 17 00:00:00 2001 From: TeddYE Date: Tue, 1 Feb 2022 13:45:08 +0800 Subject: [PATCH 15/32] Add JUnit tests to test the behavior of the code --- src/test/duke/DukeTest.java | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/test/duke/DukeTest.java diff --git a/src/test/duke/DukeTest.java b/src/test/duke/DukeTest.java new file mode 100644 index 0000000000..78a45950a2 --- /dev/null +++ b/src/test/duke/DukeTest.java @@ -0,0 +1,34 @@ +import main.duke.DukeException; +import main.duke.commands.CBye; +import main.duke.commands.CDeadline; +import main.duke.commands.Command; +import main.duke.io.Parser; +import org.testng.annotations.Test; + +import static org.testng.AssertJUnit.assertEquals; + +public class DukeTest { + private static Parser parser = new Parser(); + + @Test + public void parseByeTest(){ + Command bye = new CBye(); + try{ + Command parseBye = parser.parse("bye"); + assertEquals(bye.getClass(), parseBye.getClass()); + } + catch(DukeException e){ + System.out.println(e.getMessage()); + } + } + + @Test + public void parseDeadlineTest() { + try { + Command parseDeadline = parser.parse("deadline test /by 1111-11-11 1111"); + assertEquals(parseDeadline.getClass(), CDeadline.class); + } catch (DukeException dukeException) { + System.out.println(dukeException.getMessage()); + } + } +} \ No newline at end of file From 3aad3db8cdf8af1f16c0d01965300d33330ad9a7 Mon Sep 17 00:00:00 2001 From: TeddYE Date: Wed, 2 Feb 2022 15:50:39 +0800 Subject: [PATCH 16/32] Package the app as an executable JAR file --- src/main/{duke => }/Duke.java | 8 ++++---- src/main/{duke => }/DukeException.java | 2 +- src/main/META-INF/MANIFEST.MF | 3 +++ src/main/{duke => }/TaskList.java | 4 ++-- src/main/{duke => }/Ui.java | 4 ++-- src/main/{duke => }/commands/CBye.java | 8 ++++---- src/main/{duke => }/commands/CDeadline.java | 12 +++++------ src/main/{duke => }/commands/CDelete.java | 12 +++++------ src/main/{duke => }/commands/CEvent.java | 12 +++++------ src/main/{duke => }/commands/CList.java | 8 ++++---- src/main/{duke => }/commands/CMark.java | 12 +++++------ src/main/{duke => }/commands/CTodo.java | 12 +++++------ src/main/{duke => }/commands/CUnmark.java | 12 +++++------ src/main/{duke => }/commands/Command.java | 10 +++++----- src/main/{duke => }/enums/CommandType.java | 2 +- src/main/{duke => }/enums/TaskType.java | 2 +- src/main/{duke => }/io/Parser.java | 22 ++++++++++----------- src/main/{duke => }/io/Storage.java | 12 +++++------ src/main/{duke => }/tasks/Deadline.java | 4 ++-- src/main/{duke => }/tasks/Event.java | 4 ++-- src/main/{duke => }/tasks/Task.java | 4 ++-- src/main/{duke => }/tasks/ToDo.java | 4 ++-- src/test/duke/DukeTest.java | 10 +++++----- 23 files changed, 93 insertions(+), 90 deletions(-) rename src/main/{duke => }/Duke.java (90%) rename src/main/{duke => }/DukeException.java (87%) create mode 100644 src/main/META-INF/MANIFEST.MF rename src/main/{duke => }/TaskList.java (92%) rename src/main/{duke => }/Ui.java (96%) rename src/main/{duke => }/commands/CBye.java (66%) rename src/main/{duke => }/commands/CDeadline.java (79%) rename src/main/{duke => }/commands/CDelete.java (80%) rename src/main/{duke => }/commands/CEvent.java (79%) rename src/main/{duke => }/commands/CList.java (65%) rename src/main/{duke => }/commands/CMark.java (79%) rename src/main/{duke => }/commands/CTodo.java (73%) rename src/main/{duke => }/commands/CUnmark.java (79%) rename src/main/{duke => }/commands/Command.java (77%) rename src/main/{duke => }/enums/CommandType.java (82%) rename src/main/{duke => }/enums/TaskType.java (90%) rename src/main/{duke => }/io/Parser.java (93%) rename src/main/{duke => }/io/Storage.java (95%) rename src/main/{duke => }/tasks/Deadline.java (94%) rename src/main/{duke => }/tasks/Event.java (94%) rename src/main/{duke => }/tasks/Task.java (95%) rename src/main/{duke => }/tasks/ToDo.java (80%) diff --git a/src/main/duke/Duke.java b/src/main/Duke.java similarity index 90% rename from src/main/duke/Duke.java rename to src/main/Duke.java index e9aff81a7f..bbb2118e0d 100644 --- a/src/main/duke/Duke.java +++ b/src/main/Duke.java @@ -1,8 +1,8 @@ -package main.duke; +package main; -import main.duke.commands.Command; -import main.duke.io.Parser; -import main.duke.io.Storage; +import main.commands.Command; +import main.io.Parser; +import main.io.Storage; import java.util.Scanner; diff --git a/src/main/duke/DukeException.java b/src/main/DukeException.java similarity index 87% rename from src/main/duke/DukeException.java rename to src/main/DukeException.java index 35e9a6ebc4..0fa0925e55 100644 --- a/src/main/duke/DukeException.java +++ b/src/main/DukeException.java @@ -1,4 +1,4 @@ -package main.duke; +package main; public class DukeException extends Exception{ public DukeException (String errorMessage){ diff --git a/src/main/META-INF/MANIFEST.MF b/src/main/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..ae812494c4 --- /dev/null +++ b/src/main/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: main.Duke + diff --git a/src/main/duke/TaskList.java b/src/main/TaskList.java similarity index 92% rename from src/main/duke/TaskList.java rename to src/main/TaskList.java index 62e2b4aac4..9190eee9b4 100644 --- a/src/main/duke/TaskList.java +++ b/src/main/TaskList.java @@ -1,6 +1,6 @@ -package main.duke; +package main; -import main.duke.tasks.Task; +import main.tasks.Task; import java.util.ArrayList; diff --git a/src/main/duke/Ui.java b/src/main/Ui.java similarity index 96% rename from src/main/duke/Ui.java rename to src/main/Ui.java index 5430d7b194..6a5d754169 100644 --- a/src/main/duke/Ui.java +++ b/src/main/Ui.java @@ -1,6 +1,6 @@ -package main.duke; +package main; -import main.duke.tasks.Task; +import main.tasks.Task; public class Ui { private static final String GOODBYE_MESSAGE = "Bye. Hope to see you again soon!"; diff --git a/src/main/duke/commands/CBye.java b/src/main/commands/CBye.java similarity index 66% rename from src/main/duke/commands/CBye.java rename to src/main/commands/CBye.java index c90270154f..17d133bff4 100644 --- a/src/main/duke/commands/CBye.java +++ b/src/main/commands/CBye.java @@ -1,8 +1,8 @@ -package main.duke.commands; +package main.commands; -import main.duke.TaskList; -import main.duke.Ui; -import main.duke.enums.CommandType; +import main.TaskList; +import main.Ui; +import main.enums.CommandType; public class CBye extends Command{ diff --git a/src/main/duke/commands/CDeadline.java b/src/main/commands/CDeadline.java similarity index 79% rename from src/main/duke/commands/CDeadline.java rename to src/main/commands/CDeadline.java index b0694a5a1a..b1bae7ef55 100644 --- a/src/main/duke/commands/CDeadline.java +++ b/src/main/commands/CDeadline.java @@ -1,10 +1,10 @@ -package main.duke.commands; +package main.commands; -import main.duke.TaskList; -import main.duke.Ui; -import main.duke.enums.CommandType; -import main.duke.tasks.Deadline; -import main.duke.tasks.Task; +import main.TaskList; +import main.Ui; +import main.enums.CommandType; +import main.tasks.Deadline; +import main.tasks.Task; public class CDeadline extends Command { protected String description; diff --git a/src/main/duke/commands/CDelete.java b/src/main/commands/CDelete.java similarity index 80% rename from src/main/duke/commands/CDelete.java rename to src/main/commands/CDelete.java index 61b82e41ea..717686b01d 100644 --- a/src/main/duke/commands/CDelete.java +++ b/src/main/commands/CDelete.java @@ -1,10 +1,10 @@ -package main.duke.commands; +package main.commands; -import main.duke.DukeException; -import main.duke.TaskList; -import main.duke.Ui; -import main.duke.enums.CommandType; -import main.duke.tasks.Task; +import main.DukeException; +import main.TaskList; +import main.Ui; +import main.enums.CommandType; +import main.tasks.Task; public class CDelete extends Command{ protected int deleteIndex; diff --git a/src/main/duke/commands/CEvent.java b/src/main/commands/CEvent.java similarity index 79% rename from src/main/duke/commands/CEvent.java rename to src/main/commands/CEvent.java index a39c0ea315..2f7ce7418b 100644 --- a/src/main/duke/commands/CEvent.java +++ b/src/main/commands/CEvent.java @@ -1,10 +1,10 @@ -package main.duke.commands; +package main.commands; -import main.duke.TaskList; -import main.duke.Ui; -import main.duke.enums.CommandType; -import main.duke.tasks.Event; -import main.duke.tasks.Task; +import main.TaskList; +import main.Ui; +import main.enums.CommandType; +import main.tasks.Event; +import main.tasks.Task; public class CEvent extends Command { protected String description; diff --git a/src/main/duke/commands/CList.java b/src/main/commands/CList.java similarity index 65% rename from src/main/duke/commands/CList.java rename to src/main/commands/CList.java index 914e4f1154..d9490d29bc 100644 --- a/src/main/duke/commands/CList.java +++ b/src/main/commands/CList.java @@ -1,8 +1,8 @@ -package main.duke.commands; +package main.commands; -import main.duke.TaskList; -import main.duke.Ui; -import main.duke.enums.CommandType; +import main.TaskList; +import main.Ui; +import main.enums.CommandType; public class CList extends Command { public CList() { diff --git a/src/main/duke/commands/CMark.java b/src/main/commands/CMark.java similarity index 79% rename from src/main/duke/commands/CMark.java rename to src/main/commands/CMark.java index ed44f0cece..920dbf5094 100644 --- a/src/main/duke/commands/CMark.java +++ b/src/main/commands/CMark.java @@ -1,10 +1,10 @@ -package main.duke.commands; +package main.commands; -import main.duke.DukeException; -import main.duke.TaskList; -import main.duke.Ui; -import main.duke.enums.CommandType; -import main.duke.tasks.Task; +import main.DukeException; +import main.TaskList; +import main.Ui; +import main.enums.CommandType; +import main.tasks.Task; public class CMark extends Command{ protected int markIndex; diff --git a/src/main/duke/commands/CTodo.java b/src/main/commands/CTodo.java similarity index 73% rename from src/main/duke/commands/CTodo.java rename to src/main/commands/CTodo.java index e424da5f6e..fdbc5c4aaf 100644 --- a/src/main/duke/commands/CTodo.java +++ b/src/main/commands/CTodo.java @@ -1,10 +1,10 @@ -package main.duke.commands; +package main.commands; -import main.duke.TaskList; -import main.duke.Ui; -import main.duke.enums.CommandType; -import main.duke.tasks.Task; -import main.duke.tasks.ToDo; +import main.TaskList; +import main.Ui; +import main.enums.CommandType; +import main.tasks.Task; +import main.tasks.ToDo; public class CTodo extends Command{ protected String description; diff --git a/src/main/duke/commands/CUnmark.java b/src/main/commands/CUnmark.java similarity index 79% rename from src/main/duke/commands/CUnmark.java rename to src/main/commands/CUnmark.java index cf8210a76f..3d7745c709 100644 --- a/src/main/duke/commands/CUnmark.java +++ b/src/main/commands/CUnmark.java @@ -1,10 +1,10 @@ -package main.duke.commands; +package main.commands; -import main.duke.DukeException; -import main.duke.TaskList; -import main.duke.Ui; -import main.duke.enums.CommandType; -import main.duke.tasks.Task; +import main.DukeException; +import main.TaskList; +import main.Ui; +import main.enums.CommandType; +import main.tasks.Task; public class CUnmark extends Command{ protected int unmarkIndex; diff --git a/src/main/duke/commands/Command.java b/src/main/commands/Command.java similarity index 77% rename from src/main/duke/commands/Command.java rename to src/main/commands/Command.java index 0be66aa607..c3fccd4c15 100644 --- a/src/main/duke/commands/Command.java +++ b/src/main/commands/Command.java @@ -1,9 +1,9 @@ -package main.duke.commands; +package main.commands; -import main.duke.DukeException; -import main.duke.TaskList; -import main.duke.Ui; -import main.duke.enums.CommandType; +import main.DukeException; +import main.TaskList; +import main.Ui; +import main.enums.CommandType; public abstract class Command { protected CommandType commandType; diff --git a/src/main/duke/enums/CommandType.java b/src/main/enums/CommandType.java similarity index 82% rename from src/main/duke/enums/CommandType.java rename to src/main/enums/CommandType.java index 409eed63ff..42fb5665d8 100644 --- a/src/main/duke/enums/CommandType.java +++ b/src/main/enums/CommandType.java @@ -1,4 +1,4 @@ -package main.duke.enums; +package main.enums; public enum CommandType { BYE, diff --git a/src/main/duke/enums/TaskType.java b/src/main/enums/TaskType.java similarity index 90% rename from src/main/duke/enums/TaskType.java rename to src/main/enums/TaskType.java index e9fb6f1def..49064b8674 100644 --- a/src/main/duke/enums/TaskType.java +++ b/src/main/enums/TaskType.java @@ -1,4 +1,4 @@ -package main.duke.enums; +package main.enums; public enum TaskType { TODO("T"), diff --git a/src/main/duke/io/Parser.java b/src/main/io/Parser.java similarity index 93% rename from src/main/duke/io/Parser.java rename to src/main/io/Parser.java index 927c0a6857..6e82ce7691 100644 --- a/src/main/duke/io/Parser.java +++ b/src/main/io/Parser.java @@ -1,15 +1,15 @@ -package main.duke.io; +package main.io; -import main.duke.commands.Command; -import main.duke.commands.CBye; -import main.duke.commands.CMark; -import main.duke.commands.CDelete; -import main.duke.commands.CList; -import main.duke.commands.CTodo; -import main.duke.commands.CDeadline; -import main.duke.commands.CEvent; -import main.duke.commands.CUnmark; -import main.duke.DukeException; +import main.commands.Command; +import main.commands.CBye; +import main.commands.CMark; +import main.commands.CDelete; +import main.commands.CList; +import main.commands.CTodo; +import main.commands.CDeadline; +import main.commands.CEvent; +import main.commands.CUnmark; +import main.DukeException; import java.util.Arrays; diff --git a/src/main/duke/io/Storage.java b/src/main/io/Storage.java similarity index 95% rename from src/main/duke/io/Storage.java rename to src/main/io/Storage.java index 6260ffbc3d..909e3d08f0 100644 --- a/src/main/duke/io/Storage.java +++ b/src/main/io/Storage.java @@ -1,10 +1,10 @@ -package main.duke.io; +package main.io; -import main.duke.DukeException; -import main.duke.TaskList; -import main.duke.tasks.Deadline; -import main.duke.tasks.Event; -import main.duke.tasks.ToDo; +import main.DukeException; +import main.TaskList; +import main.tasks.Deadline; +import main.tasks.Event; +import main.tasks.ToDo; import java.io.File; import java.io.FileWriter; diff --git a/src/main/duke/tasks/Deadline.java b/src/main/tasks/Deadline.java similarity index 94% rename from src/main/duke/tasks/Deadline.java rename to src/main/tasks/Deadline.java index daaba2299d..5582257f76 100644 --- a/src/main/duke/tasks/Deadline.java +++ b/src/main/tasks/Deadline.java @@ -1,6 +1,6 @@ -package main.duke.tasks; +package main.tasks; -import main.duke.enums.TaskType; +import main.enums.TaskType; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; diff --git a/src/main/duke/tasks/Event.java b/src/main/tasks/Event.java similarity index 94% rename from src/main/duke/tasks/Event.java rename to src/main/tasks/Event.java index 65cdb5a86b..839ef28530 100644 --- a/src/main/duke/tasks/Event.java +++ b/src/main/tasks/Event.java @@ -1,6 +1,6 @@ -package main.duke.tasks; +package main.tasks; -import main.duke.enums.TaskType; +import main.enums.TaskType; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; diff --git a/src/main/duke/tasks/Task.java b/src/main/tasks/Task.java similarity index 95% rename from src/main/duke/tasks/Task.java rename to src/main/tasks/Task.java index 8bcfc1a921..652c1a54f2 100644 --- a/src/main/duke/tasks/Task.java +++ b/src/main/tasks/Task.java @@ -1,6 +1,6 @@ -package main.duke.tasks; +package main.tasks; -import main.duke.enums.TaskType; +import main.enums.TaskType; public abstract class Task { protected String description; diff --git a/src/main/duke/tasks/ToDo.java b/src/main/tasks/ToDo.java similarity index 80% rename from src/main/duke/tasks/ToDo.java rename to src/main/tasks/ToDo.java index ccb8e25cea..66c011f7e5 100644 --- a/src/main/duke/tasks/ToDo.java +++ b/src/main/tasks/ToDo.java @@ -1,6 +1,6 @@ -package main.duke.tasks; +package main.tasks; -import main.duke.enums.TaskType; +import main.enums.TaskType; public class ToDo extends Task{ public ToDo(String description) { diff --git a/src/test/duke/DukeTest.java b/src/test/duke/DukeTest.java index 78a45950a2..9d87ed401c 100644 --- a/src/test/duke/DukeTest.java +++ b/src/test/duke/DukeTest.java @@ -1,8 +1,8 @@ -import main.duke.DukeException; -import main.duke.commands.CBye; -import main.duke.commands.CDeadline; -import main.duke.commands.Command; -import main.duke.io.Parser; +import main.DukeException; +import main.commands.CBye; +import main.commands.CDeadline; +import main.commands.Command; +import main.io.Parser; import org.testng.annotations.Test; import static org.testng.AssertJUnit.assertEquals; From 53c09c962ea588788d6b5cbda3de662e5f0c9264 Mon Sep 17 00:00:00 2001 From: TeddYE Date: Wed, 2 Feb 2022 17:08:08 +0800 Subject: [PATCH 17/32] Add JavaDoc comments to the code --- src/main/MANIFEST.MF | 3 +++ src/main/META-INF/MANIFEST.MF | 3 --- src/main/{ => duke}/Duke.java | 8 +++--- src/main/{ => duke}/DukeException.java | 2 +- src/main/{ => duke}/TaskList.java | 4 +-- src/main/{ => duke}/Ui.java | 26 ++++++++++++++++-- src/main/{ => duke}/commands/CBye.java | 8 +++--- src/main/{ => duke}/commands/CDeadline.java | 12 ++++----- src/main/{ => duke}/commands/CDelete.java | 12 ++++----- src/main/{ => duke}/commands/CEvent.java | 12 ++++----- src/main/{ => duke}/commands/CList.java | 8 +++--- src/main/{ => duke}/commands/CMark.java | 12 ++++----- src/main/{ => duke}/commands/CTodo.java | 12 ++++----- src/main/{ => duke}/commands/CUnmark.java | 12 ++++----- src/main/{ => duke}/commands/Command.java | 10 +++---- src/main/{ => duke}/enums/CommandType.java | 2 +- src/main/{ => duke}/enums/TaskType.java | 2 +- src/main/{ => duke}/io/Parser.java | 30 +++++++++++++-------- src/main/{ => duke}/io/Storage.java | 28 ++++++++++++++----- src/main/{ => duke}/tasks/Deadline.java | 4 +-- src/main/{ => duke}/tasks/Event.java | 4 +-- src/main/{ => duke}/tasks/Task.java | 7 +++-- src/main/{ => duke}/tasks/ToDo.java | 4 +-- src/test/duke/DukeTest.java | 10 +++---- 24 files changed, 142 insertions(+), 93 deletions(-) create mode 100644 src/main/MANIFEST.MF delete mode 100644 src/main/META-INF/MANIFEST.MF rename src/main/{ => duke}/Duke.java (90%) rename src/main/{ => duke}/DukeException.java (87%) rename src/main/{ => duke}/TaskList.java (92%) rename src/main/{ => duke}/Ui.java (61%) rename src/main/{ => duke}/commands/CBye.java (66%) rename src/main/{ => duke}/commands/CDeadline.java (79%) rename src/main/{ => duke}/commands/CDelete.java (80%) rename src/main/{ => duke}/commands/CEvent.java (79%) rename src/main/{ => duke}/commands/CList.java (65%) rename src/main/{ => duke}/commands/CMark.java (79%) rename src/main/{ => duke}/commands/CTodo.java (73%) rename src/main/{ => duke}/commands/CUnmark.java (79%) rename src/main/{ => duke}/commands/Command.java (77%) rename src/main/{ => duke}/enums/CommandType.java (82%) rename src/main/{ => duke}/enums/TaskType.java (90%) rename src/main/{ => duke}/io/Parser.java (87%) rename src/main/{ => duke}/io/Storage.java (84%) rename src/main/{ => duke}/tasks/Deadline.java (94%) rename src/main/{ => duke}/tasks/Event.java (94%) rename src/main/{ => duke}/tasks/Task.java (89%) rename src/main/{ => duke}/tasks/ToDo.java (80%) diff --git a/src/main/MANIFEST.MF b/src/main/MANIFEST.MF new file mode 100644 index 0000000000..58202def9f --- /dev/null +++ b/src/main/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: main.duke.Duke + diff --git a/src/main/META-INF/MANIFEST.MF b/src/main/META-INF/MANIFEST.MF deleted file mode 100644 index ae812494c4..0000000000 --- a/src/main/META-INF/MANIFEST.MF +++ /dev/null @@ -1,3 +0,0 @@ -Manifest-Version: 1.0 -Main-Class: main.Duke - diff --git a/src/main/Duke.java b/src/main/duke/Duke.java similarity index 90% rename from src/main/Duke.java rename to src/main/duke/Duke.java index bbb2118e0d..e9aff81a7f 100644 --- a/src/main/Duke.java +++ b/src/main/duke/Duke.java @@ -1,8 +1,8 @@ -package main; +package main.duke; -import main.commands.Command; -import main.io.Parser; -import main.io.Storage; +import main.duke.commands.Command; +import main.duke.io.Parser; +import main.duke.io.Storage; import java.util.Scanner; diff --git a/src/main/DukeException.java b/src/main/duke/DukeException.java similarity index 87% rename from src/main/DukeException.java rename to src/main/duke/DukeException.java index 0fa0925e55..35e9a6ebc4 100644 --- a/src/main/DukeException.java +++ b/src/main/duke/DukeException.java @@ -1,4 +1,4 @@ -package main; +package main.duke; public class DukeException extends Exception{ public DukeException (String errorMessage){ diff --git a/src/main/TaskList.java b/src/main/duke/TaskList.java similarity index 92% rename from src/main/TaskList.java rename to src/main/duke/TaskList.java index 9190eee9b4..62e2b4aac4 100644 --- a/src/main/TaskList.java +++ b/src/main/duke/TaskList.java @@ -1,6 +1,6 @@ -package main; +package main.duke; -import main.tasks.Task; +import main.duke.tasks.Task; import java.util.ArrayList; diff --git a/src/main/Ui.java b/src/main/duke/Ui.java similarity index 61% rename from src/main/Ui.java rename to src/main/duke/Ui.java index 6a5d754169..a64e4e37e2 100644 --- a/src/main/Ui.java +++ b/src/main/duke/Ui.java @@ -1,6 +1,6 @@ -package main; +package main.duke; -import main.tasks.Task; +import main.duke.tasks.Task; public class Ui { private static final String GOODBYE_MESSAGE = "Bye. Hope to see you again soon!"; @@ -9,6 +9,10 @@ public void respondBye() { System.out.println(Ui.GOODBYE_MESSAGE); } + /** + * prints out all the tasks in the current list + * @param taskList the current list of tasks + */ public void respondList(TaskList taskList) { int n = taskList.getTasksCount(); if (n == 0) { @@ -20,21 +24,39 @@ public void respondList(TaskList taskList) { } } + /** + * prints out the task that has been marked + * @param markTask the targeted task to mark + */ public void respondMark(Task markTask) { System.out.printf("Nice! I've marked this task as done: \n" + " %s\n", markTask); } + /** + * prints out the task that has been unmarked + * @param unmarkTask the targeted task to unmark + */ public void respondUnmark(Task unmarkTask) { System.out.printf("Nice! I've marked this task as done: \n" + " %s\n", unmarkTask); } + /** + * prints out the task that has been added as well as the current number of tasks after adding + * @param newTask the targeted task to add + * @param taskList the current list of tasks + */ public void respondAddTask(Task newTask, TaskList taskList) { System.out.printf("Got it. I've added this task:\n" + "%s\n" + "%s\n", newTask, taskList.taskCountToString()); } + /** + * prints out the task that has been added as well as the current number of tasks after removing + * @param deleteTask the targeted task to add + * @param taskList the current list of tasks + */ public void respondDeleteTask(Task deleteTask, TaskList taskList) { System.out.printf("Noted. I've removed this task: \n" + " %s\n" + "%s\n", deleteTask, taskList.taskCountToString()); diff --git a/src/main/commands/CBye.java b/src/main/duke/commands/CBye.java similarity index 66% rename from src/main/commands/CBye.java rename to src/main/duke/commands/CBye.java index 17d133bff4..c90270154f 100644 --- a/src/main/commands/CBye.java +++ b/src/main/duke/commands/CBye.java @@ -1,8 +1,8 @@ -package main.commands; +package main.duke.commands; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; public class CBye extends Command{ diff --git a/src/main/commands/CDeadline.java b/src/main/duke/commands/CDeadline.java similarity index 79% rename from src/main/commands/CDeadline.java rename to src/main/duke/commands/CDeadline.java index b1bae7ef55..b0694a5a1a 100644 --- a/src/main/commands/CDeadline.java +++ b/src/main/duke/commands/CDeadline.java @@ -1,10 +1,10 @@ -package main.commands; +package main.duke.commands; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; -import main.tasks.Deadline; -import main.tasks.Task; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; +import main.duke.tasks.Deadline; +import main.duke.tasks.Task; public class CDeadline extends Command { protected String description; diff --git a/src/main/commands/CDelete.java b/src/main/duke/commands/CDelete.java similarity index 80% rename from src/main/commands/CDelete.java rename to src/main/duke/commands/CDelete.java index 717686b01d..61b82e41ea 100644 --- a/src/main/commands/CDelete.java +++ b/src/main/duke/commands/CDelete.java @@ -1,10 +1,10 @@ -package main.commands; +package main.duke.commands; -import main.DukeException; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; -import main.tasks.Task; +import main.duke.DukeException; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; +import main.duke.tasks.Task; public class CDelete extends Command{ protected int deleteIndex; diff --git a/src/main/commands/CEvent.java b/src/main/duke/commands/CEvent.java similarity index 79% rename from src/main/commands/CEvent.java rename to src/main/duke/commands/CEvent.java index 2f7ce7418b..a39c0ea315 100644 --- a/src/main/commands/CEvent.java +++ b/src/main/duke/commands/CEvent.java @@ -1,10 +1,10 @@ -package main.commands; +package main.duke.commands; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; -import main.tasks.Event; -import main.tasks.Task; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; +import main.duke.tasks.Event; +import main.duke.tasks.Task; public class CEvent extends Command { protected String description; diff --git a/src/main/commands/CList.java b/src/main/duke/commands/CList.java similarity index 65% rename from src/main/commands/CList.java rename to src/main/duke/commands/CList.java index d9490d29bc..914e4f1154 100644 --- a/src/main/commands/CList.java +++ b/src/main/duke/commands/CList.java @@ -1,8 +1,8 @@ -package main.commands; +package main.duke.commands; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; public class CList extends Command { public CList() { diff --git a/src/main/commands/CMark.java b/src/main/duke/commands/CMark.java similarity index 79% rename from src/main/commands/CMark.java rename to src/main/duke/commands/CMark.java index 920dbf5094..ed44f0cece 100644 --- a/src/main/commands/CMark.java +++ b/src/main/duke/commands/CMark.java @@ -1,10 +1,10 @@ -package main.commands; +package main.duke.commands; -import main.DukeException; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; -import main.tasks.Task; +import main.duke.DukeException; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; +import main.duke.tasks.Task; public class CMark extends Command{ protected int markIndex; diff --git a/src/main/commands/CTodo.java b/src/main/duke/commands/CTodo.java similarity index 73% rename from src/main/commands/CTodo.java rename to src/main/duke/commands/CTodo.java index fdbc5c4aaf..e424da5f6e 100644 --- a/src/main/commands/CTodo.java +++ b/src/main/duke/commands/CTodo.java @@ -1,10 +1,10 @@ -package main.commands; +package main.duke.commands; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; -import main.tasks.Task; -import main.tasks.ToDo; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; +import main.duke.tasks.Task; +import main.duke.tasks.ToDo; public class CTodo extends Command{ protected String description; diff --git a/src/main/commands/CUnmark.java b/src/main/duke/commands/CUnmark.java similarity index 79% rename from src/main/commands/CUnmark.java rename to src/main/duke/commands/CUnmark.java index 3d7745c709..cf8210a76f 100644 --- a/src/main/commands/CUnmark.java +++ b/src/main/duke/commands/CUnmark.java @@ -1,10 +1,10 @@ -package main.commands; +package main.duke.commands; -import main.DukeException; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; -import main.tasks.Task; +import main.duke.DukeException; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; +import main.duke.tasks.Task; public class CUnmark extends Command{ protected int unmarkIndex; diff --git a/src/main/commands/Command.java b/src/main/duke/commands/Command.java similarity index 77% rename from src/main/commands/Command.java rename to src/main/duke/commands/Command.java index c3fccd4c15..0be66aa607 100644 --- a/src/main/commands/Command.java +++ b/src/main/duke/commands/Command.java @@ -1,9 +1,9 @@ -package main.commands; +package main.duke.commands; -import main.DukeException; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; +import main.duke.DukeException; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; public abstract class Command { protected CommandType commandType; diff --git a/src/main/enums/CommandType.java b/src/main/duke/enums/CommandType.java similarity index 82% rename from src/main/enums/CommandType.java rename to src/main/duke/enums/CommandType.java index 42fb5665d8..409eed63ff 100644 --- a/src/main/enums/CommandType.java +++ b/src/main/duke/enums/CommandType.java @@ -1,4 +1,4 @@ -package main.enums; +package main.duke.enums; public enum CommandType { BYE, diff --git a/src/main/enums/TaskType.java b/src/main/duke/enums/TaskType.java similarity index 90% rename from src/main/enums/TaskType.java rename to src/main/duke/enums/TaskType.java index 49064b8674..e9fb6f1def 100644 --- a/src/main/enums/TaskType.java +++ b/src/main/duke/enums/TaskType.java @@ -1,4 +1,4 @@ -package main.enums; +package main.duke.enums; public enum TaskType { TODO("T"), diff --git a/src/main/io/Parser.java b/src/main/duke/io/Parser.java similarity index 87% rename from src/main/io/Parser.java rename to src/main/duke/io/Parser.java index 6e82ce7691..6b6904ec45 100644 --- a/src/main/io/Parser.java +++ b/src/main/duke/io/Parser.java @@ -1,15 +1,15 @@ -package main.io; +package main.duke.io; -import main.commands.Command; -import main.commands.CBye; -import main.commands.CMark; -import main.commands.CDelete; -import main.commands.CList; -import main.commands.CTodo; -import main.commands.CDeadline; -import main.commands.CEvent; -import main.commands.CUnmark; -import main.DukeException; +import main.duke.commands.Command; +import main.duke.commands.CBye; +import main.duke.commands.CMark; +import main.duke.commands.CDelete; +import main.duke.commands.CList; +import main.duke.commands.CTodo; +import main.duke.commands.CDeadline; +import main.duke.commands.CEvent; +import main.duke.commands.CUnmark; +import main.duke.DukeException; import java.util.Arrays; @@ -18,6 +18,12 @@ import java.time.format.DateTimeParseException; public class Parser { + + /** + * @param userInput the whole console command line from the user + * @return Command to be executed + * @throws DukeException when invalid input detected + */ public Command parse(String userInput) throws DukeException { String[] inputArray = userInput.split(" "); String userCommand = inputArray[0]; @@ -79,6 +85,7 @@ public Command parse(String userInput) throws DukeException { String dueDate = String.join(" ", Arrays.copyOfRange(inputArray, byIndex + 1, inputArray.length)); LocalDateTime.parse(dueDate, DateTimeFormatter.ofPattern("yyyy-MM-dd kkmm")); + // check if the date and time input is in the right format if (deadlineDescription.equals("") || dueDate.equals("")) { throw new DukeException("Please specify the description/due date of the deadline task."); } @@ -99,6 +106,7 @@ public Command parse(String userInput) throws DukeException { String dateTime = String.join(" ", Arrays.copyOfRange(inputArray, byIndex + 1, inputArray.length)); LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern("yyyy-MM-dd kkmm")); + // check if the date and time input is in the right format if (eventDescription.equals("") || dateTime.equals("")) { throw new DukeException("Please specify the description/date time of the event task."); } diff --git a/src/main/io/Storage.java b/src/main/duke/io/Storage.java similarity index 84% rename from src/main/io/Storage.java rename to src/main/duke/io/Storage.java index 909e3d08f0..b5b85d11cb 100644 --- a/src/main/io/Storage.java +++ b/src/main/duke/io/Storage.java @@ -1,10 +1,10 @@ -package main.io; +package main.duke.io; -import main.DukeException; -import main.TaskList; -import main.tasks.Deadline; -import main.tasks.Event; -import main.tasks.ToDo; +import main.duke.DukeException; +import main.duke.TaskList; +import main.duke.tasks.Deadline; +import main.duke.tasks.Event; +import main.duke.tasks.ToDo; import java.io.File; import java.io.FileWriter; @@ -42,6 +42,9 @@ private Path getFilePath() { String.format("%s/%s", this.getDirname(), this.getFilename())); } + /** + * create the required directory and file to store the list if it doesn't exist + */ private void createFile(){ try { if (!Files.exists(this.getDirPath())) { @@ -55,6 +58,10 @@ private void createFile(){ } } + /** + * read the file for the saved list and update the list of tasks + * @param taskList empty list of task + */ public void readFile(TaskList taskList) { try { File dukeFile = new File(String.format("%s/%s", this.getDirname(), this.getFilename())); @@ -72,6 +79,11 @@ public void readFile(TaskList taskList) { } } + /** + * decipher the array and add the appropriate task to the list + * @param taskStringArray array of strings representing a task + * @param taskList current list of tasks + */ public void addToTasks(String[] taskStringArray, TaskList taskList) throws DukeException { String type = taskStringArray[0]; boolean isDone = taskStringArray[1].equals("1"); @@ -97,6 +109,10 @@ public void addToTasks(String[] taskStringArray, TaskList taskList) throws DukeE } } + /** + * save the list back into the save file + * @param taskList current list of tasks + */ public void writeFile(TaskList taskList) { try { FileWriter dukeWriter = new FileWriter(String.format("%s/%s", this.getDirname(), this.getFilename())); diff --git a/src/main/tasks/Deadline.java b/src/main/duke/tasks/Deadline.java similarity index 94% rename from src/main/tasks/Deadline.java rename to src/main/duke/tasks/Deadline.java index 5582257f76..daaba2299d 100644 --- a/src/main/tasks/Deadline.java +++ b/src/main/duke/tasks/Deadline.java @@ -1,6 +1,6 @@ -package main.tasks; +package main.duke.tasks; -import main.enums.TaskType; +import main.duke.enums.TaskType; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; diff --git a/src/main/tasks/Event.java b/src/main/duke/tasks/Event.java similarity index 94% rename from src/main/tasks/Event.java rename to src/main/duke/tasks/Event.java index 839ef28530..65cdb5a86b 100644 --- a/src/main/tasks/Event.java +++ b/src/main/duke/tasks/Event.java @@ -1,6 +1,6 @@ -package main.tasks; +package main.duke.tasks; -import main.enums.TaskType; +import main.duke.enums.TaskType; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; diff --git a/src/main/tasks/Task.java b/src/main/duke/tasks/Task.java similarity index 89% rename from src/main/tasks/Task.java rename to src/main/duke/tasks/Task.java index 652c1a54f2..8a44ad7375 100644 --- a/src/main/tasks/Task.java +++ b/src/main/duke/tasks/Task.java @@ -1,6 +1,6 @@ -package main.tasks; +package main.duke.tasks; -import main.enums.TaskType; +import main.duke.enums.TaskType; public abstract class Task { protected String description; @@ -33,6 +33,9 @@ public void setIsDone(boolean isDone) { this.isDone = isDone; } + /** + * format the task into a string to be stored in the save file + */ public String toStoreString() { return String.format("%s~%d~%s", this.getTaskType(), diff --git a/src/main/tasks/ToDo.java b/src/main/duke/tasks/ToDo.java similarity index 80% rename from src/main/tasks/ToDo.java rename to src/main/duke/tasks/ToDo.java index 66c011f7e5..ccb8e25cea 100644 --- a/src/main/tasks/ToDo.java +++ b/src/main/duke/tasks/ToDo.java @@ -1,6 +1,6 @@ -package main.tasks; +package main.duke.tasks; -import main.enums.TaskType; +import main.duke.enums.TaskType; public class ToDo extends Task{ public ToDo(String description) { diff --git a/src/test/duke/DukeTest.java b/src/test/duke/DukeTest.java index 9d87ed401c..78a45950a2 100644 --- a/src/test/duke/DukeTest.java +++ b/src/test/duke/DukeTest.java @@ -1,8 +1,8 @@ -import main.DukeException; -import main.commands.CBye; -import main.commands.CDeadline; -import main.commands.Command; -import main.io.Parser; +import main.duke.DukeException; +import main.duke.commands.CBye; +import main.duke.commands.CDeadline; +import main.duke.commands.Command; +import main.duke.io.Parser; import org.testng.annotations.Test; import static org.testng.AssertJUnit.assertEquals; From 3b36a9074af7281d8250b29a702cf4537cf776ec Mon Sep 17 00:00:00 2001 From: TeddYE Date: Wed, 2 Feb 2022 17:12:01 +0800 Subject: [PATCH 18/32] Reorganize the directories --- src/main/META-INF/MANIFEST.MF | 2 +- src/main/{ => duke}/Duke.java | 8 ++++---- src/main/{ => duke}/DukeException.java | 2 +- src/main/{ => duke}/TaskList.java | 4 ++-- src/main/{ => duke}/Ui.java | 4 ++-- src/main/{ => duke}/commands/CBye.java | 8 ++++---- src/main/{ => duke}/commands/CDeadline.java | 12 +++++------ src/main/{ => duke}/commands/CDelete.java | 12 +++++------ src/main/{ => duke}/commands/CEvent.java | 12 +++++------ src/main/{ => duke}/commands/CList.java | 8 ++++---- src/main/{ => duke}/commands/CMark.java | 12 +++++------ src/main/{ => duke}/commands/CTodo.java | 12 +++++------ src/main/{ => duke}/commands/CUnmark.java | 12 +++++------ src/main/{ => duke}/commands/Command.java | 10 +++++----- src/main/{ => duke}/enums/CommandType.java | 2 +- src/main/{ => duke}/enums/TaskType.java | 2 +- src/main/{ => duke}/io/Parser.java | 22 ++++++++++----------- src/main/{ => duke}/io/Storage.java | 12 +++++------ src/main/{ => duke}/tasks/Deadline.java | 4 ++-- src/main/{ => duke}/tasks/Event.java | 4 ++-- src/main/{ => duke}/tasks/Task.java | 4 ++-- src/main/{ => duke}/tasks/ToDo.java | 4 ++-- src/test/duke/DukeTest.java | 10 +++++----- 23 files changed, 91 insertions(+), 91 deletions(-) rename src/main/{ => duke}/Duke.java (90%) rename src/main/{ => duke}/DukeException.java (87%) rename src/main/{ => duke}/TaskList.java (92%) rename src/main/{ => duke}/Ui.java (96%) rename src/main/{ => duke}/commands/CBye.java (66%) rename src/main/{ => duke}/commands/CDeadline.java (79%) rename src/main/{ => duke}/commands/CDelete.java (80%) rename src/main/{ => duke}/commands/CEvent.java (79%) rename src/main/{ => duke}/commands/CList.java (65%) rename src/main/{ => duke}/commands/CMark.java (79%) rename src/main/{ => duke}/commands/CTodo.java (73%) rename src/main/{ => duke}/commands/CUnmark.java (79%) rename src/main/{ => duke}/commands/Command.java (77%) rename src/main/{ => duke}/enums/CommandType.java (82%) rename src/main/{ => duke}/enums/TaskType.java (90%) rename src/main/{ => duke}/io/Parser.java (93%) rename src/main/{ => duke}/io/Storage.java (95%) rename src/main/{ => duke}/tasks/Deadline.java (94%) rename src/main/{ => duke}/tasks/Event.java (94%) rename src/main/{ => duke}/tasks/Task.java (95%) rename src/main/{ => duke}/tasks/ToDo.java (80%) diff --git a/src/main/META-INF/MANIFEST.MF b/src/main/META-INF/MANIFEST.MF index ae812494c4..58202def9f 100644 --- a/src/main/META-INF/MANIFEST.MF +++ b/src/main/META-INF/MANIFEST.MF @@ -1,3 +1,3 @@ Manifest-Version: 1.0 -Main-Class: main.Duke +Main-Class: main.duke.Duke diff --git a/src/main/Duke.java b/src/main/duke/Duke.java similarity index 90% rename from src/main/Duke.java rename to src/main/duke/Duke.java index bbb2118e0d..e9aff81a7f 100644 --- a/src/main/Duke.java +++ b/src/main/duke/Duke.java @@ -1,8 +1,8 @@ -package main; +package main.duke; -import main.commands.Command; -import main.io.Parser; -import main.io.Storage; +import main.duke.commands.Command; +import main.duke.io.Parser; +import main.duke.io.Storage; import java.util.Scanner; diff --git a/src/main/DukeException.java b/src/main/duke/DukeException.java similarity index 87% rename from src/main/DukeException.java rename to src/main/duke/DukeException.java index 0fa0925e55..35e9a6ebc4 100644 --- a/src/main/DukeException.java +++ b/src/main/duke/DukeException.java @@ -1,4 +1,4 @@ -package main; +package main.duke; public class DukeException extends Exception{ public DukeException (String errorMessage){ diff --git a/src/main/TaskList.java b/src/main/duke/TaskList.java similarity index 92% rename from src/main/TaskList.java rename to src/main/duke/TaskList.java index 9190eee9b4..62e2b4aac4 100644 --- a/src/main/TaskList.java +++ b/src/main/duke/TaskList.java @@ -1,6 +1,6 @@ -package main; +package main.duke; -import main.tasks.Task; +import main.duke.tasks.Task; import java.util.ArrayList; diff --git a/src/main/Ui.java b/src/main/duke/Ui.java similarity index 96% rename from src/main/Ui.java rename to src/main/duke/Ui.java index 6a5d754169..5430d7b194 100644 --- a/src/main/Ui.java +++ b/src/main/duke/Ui.java @@ -1,6 +1,6 @@ -package main; +package main.duke; -import main.tasks.Task; +import main.duke.tasks.Task; public class Ui { private static final String GOODBYE_MESSAGE = "Bye. Hope to see you again soon!"; diff --git a/src/main/commands/CBye.java b/src/main/duke/commands/CBye.java similarity index 66% rename from src/main/commands/CBye.java rename to src/main/duke/commands/CBye.java index 17d133bff4..c90270154f 100644 --- a/src/main/commands/CBye.java +++ b/src/main/duke/commands/CBye.java @@ -1,8 +1,8 @@ -package main.commands; +package main.duke.commands; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; public class CBye extends Command{ diff --git a/src/main/commands/CDeadline.java b/src/main/duke/commands/CDeadline.java similarity index 79% rename from src/main/commands/CDeadline.java rename to src/main/duke/commands/CDeadline.java index b1bae7ef55..b0694a5a1a 100644 --- a/src/main/commands/CDeadline.java +++ b/src/main/duke/commands/CDeadline.java @@ -1,10 +1,10 @@ -package main.commands; +package main.duke.commands; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; -import main.tasks.Deadline; -import main.tasks.Task; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; +import main.duke.tasks.Deadline; +import main.duke.tasks.Task; public class CDeadline extends Command { protected String description; diff --git a/src/main/commands/CDelete.java b/src/main/duke/commands/CDelete.java similarity index 80% rename from src/main/commands/CDelete.java rename to src/main/duke/commands/CDelete.java index 717686b01d..61b82e41ea 100644 --- a/src/main/commands/CDelete.java +++ b/src/main/duke/commands/CDelete.java @@ -1,10 +1,10 @@ -package main.commands; +package main.duke.commands; -import main.DukeException; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; -import main.tasks.Task; +import main.duke.DukeException; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; +import main.duke.tasks.Task; public class CDelete extends Command{ protected int deleteIndex; diff --git a/src/main/commands/CEvent.java b/src/main/duke/commands/CEvent.java similarity index 79% rename from src/main/commands/CEvent.java rename to src/main/duke/commands/CEvent.java index 2f7ce7418b..a39c0ea315 100644 --- a/src/main/commands/CEvent.java +++ b/src/main/duke/commands/CEvent.java @@ -1,10 +1,10 @@ -package main.commands; +package main.duke.commands; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; -import main.tasks.Event; -import main.tasks.Task; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; +import main.duke.tasks.Event; +import main.duke.tasks.Task; public class CEvent extends Command { protected String description; diff --git a/src/main/commands/CList.java b/src/main/duke/commands/CList.java similarity index 65% rename from src/main/commands/CList.java rename to src/main/duke/commands/CList.java index d9490d29bc..914e4f1154 100644 --- a/src/main/commands/CList.java +++ b/src/main/duke/commands/CList.java @@ -1,8 +1,8 @@ -package main.commands; +package main.duke.commands; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; public class CList extends Command { public CList() { diff --git a/src/main/commands/CMark.java b/src/main/duke/commands/CMark.java similarity index 79% rename from src/main/commands/CMark.java rename to src/main/duke/commands/CMark.java index 920dbf5094..ed44f0cece 100644 --- a/src/main/commands/CMark.java +++ b/src/main/duke/commands/CMark.java @@ -1,10 +1,10 @@ -package main.commands; +package main.duke.commands; -import main.DukeException; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; -import main.tasks.Task; +import main.duke.DukeException; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; +import main.duke.tasks.Task; public class CMark extends Command{ protected int markIndex; diff --git a/src/main/commands/CTodo.java b/src/main/duke/commands/CTodo.java similarity index 73% rename from src/main/commands/CTodo.java rename to src/main/duke/commands/CTodo.java index fdbc5c4aaf..e424da5f6e 100644 --- a/src/main/commands/CTodo.java +++ b/src/main/duke/commands/CTodo.java @@ -1,10 +1,10 @@ -package main.commands; +package main.duke.commands; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; -import main.tasks.Task; -import main.tasks.ToDo; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; +import main.duke.tasks.Task; +import main.duke.tasks.ToDo; public class CTodo extends Command{ protected String description; diff --git a/src/main/commands/CUnmark.java b/src/main/duke/commands/CUnmark.java similarity index 79% rename from src/main/commands/CUnmark.java rename to src/main/duke/commands/CUnmark.java index 3d7745c709..cf8210a76f 100644 --- a/src/main/commands/CUnmark.java +++ b/src/main/duke/commands/CUnmark.java @@ -1,10 +1,10 @@ -package main.commands; +package main.duke.commands; -import main.DukeException; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; -import main.tasks.Task; +import main.duke.DukeException; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; +import main.duke.tasks.Task; public class CUnmark extends Command{ protected int unmarkIndex; diff --git a/src/main/commands/Command.java b/src/main/duke/commands/Command.java similarity index 77% rename from src/main/commands/Command.java rename to src/main/duke/commands/Command.java index c3fccd4c15..0be66aa607 100644 --- a/src/main/commands/Command.java +++ b/src/main/duke/commands/Command.java @@ -1,9 +1,9 @@ -package main.commands; +package main.duke.commands; -import main.DukeException; -import main.TaskList; -import main.Ui; -import main.enums.CommandType; +import main.duke.DukeException; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; public abstract class Command { protected CommandType commandType; diff --git a/src/main/enums/CommandType.java b/src/main/duke/enums/CommandType.java similarity index 82% rename from src/main/enums/CommandType.java rename to src/main/duke/enums/CommandType.java index 42fb5665d8..409eed63ff 100644 --- a/src/main/enums/CommandType.java +++ b/src/main/duke/enums/CommandType.java @@ -1,4 +1,4 @@ -package main.enums; +package main.duke.enums; public enum CommandType { BYE, diff --git a/src/main/enums/TaskType.java b/src/main/duke/enums/TaskType.java similarity index 90% rename from src/main/enums/TaskType.java rename to src/main/duke/enums/TaskType.java index 49064b8674..e9fb6f1def 100644 --- a/src/main/enums/TaskType.java +++ b/src/main/duke/enums/TaskType.java @@ -1,4 +1,4 @@ -package main.enums; +package main.duke.enums; public enum TaskType { TODO("T"), diff --git a/src/main/io/Parser.java b/src/main/duke/io/Parser.java similarity index 93% rename from src/main/io/Parser.java rename to src/main/duke/io/Parser.java index 6e82ce7691..927c0a6857 100644 --- a/src/main/io/Parser.java +++ b/src/main/duke/io/Parser.java @@ -1,15 +1,15 @@ -package main.io; +package main.duke.io; -import main.commands.Command; -import main.commands.CBye; -import main.commands.CMark; -import main.commands.CDelete; -import main.commands.CList; -import main.commands.CTodo; -import main.commands.CDeadline; -import main.commands.CEvent; -import main.commands.CUnmark; -import main.DukeException; +import main.duke.commands.Command; +import main.duke.commands.CBye; +import main.duke.commands.CMark; +import main.duke.commands.CDelete; +import main.duke.commands.CList; +import main.duke.commands.CTodo; +import main.duke.commands.CDeadline; +import main.duke.commands.CEvent; +import main.duke.commands.CUnmark; +import main.duke.DukeException; import java.util.Arrays; diff --git a/src/main/io/Storage.java b/src/main/duke/io/Storage.java similarity index 95% rename from src/main/io/Storage.java rename to src/main/duke/io/Storage.java index 909e3d08f0..6260ffbc3d 100644 --- a/src/main/io/Storage.java +++ b/src/main/duke/io/Storage.java @@ -1,10 +1,10 @@ -package main.io; +package main.duke.io; -import main.DukeException; -import main.TaskList; -import main.tasks.Deadline; -import main.tasks.Event; -import main.tasks.ToDo; +import main.duke.DukeException; +import main.duke.TaskList; +import main.duke.tasks.Deadline; +import main.duke.tasks.Event; +import main.duke.tasks.ToDo; import java.io.File; import java.io.FileWriter; diff --git a/src/main/tasks/Deadline.java b/src/main/duke/tasks/Deadline.java similarity index 94% rename from src/main/tasks/Deadline.java rename to src/main/duke/tasks/Deadline.java index 5582257f76..daaba2299d 100644 --- a/src/main/tasks/Deadline.java +++ b/src/main/duke/tasks/Deadline.java @@ -1,6 +1,6 @@ -package main.tasks; +package main.duke.tasks; -import main.enums.TaskType; +import main.duke.enums.TaskType; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; diff --git a/src/main/tasks/Event.java b/src/main/duke/tasks/Event.java similarity index 94% rename from src/main/tasks/Event.java rename to src/main/duke/tasks/Event.java index 839ef28530..65cdb5a86b 100644 --- a/src/main/tasks/Event.java +++ b/src/main/duke/tasks/Event.java @@ -1,6 +1,6 @@ -package main.tasks; +package main.duke.tasks; -import main.enums.TaskType; +import main.duke.enums.TaskType; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; diff --git a/src/main/tasks/Task.java b/src/main/duke/tasks/Task.java similarity index 95% rename from src/main/tasks/Task.java rename to src/main/duke/tasks/Task.java index 652c1a54f2..8bcfc1a921 100644 --- a/src/main/tasks/Task.java +++ b/src/main/duke/tasks/Task.java @@ -1,6 +1,6 @@ -package main.tasks; +package main.duke.tasks; -import main.enums.TaskType; +import main.duke.enums.TaskType; public abstract class Task { protected String description; diff --git a/src/main/tasks/ToDo.java b/src/main/duke/tasks/ToDo.java similarity index 80% rename from src/main/tasks/ToDo.java rename to src/main/duke/tasks/ToDo.java index 66c011f7e5..ccb8e25cea 100644 --- a/src/main/tasks/ToDo.java +++ b/src/main/duke/tasks/ToDo.java @@ -1,6 +1,6 @@ -package main.tasks; +package main.duke.tasks; -import main.enums.TaskType; +import main.duke.enums.TaskType; public class ToDo extends Task{ public ToDo(String description) { diff --git a/src/test/duke/DukeTest.java b/src/test/duke/DukeTest.java index 9d87ed401c..78a45950a2 100644 --- a/src/test/duke/DukeTest.java +++ b/src/test/duke/DukeTest.java @@ -1,8 +1,8 @@ -import main.DukeException; -import main.commands.CBye; -import main.commands.CDeadline; -import main.commands.Command; -import main.io.Parser; +import main.duke.DukeException; +import main.duke.commands.CBye; +import main.duke.commands.CDeadline; +import main.duke.commands.Command; +import main.duke.io.Parser; import org.testng.annotations.Test; import static org.testng.AssertJUnit.assertEquals; From 4c48792a4da544bf3c5b4beb1ae817c47416ceea Mon Sep 17 00:00:00 2001 From: TeddYE Date: Wed, 2 Feb 2022 18:04:15 +0800 Subject: [PATCH 19/32] Implement Level-9 functionalities Let's: * add CFind class to handle the search function * add appropriate response after the search is done --- src/main/duke/Ui.java | 18 ++++++++++++++++ src/main/duke/commands/CFind.java | 32 ++++++++++++++++++++++++++++ src/main/duke/enums/CommandType.java | 3 ++- src/main/duke/io/Parser.java | 15 ++++++------- 4 files changed, 58 insertions(+), 10 deletions(-) create mode 100644 src/main/duke/commands/CFind.java diff --git a/src/main/duke/Ui.java b/src/main/duke/Ui.java index a64e4e37e2..40c3b1a8bc 100644 --- a/src/main/duke/Ui.java +++ b/src/main/duke/Ui.java @@ -2,6 +2,8 @@ import main.duke.tasks.Task; +import java.util.ArrayList; + public class Ui { private static final String GOODBYE_MESSAGE = "Bye. Hope to see you again soon!"; @@ -61,4 +63,20 @@ public void respondDeleteTask(Task deleteTask, TaskList taskList) { System.out.printf("Noted. I've removed this task: \n" + " %s\n" + "%s\n", deleteTask, taskList.taskCountToString()); } + + /** + * prints out the task that was filtered by the user + * @param foundTasks the targeted task to add + */ + public void respondFindTask(ArrayList foundTasks) { + int n = foundTasks.size(); + if (n == 0) { + System.out.println("Cannot find any related tasks."); + } else { + System.out.println("Here are the matching tasks in your list:"); + for (int i = 0; i < n; i++) { + System.out.printf("%d.%s%n", i + 1, foundTasks.get(i)); + } + } + } } diff --git a/src/main/duke/commands/CFind.java b/src/main/duke/commands/CFind.java new file mode 100644 index 0000000000..41b75ea05d --- /dev/null +++ b/src/main/duke/commands/CFind.java @@ -0,0 +1,32 @@ +package main.duke.commands; + +import main.duke.DukeException; +import main.duke.TaskList; +import main.duke.Ui; +import main.duke.enums.CommandType; +import main.duke.tasks.Task; + +import java.util.ArrayList; + +public class CFind extends Command{ + protected String findString; + + public CFind(String findString) { + super(CommandType.FIND); + this.findString = findString; + } + + public String getFindString() { return this.findString; } + + @Override + public void runCommand(Ui ui, TaskList taskList) throws DukeException { + ArrayList foundTasks = new ArrayList<>(); + for (int i = 0; i < taskList.getTasksCount(); i++) { + Task curTask = taskList.getTask(i); + if (curTask.getDescription().contains(this.getFindString())) { + foundTasks.add(curTask); + } + } + ui.respondFindTask(foundTasks); + } +} diff --git a/src/main/duke/enums/CommandType.java b/src/main/duke/enums/CommandType.java index 409eed63ff..7fd03a2094 100644 --- a/src/main/duke/enums/CommandType.java +++ b/src/main/duke/enums/CommandType.java @@ -8,5 +8,6 @@ public enum CommandType { LIST, MARK, TODO, - UNMARK; + UNMARK, + FIND, } diff --git a/src/main/duke/io/Parser.java b/src/main/duke/io/Parser.java index 6b6904ec45..a1c5aa823f 100644 --- a/src/main/duke/io/Parser.java +++ b/src/main/duke/io/Parser.java @@ -1,14 +1,6 @@ package main.duke.io; -import main.duke.commands.Command; -import main.duke.commands.CBye; -import main.duke.commands.CMark; -import main.duke.commands.CDelete; -import main.duke.commands.CList; -import main.duke.commands.CTodo; -import main.duke.commands.CDeadline; -import main.duke.commands.CEvent; -import main.duke.commands.CUnmark; +import main.duke.commands.*; import main.duke.DukeException; import java.util.Arrays; @@ -116,6 +108,11 @@ public Command parse(String userInput) throws DukeException { } } break; + case "find": + String findString = String.join(" ", + Arrays.copyOfRange(inputArray, 1, inputArray.length)); + newCommand = new CFind(findString); + break; default: throw new DukeException("Sorry. I do not understand your input."); } From fb5007d168d1a45e4017247c1676b26122680b93 Mon Sep 17 00:00:00 2001 From: TeddYE Date: Sat, 5 Feb 2022 23:14:48 +0800 Subject: [PATCH 20/32] Use Gradle to automate some of the build tasks of the project --- build.gradle | 64 ++++++++ data/duke.txt | 7 +- gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 58910 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 185 +++++++++++++++++++++++ gradlew.bat | 104 +++++++++++++ 6 files changed, 365 insertions(+), 1 deletion(-) create mode 100644 build.gradle create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000000..7db9cc5277 --- /dev/null +++ b/build.gradle @@ -0,0 +1,64 @@ +plugins { + id 'java' + id 'application' + id 'checkstyle' + id "com.github.johnrengelman.shadow" version "6.0.0" +} + +group 'org.example' +version '1.0-SNAPSHOT' + +repositories { + mavenCentral() +} +sourceSets { + main { + java { + srcDirs = ['src'] + } + } + +} + +dependencies { + compile 'junit:junit:4.12' +} + +run { + enableAssertions = true +} + +test { + useJUnitPlatform() +} + +dependencies { + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.4.0' + testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.4.0' + implementation 'org.junit.jupiter:junit-jupiter-api:5.5.1' + String javaFxVersion = '11' + + implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'linux' + implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'linux' + implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'linux' + implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'linux' + compile group: 'org.testng', name: 'testng', version: '6.11' +} + +checkstyle { + toolVersion = '8.23' +} + +run{ + standardInput = System.in +} + +mainClassName ="main.duke.Duke" \ No newline at end of file diff --git a/data/duke.txt b/data/duke.txt index 56b54e18a4..b1316f374f 100644 --- a/data/duke.txt +++ b/data/duke.txt @@ -1 +1,6 @@ -D~0~1~1111-11-11 1111 +D~0~d1~1111-11-11 1111 +T~1~t1 +E~0~e1~1111-11-11 1212 +T~1~t2 +D~0~d2~1111-11-11 1111 +T~0~t3 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..62d4c053550b91381bbd28b1afc82d634bf73a8a GIT binary patch literal 58910 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 literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..7dcdbdde07 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue Feb 23 16:47:37 SGT 2021 +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew new file mode 100644 index 0000000000..fbd7c51583 --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000000..5093609d51 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,104 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega From 746eb08b3130767df937d3c1e030026718eb48e0 Mon Sep 17 00:00:00 2001 From: TeddYE Date: Wed, 9 Feb 2022 15:35:28 +0800 Subject: [PATCH 21/32] Implement Level-10 functionalities Add GUI supoport --- build.gradle | 1 + src/main/duke/Duke.java | 26 ++++------ src/main/duke/Ui.java | 37 +++++++------- src/main/duke/commands/CBye.java | 4 +- src/main/duke/commands/CDeadline.java | 4 +- src/main/duke/commands/CDelete.java | 4 +- src/main/duke/commands/CEvent.java | 4 +- src/main/duke/commands/CFind.java | 4 +- src/main/duke/commands/CList.java | 4 +- src/main/duke/commands/CMark.java | 4 +- src/main/duke/commands/CTodo.java | 4 +- src/main/duke/commands/CUnmark.java | 4 +- src/main/duke/commands/Command.java | 2 +- src/main/duke/gui/DialogBox.java | 61 ++++++++++++++++++++++++ src/main/duke/gui/Launcher.java | 9 ++++ src/main/duke/gui/Main.java | 33 +++++++++++++ src/main/duke/gui/MainWindow.java | 52 ++++++++++++++++++++ src/main/resources/images/duke.jpg | Bin 0 -> 12893 bytes src/main/resources/images/user.png | Bin 0 -> 32995 bytes src/main/resources/view/DialogBox.fxml | 16 +++++++ src/main/resources/view/MainWindow.fxml | 19 ++++++++ 21 files changed, 240 insertions(+), 52 deletions(-) create mode 100644 src/main/duke/gui/DialogBox.java create mode 100644 src/main/duke/gui/Launcher.java create mode 100644 src/main/duke/gui/Main.java create mode 100644 src/main/duke/gui/MainWindow.java create mode 100644 src/main/resources/images/duke.jpg create mode 100644 src/main/resources/images/user.png create mode 100644 src/main/resources/view/DialogBox.fxml create mode 100644 src/main/resources/view/MainWindow.fxml diff --git a/build.gradle b/build.gradle index 7db9cc5277..35d48b1059 100644 --- a/build.gradle +++ b/build.gradle @@ -11,6 +11,7 @@ version '1.0-SNAPSHOT' repositories { mavenCentral() } + sourceSets { main { java { diff --git a/src/main/duke/Duke.java b/src/main/duke/Duke.java index e9aff81a7f..91fd375b7c 100644 --- a/src/main/duke/Duke.java +++ b/src/main/duke/Duke.java @@ -19,24 +19,18 @@ public Duke(String dirname, String filename) { this.taskList = new TaskList(); this.ui = new Ui(); this.parser = new Parser(); - } - - public void run() throws DukeException{ - Scanner sc = new Scanner(System.in); - this.storage.readFile(this.taskList); - - System.out.println(WELCOME_MESSAGE); - - while (!Command.getIsExit()) { - Command newCommand = this.parser.parse(sc.nextLine()); - newCommand.runCommand(this.ui, this.taskList); - } - - storage.writeFile(this.taskList); } - public static void main(String[] args) throws DukeException { - new Duke("data", "duke.txt").run(); + public String getResponse(String input){ + try { + Command command = this.parser.parse(input); + String reply = command.runCommand(this.ui, this.taskList); + this.storage.writeFile(this.taskList); + return reply; + } + catch (DukeException e) { + return e.getMessage(); + } } } diff --git a/src/main/duke/Ui.java b/src/main/duke/Ui.java index 40c3b1a8bc..4d82a30d5c 100644 --- a/src/main/duke/Ui.java +++ b/src/main/duke/Ui.java @@ -7,22 +7,24 @@ public class Ui { private static final String GOODBYE_MESSAGE = "Bye. Hope to see you again soon!"; - public void respondBye() { - System.out.println(Ui.GOODBYE_MESSAGE); + public String respondBye() { + return Ui.GOODBYE_MESSAGE; } /** * prints out all the tasks in the current list * @param taskList the current list of tasks */ - public void respondList(TaskList taskList) { + public String respondList(TaskList taskList) { int n = taskList.getTasksCount(); if (n == 0) { - System.out.println("The list is currently empty."); + return "The list is currently empty."; } else { + StringBuilder response = new StringBuilder(); for (int i = 0; i < n; i++) { - System.out.printf("%d.%s%n", i + 1, taskList.getTask(i)); + response.append(String.format("%d.%s%n", i + 1, taskList.getTask(i))); } + return response.toString(); } } @@ -30,8 +32,8 @@ public void respondList(TaskList taskList) { * prints out the task that has been marked * @param markTask the targeted task to mark */ - public void respondMark(Task markTask) { - System.out.printf("Nice! I've marked this task as done: \n" + public String respondMark(Task markTask) { + return String.format("Nice! I've marked this task as done: \n" + " %s\n", markTask); } @@ -39,8 +41,8 @@ public void respondMark(Task markTask) { * prints out the task that has been unmarked * @param unmarkTask the targeted task to unmark */ - public void respondUnmark(Task unmarkTask) { - System.out.printf("Nice! I've marked this task as done: \n" + public String respondUnmark(Task unmarkTask) { + return String.format("Nice! I've marked this task as done: \n" + " %s\n", unmarkTask); } @@ -49,8 +51,8 @@ public void respondUnmark(Task unmarkTask) { * @param newTask the targeted task to add * @param taskList the current list of tasks */ - public void respondAddTask(Task newTask, TaskList taskList) { - System.out.printf("Got it. I've added this task:\n" + "%s\n" + "%s\n", + public String respondAddTask(Task newTask, TaskList taskList) { + return String.format("Got it. I've added this task:\n" + "%s\n" + "%s\n", newTask, taskList.taskCountToString()); } @@ -59,8 +61,8 @@ public void respondAddTask(Task newTask, TaskList taskList) { * @param deleteTask the targeted task to add * @param taskList the current list of tasks */ - public void respondDeleteTask(Task deleteTask, TaskList taskList) { - System.out.printf("Noted. I've removed this task: \n" + " %s\n" + public String respondDeleteTask(Task deleteTask, TaskList taskList) { + return String.format("Noted. I've removed this task: \n" + " %s\n" + "%s\n", deleteTask, taskList.taskCountToString()); } @@ -68,15 +70,16 @@ public void respondDeleteTask(Task deleteTask, TaskList taskList) { * prints out the task that was filtered by the user * @param foundTasks the targeted task to add */ - public void respondFindTask(ArrayList foundTasks) { + public String respondFindTask(ArrayList foundTasks) { int n = foundTasks.size(); if (n == 0) { - System.out.println("Cannot find any related tasks."); + return "Cannot find any related tasks."; } else { - System.out.println("Here are the matching tasks in your list:"); + StringBuilder response = new StringBuilder("Here are the matching tasks in your list:"); for (int i = 0; i < n; i++) { - System.out.printf("%d.%s%n", i + 1, foundTasks.get(i)); + response.append(String.format("%d.%s%n", i + 1, foundTasks.get(i))); } + return response.toString(); } } } diff --git a/src/main/duke/commands/CBye.java b/src/main/duke/commands/CBye.java index c90270154f..bcbb8e7a42 100644 --- a/src/main/duke/commands/CBye.java +++ b/src/main/duke/commands/CBye.java @@ -11,8 +11,8 @@ public CBye() { } @Override - public void runCommand(Ui ui, TaskList taskList) { + public String runCommand(Ui ui, TaskList taskList) { Command.exitDuke(); - ui.respondBye(); + return ui.respondBye(); } } diff --git a/src/main/duke/commands/CDeadline.java b/src/main/duke/commands/CDeadline.java index b0694a5a1a..7a647af20c 100644 --- a/src/main/duke/commands/CDeadline.java +++ b/src/main/duke/commands/CDeadline.java @@ -25,9 +25,9 @@ public String getDescription() { } @Override - public void runCommand(Ui ui, TaskList taskList) { + public String runCommand(Ui ui, TaskList taskList) { Task newDeadline = new Deadline(this.getDescription(), this.getDueDate()); taskList.addTask(newDeadline); - ui.respondAddTask(newDeadline, taskList); + return ui.respondAddTask(newDeadline, taskList); } } diff --git a/src/main/duke/commands/CDelete.java b/src/main/duke/commands/CDelete.java index 61b82e41ea..4ad3c30353 100644 --- a/src/main/duke/commands/CDelete.java +++ b/src/main/duke/commands/CDelete.java @@ -19,11 +19,11 @@ public int getDeleteIndex() { } @Override - public void runCommand(Ui ui, TaskList taskList) throws DukeException { + public String runCommand(Ui ui, TaskList taskList) throws DukeException { try { Task deleteTask = taskList.getTask(this.getDeleteIndex()); taskList.deleteTask(this.getDeleteIndex()); - ui.respondDeleteTask(deleteTask, taskList); + return ui.respondDeleteTask(deleteTask, taskList); } catch (IndexOutOfBoundsException e) { throw new DukeException("Please check that you have entered the correct index."); } diff --git a/src/main/duke/commands/CEvent.java b/src/main/duke/commands/CEvent.java index a39c0ea315..bd42e11f9e 100644 --- a/src/main/duke/commands/CEvent.java +++ b/src/main/duke/commands/CEvent.java @@ -26,9 +26,9 @@ public String getDescription() { @Override - public void runCommand(Ui ui, TaskList taskList) { + public String runCommand(Ui ui, TaskList taskList) { Task newEvent = new Event(this.getDescription(), this.getDateTime()); taskList.addTask(newEvent); - ui.respondAddTask(newEvent, taskList); + return ui.respondAddTask(newEvent, taskList); } } diff --git a/src/main/duke/commands/CFind.java b/src/main/duke/commands/CFind.java index 41b75ea05d..3fe8df86f4 100644 --- a/src/main/duke/commands/CFind.java +++ b/src/main/duke/commands/CFind.java @@ -19,7 +19,7 @@ public CFind(String findString) { public String getFindString() { return this.findString; } @Override - public void runCommand(Ui ui, TaskList taskList) throws DukeException { + public String runCommand(Ui ui, TaskList taskList) throws DukeException { ArrayList foundTasks = new ArrayList<>(); for (int i = 0; i < taskList.getTasksCount(); i++) { Task curTask = taskList.getTask(i); @@ -27,6 +27,6 @@ public void runCommand(Ui ui, TaskList taskList) throws DukeException { foundTasks.add(curTask); } } - ui.respondFindTask(foundTasks); + return ui.respondFindTask(foundTasks); } } diff --git a/src/main/duke/commands/CList.java b/src/main/duke/commands/CList.java index 914e4f1154..676ea94554 100644 --- a/src/main/duke/commands/CList.java +++ b/src/main/duke/commands/CList.java @@ -10,7 +10,7 @@ public CList() { } @Override - public void runCommand(Ui ui, TaskList taskList) { - ui.respondList(taskList); + public String runCommand(Ui ui, TaskList taskList) { + return ui.respondList(taskList); } } diff --git a/src/main/duke/commands/CMark.java b/src/main/duke/commands/CMark.java index ed44f0cece..3d386f8bc2 100644 --- a/src/main/duke/commands/CMark.java +++ b/src/main/duke/commands/CMark.java @@ -19,11 +19,11 @@ public int getMarkIndex() { } @Override - public void runCommand(Ui ui, TaskList taskList) throws DukeException { + public String runCommand(Ui ui, TaskList taskList) throws DukeException { try { Task markTask = taskList.getTask(this.getMarkIndex()); markTask.setIsDone(true); - ui.respondMark(markTask); + return ui.respondMark(markTask); } catch (IndexOutOfBoundsException e) { throw new DukeException("Please check that you have entered the correct index."); } diff --git a/src/main/duke/commands/CTodo.java b/src/main/duke/commands/CTodo.java index e424da5f6e..ad41a873d2 100644 --- a/src/main/duke/commands/CTodo.java +++ b/src/main/duke/commands/CTodo.java @@ -19,9 +19,9 @@ public String getDescription() { } @Override - public void runCommand(Ui ui, TaskList taskList) { + public String runCommand(Ui ui, TaskList taskList) { Task newToDo = new ToDo(this.getDescription()); taskList.addTask(newToDo); - ui.respondAddTask(newToDo, taskList); + return ui.respondAddTask(newToDo, taskList); } } diff --git a/src/main/duke/commands/CUnmark.java b/src/main/duke/commands/CUnmark.java index cf8210a76f..337b38b41b 100644 --- a/src/main/duke/commands/CUnmark.java +++ b/src/main/duke/commands/CUnmark.java @@ -19,11 +19,11 @@ public int getUnmarkIndex() { } @Override - public void runCommand(Ui ui, TaskList taskList) throws DukeException { + public String runCommand(Ui ui, TaskList taskList) throws DukeException { try { Task unmarkTask = taskList.getTask(this.getUnmarkIndex()); unmarkTask.setIsDone(false); - ui.respondUnmark(unmarkTask); + return ui.respondUnmark(unmarkTask); } catch (IndexOutOfBoundsException e) { throw new DukeException("Please check that you have entered the correct index."); } diff --git a/src/main/duke/commands/Command.java b/src/main/duke/commands/Command.java index 0be66aa607..34b8b87b16 100644 --- a/src/main/duke/commands/Command.java +++ b/src/main/duke/commands/Command.java @@ -20,5 +20,5 @@ public Command(CommandType commandType) { public CommandType getCommandType() { return this.commandType; } - public abstract void runCommand(Ui ui, TaskList taskList) throws DukeException; + public abstract String runCommand(Ui ui, TaskList taskList) throws DukeException; } diff --git a/src/main/duke/gui/DialogBox.java b/src/main/duke/gui/DialogBox.java new file mode 100644 index 0000000000..f4dddc2426 --- /dev/null +++ b/src/main/duke/gui/DialogBox.java @@ -0,0 +1,61 @@ +package main.duke.gui; + +import java.io.IOException; +import java.util.Collections; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; + +/** + * An example of a custom control using FXML. + * This control represents a dialog box consisting of an ImageView to represent the speaker's face and a label + * containing text from the speaker. + */ +public class DialogBox extends HBox { + @FXML + private Label dialog; + @FXML + private ImageView displayPicture; + + private DialogBox(String text, Image img) { + try { + FXMLLoader fxmlLoader = new FXMLLoader(MainWindow.class.getResource("/view/DialogBox.fxml")); + fxmlLoader.setController(this); + fxmlLoader.setRoot(this); + fxmlLoader.load(); + } catch (IOException e) { + e.printStackTrace(); + } + + dialog.setText(text); + displayPicture.setImage(img); + } + + /** + * Flips the dialog box such that the ImageView is on the left and text on the right. + */ + private void flip() { + ObservableList tmp = FXCollections.observableArrayList(this.getChildren()); + Collections.reverse(tmp); + getChildren().setAll(tmp); + setAlignment(Pos.TOP_LEFT); + } + + public static DialogBox getUserDialog(String text, Image img) { + return new DialogBox(text, img); + } + + public static DialogBox getDukeDialog(String text, Image img) { + var db = new DialogBox(text, img); + db.flip(); + return db; + } +} diff --git a/src/main/duke/gui/Launcher.java b/src/main/duke/gui/Launcher.java new file mode 100644 index 0000000000..0d59cc8c66 --- /dev/null +++ b/src/main/duke/gui/Launcher.java @@ -0,0 +1,9 @@ +package main.duke.gui; + +import javafx.application.Application; + +public class Launcher { + public static void main(String[] args) { + Application.launch(Main.class, args); + } +} diff --git a/src/main/duke/gui/Main.java b/src/main/duke/gui/Main.java new file mode 100644 index 0000000000..482171a09c --- /dev/null +++ b/src/main/duke/gui/Main.java @@ -0,0 +1,33 @@ +package main.duke.gui; + +import java.io.IOException; + +import javafx.application.Application; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.scene.layout.AnchorPane; +import javafx.stage.Stage; + +import main.duke.Duke; + +/** + * A GUI for Duke using FXML. + */ +public class Main extends Application { + + private Duke duke = new Duke("data", "duke.txt"); + + @Override + public void start(Stage stage) { + try { + FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("/view/MainWindow.fxml")); + AnchorPane ap = fxmlLoader.load(); + Scene scene = new Scene(ap); + stage.setScene(scene); + fxmlLoader.getController().setDuke(duke); + stage.show(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/duke/gui/MainWindow.java b/src/main/duke/gui/MainWindow.java new file mode 100644 index 0000000000..5c8c222b3d --- /dev/null +++ b/src/main/duke/gui/MainWindow.java @@ -0,0 +1,52 @@ +package main.duke.gui; + +import javafx.fxml.FXML; +import main.duke.Duke; + +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.TextField; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.VBox; +import javafx.scene.image.Image; + +public class MainWindow extends AnchorPane{ + + @FXML + private ScrollPane scrollPane; + @FXML + private VBox dialogContainer; + @FXML + private TextField userInput; + @FXML + + private Image userImage = new Image(this.getClass().getResourceAsStream("/images/user.png")); + private Image dukeImage = new Image(this.getClass().getResourceAsStream("/images/duke.jpg")); + + private Duke duke = new Duke("data", "duke.txt"); + + @FXML + public void initialize() { + scrollPane.vvalueProperty().bind(dialogContainer.heightProperty()); + } + + public void setDuke(Duke d) { + duke = d; + } + + /** + * Creates two dialog boxes, one echoing user input and the other containing Duke's reply and then appends them to + * the dialog container. Clears the user input after processing. + */ + @FXML + private void handleUserInput() { + String input = userInput.getText(); + String response = duke.getResponse(input); + dialogContainer.getChildren().addAll( + DialogBox.getUserDialog(input, userImage), + DialogBox.getDukeDialog(response, dukeImage) + ); + userInput.clear(); + } +} diff --git a/src/main/resources/images/duke.jpg b/src/main/resources/images/duke.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e0186fa50f4e6cdaaee07817ea2675db6bd6c8be GIT binary patch literal 12893 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 uY0RW` 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
qq;AY)Rm!_6RfE0P&hqrU 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/view/DialogBox.fxml b/src/main/resources/view/DialogBox.fxml new file mode 100644 index 0000000000..ede775d4f9 --- /dev/null +++ b/src/main/resources/view/DialogBox.fxml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml new file mode 100644 index 0000000000..f8c5457847 --- /dev/null +++ b/src/main/resources/view/MainWindow.fxml @@ -0,0 +1,19 @@ + + + + + + + + + + + +