From aa829aeb6367a975e5c969f221c6b6fceb6f1aee Mon Sep 17 00:00:00 2001 From: Shane Duggan <> Date: Tue, 24 Jan 2023 12:03:09 +0800 Subject: [PATCH 01/28] no message --- src/main/java/Duke.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 5d313334cc..32ddeb3401 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,3 +1,5 @@ +import javax.swing.event.SwingPropertyChangeSupport; + public class Duke { public static void main(String[] args) { String logo = " ____ _ \n" @@ -6,5 +8,6 @@ public static void main(String[] args) { + "| |_| | |_| | < __/\n" + "|____/ \\__,_|_|\\_\\___|\n"; System.out.println("Hello from\n" + logo); + System.out.println("Hi"); } } From 99c297e6a9a172af13c5ed5302602a4a8c0388b2 Mon Sep 17 00:00:00 2001 From: Shane Duggan <> Date: Tue, 24 Jan 2023 12:38:33 +0800 Subject: [PATCH 02/28] no message --- src/main/java/Duke.java | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 32ddeb3401..95d62842d8 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,13 +1,18 @@ -import javax.swing.event.SwingPropertyChangeSupport; +import java.util.Scanner; public class Duke { public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); - System.out.println("Hi"); + System.out.println("Hello I'm Duke\nWhat can I do for you?"); + Scanner scan = new Scanner(System.in); + + while (true) { + String textInput = scan.nextLine(); + if (textInput.equalsIgnoreCase("bye")) { + System.out.println("Bye. Hope to see you again soon!"); + scan.close(); + return; + } + System.out.println(textInput); + } } } From 38c6d7f71fdde740375a4af7a88dd3879026f896 Mon Sep 17 00:00:00 2001 From: Shane Duggan <> Date: Tue, 24 Jan 2023 16:22:44 +0800 Subject: [PATCH 03/28] no message --- src/main/java/Duke.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 95d62842d8..6f5dbc96d2 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -2,6 +2,8 @@ public class Duke { public static void main(String[] args) { + String[] storedList = new String[100]; + int index = 0; System.out.println("Hello I'm Duke\nWhat can I do for you?"); Scanner scan = new Scanner(System.in); @@ -12,7 +14,15 @@ public static void main(String[] args) { scan.close(); return; } - System.out.println(textInput); + if (textInput.equals("list")) { + for (int i = 0; i < index; i++) { + System.out.println(i + 1 + ". " + storedList[i]); + } + continue; + } + storedList[index] = textInput; + index++; + System.out.println("added: " + textInput); } } } From cda40e052a584765e81f882d2e460729e795ddaa Mon Sep 17 00:00:00 2001 From: Shane Duggan <> Date: Tue, 24 Jan 2023 17:08:47 +0800 Subject: [PATCH 04/28] no message --- src/main/java/Duke.java | 35 ++++++++++++++++++++++++++++------- src/main/java/Task.java | 26 ++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 7 deletions(-) create mode 100644 src/main/java/Task.java diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 6f5dbc96d2..43c6f0ff61 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -2,27 +2,48 @@ public class Duke { public static void main(String[] args) { - String[] storedList = new String[100]; - int index = 0; + Task[] taskList = new Task[100]; + int index = 1; System.out.println("Hello I'm Duke\nWhat can I do for you?"); Scanner scan = new Scanner(System.in); while (true) { String textInput = scan.nextLine(); + Task t = new Task(textInput); + if (textInput.equalsIgnoreCase("bye")) { System.out.println("Bye. Hope to see you again soon!"); scan.close(); return; } - if (textInput.equals("list")) { - for (int i = 0; i < index; i++) { - System.out.println(i + 1 + ". " + storedList[i]); + + if (textInput.equalsIgnoreCase("list")) { + System.out.println("Here are the tasks in your list:"); + for (int i = 1; i < index; i++) { + System.out.println(i + ". " + taskList[i-1].toString()); } continue; } - storedList[index] = textInput; + + if (textInput.substring(0, 4).equalsIgnoreCase("mark")) { + int i = Integer.parseInt(textInput.substring(5)); + Task currTask = taskList[i-1]; + currTask.markDone(); + System.out.println("Nice! I've marked this task as done\n" + currTask.toString()); + continue; + } + + if (textInput.substring(0, 6).equalsIgnoreCase("unmark")) { + int i = Integer.parseInt(textInput.substring(7)); + Task currTask = taskList[i-1]; + currTask.markUndone(); + System.out.println("OK, I've marked this task as not done yet:\n" + currTask.toString()); + continue; + } + + taskList[index-1] = t; index++; System.out.println("added: " + textInput); } } -} +} \ No newline at end of file diff --git a/src/main/java/Task.java b/src/main/java/Task.java new file mode 100644 index 0000000000..0df4a76389 --- /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 getStatusIcon() { + return (isDone ? "X" : " "); // mark done task with X + } + + public void markDone() { + this.isDone = true; + } + + public void markUndone() { + this.isDone = false; + } + + public String toString() { + String result = String.format("[%s] %s", this.getStatusIcon(), this.description); + return result; + } +} From 1b106fde96dbc27592945c21b2b5b0e56972ece1 Mon Sep 17 00:00:00 2001 From: Shane Duggan <> Date: Tue, 24 Jan 2023 17:13:02 +0800 Subject: [PATCH 05/28] no message --- src/main/java/Duke.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 43c6f0ff61..972894e9bb 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -25,7 +25,8 @@ public static void main(String[] args) { continue; } - if (textInput.substring(0, 4).equalsIgnoreCase("mark")) { + if (textInput.length() >= 6 && + textInput.substring(0, 4).equalsIgnoreCase("mark")) { int i = Integer.parseInt(textInput.substring(5)); Task currTask = taskList[i-1]; currTask.markDone(); @@ -33,7 +34,8 @@ public static void main(String[] args) { continue; } - if (textInput.substring(0, 6).equalsIgnoreCase("unmark")) { + if (textInput.length() >= 8 && + textInput.substring(0, 6).equalsIgnoreCase("unmark")) { int i = Integer.parseInt(textInput.substring(7)); Task currTask = taskList[i-1]; currTask.markUndone(); From 5c500317bd7c79e5b4c07d5a3b99d3184e120753 Mon Sep 17 00:00:00 2001 From: Shane Duggan <> Date: Wed, 25 Jan 2023 20:18:47 +0800 Subject: [PATCH 06/28] no message --- src/main/java/Duke.java | 42 ++++++++++++++++++++++++++++-------- src/main/java/Task.java | 48 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 10 deletions(-) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 972894e9bb..33795cb1de 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -3,13 +3,12 @@ public class Duke { public static void main(String[] args) { Task[] taskList = new Task[100]; - int index = 1; + int index = 0; System.out.println("Hello I'm Duke\nWhat can I do for you?"); Scanner scan = new Scanner(System.in); while (true) { String textInput = scan.nextLine(); - Task t = new Task(textInput); if (textInput.equalsIgnoreCase("bye")) { System.out.println("Bye. Hope to see you again soon!"); @@ -19,8 +18,8 @@ public static void main(String[] args) { if (textInput.equalsIgnoreCase("list")) { System.out.println("Here are the tasks in your list:"); - for (int i = 1; i < index; i++) { - System.out.println(i + ". " + taskList[i-1].toString()); + for (int i = 0; i < index; i++) { + System.out.println(i + 1 + ". " + taskList[i].toString()); } continue; } @@ -28,7 +27,7 @@ public static void main(String[] args) { if (textInput.length() >= 6 && textInput.substring(0, 4).equalsIgnoreCase("mark")) { int i = Integer.parseInt(textInput.substring(5)); - Task currTask = taskList[i-1]; + Task currTask = taskList[i - 1]; currTask.markDone(); System.out.println("Nice! I've marked this task as done\n" + currTask.toString()); continue; @@ -37,15 +36,40 @@ public static void main(String[] args) { if (textInput.length() >= 8 && textInput.substring(0, 6).equalsIgnoreCase("unmark")) { int i = Integer.parseInt(textInput.substring(7)); - Task currTask = taskList[i-1]; + Task currTask = taskList[i - 1]; currTask.markUndone(); System.out.println("OK, I've marked this task as not done yet:\n" + currTask.toString()); continue; } - taskList[index-1] = t; - index++; - System.out.println("added: " + textInput); + if (textInput.length() >= 6 && + textInput.substring(0, 4).equalsIgnoreCase("todo")) { + Task t = new Task.Todo(textInput.substring(5)); + taskList[index] = t; + index++; + String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), index); + System.out.println(output); + } + + if (textInput.length() >= 10 && + textInput.substring(0, 8).equalsIgnoreCase("deadline")) { + String[] parts = textInput.split("/"); + Task t = new Task.Deadline(parts[0].substring(9), parts[1].substring(3)); + taskList[index] = t; + index++; + String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), index); + System.out.println(output); + } + + if (textInput.length() >= 7 && + textInput.substring(0, 5).equalsIgnoreCase("event")) { + String[] parts = textInput.split("/"); + Task t = new Task.Event(parts[0].substring(6), parts[1].substring(5), parts[2].substring(3)); + taskList[index] = t; + index++; + String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), index); + System.out.println(output); + } } } } \ No newline at end of file diff --git a/src/main/java/Task.java b/src/main/java/Task.java index 0df4a76389..ebcd1f6d9e 100644 --- a/src/main/java/Task.java +++ b/src/main/java/Task.java @@ -7,6 +7,51 @@ public Task(String description) { this.isDone = false; } + public static class Todo extends Task { + + public Todo(String description) { + super(description); + } + + @Override + public String toString() { + return "[T]" + super.toString(); + } + } + + public static class Deadline extends Task { + + protected String by; + + public Deadline(String description, String by) { + super(description); + this.by = by; + } + + @Override + public String toString() { + return "[D]" + super.toString() + " (by: " + by + ")"; + } + } + + public static class Event extends Task { + + protected String from; + protected String to; + + public Event(String description, String from, String to) { + super(description); + this.from = from; + this.to = to; + + } + + @Override + public String toString() { + return "[E]" + super.toString() + " (from: " + from + "to: " + to + ")"; + } + } + public String getStatusIcon() { return (isDone ? "X" : " "); // mark done task with X } @@ -19,8 +64,9 @@ public void markUndone() { this.isDone = false; } + @Override public String toString() { String result = String.format("[%s] %s", this.getStatusIcon(), this.description); return result; } -} +} \ No newline at end of file From 4cbf56c5ef5e90fb5f089deb96a62ab215c7a7b7 Mon Sep 17 00:00:00 2001 From: Shane Duggan <> Date: Thu, 26 Jan 2023 15:55:08 +0800 Subject: [PATCH 07/28] no message --- src/main/java/Duke.java | 26 ++++++++++++++++++++------ src/main/java/DukeException.java | 5 +++++ 2 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 src/main/java/DukeException.java diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 33795cb1de..78e4db499d 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -42,13 +42,23 @@ public static void main(String[] args) { continue; } - if (textInput.length() >= 6 && + if (textInput.length() >= 4 && textInput.substring(0, 4).equalsIgnoreCase("todo")) { - Task t = new Task.Todo(textInput.substring(5)); - taskList[index] = t; - index++; - String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), index); - System.out.println(output); + try { + String[] parts = textInput.split(" ", 2); + if (parts.length == 1 || parts[1] == "") { + throw new DukeException("☹ OOPS!!! The description of a todo cannot be empty."); + } + Task t = new Task.Todo(textInput.substring(5)); + taskList[index] = t; + index++; + String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), index); + System.out.println(output); + continue; + } catch (DukeException e) { + System.out.println(e); + continue; + } } if (textInput.length() >= 10 && @@ -59,6 +69,7 @@ public static void main(String[] args) { index++; String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), index); System.out.println(output); + continue; } if (textInput.length() >= 7 && @@ -69,7 +80,10 @@ public static void main(String[] args) { index++; String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), index); System.out.println(output); + continue; } + + System.out.println("☹ OOPS!!! I'm sorry, but I don't know what that means :-("); } } } \ No newline at end of file diff --git a/src/main/java/DukeException.java b/src/main/java/DukeException.java new file mode 100644 index 0000000000..4ecbe623d8 --- /dev/null +++ b/src/main/java/DukeException.java @@ -0,0 +1,5 @@ +public class DukeException extends Exception{ + public DukeException(String e) { + super(e); + } +} From f28eaf23b503fcc491415721828295a17f83647f Mon Sep 17 00:00:00 2001 From: Shane Duggan <> Date: Fri, 27 Jan 2023 13:07:20 +0800 Subject: [PATCH 08/28] Add "delete" feature to remove a task from the list --- src/main/java/Duke.java | 47 +++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 78e4db499d..94804b9e8e 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,9 +1,9 @@ +import java.util.ArrayList; import java.util.Scanner; public class Duke { public static void main(String[] args) { - Task[] taskList = new Task[100]; - int index = 0; + ArrayList taskList = new ArrayList(); System.out.println("Hello I'm Duke\nWhat can I do for you?"); Scanner scan = new Scanner(System.in); @@ -18,41 +18,50 @@ public static void main(String[] args) { if (textInput.equalsIgnoreCase("list")) { System.out.println("Here are the tasks in your list:"); - for (int i = 0; i < index; i++) { - System.out.println(i + 1 + ". " + taskList[i].toString()); + for (int i = 0; i < taskList.size(); i++) { + System.out.println(i + 1 + ". " + taskList.get(i).toString()); } continue; } + if (textInput.length() >= 8 && + textInput.substring(0, 6).equalsIgnoreCase("delete")) { + int i = Integer.parseInt(textInput.substring(7)); + Task t = taskList.get(i - 1); + taskList.remove(i - 1); + String output = String.format("Got it. I've removed this task:\n%s\nNow you have %d tasks in the list", t.toString(), taskList.size()); + System.out.println(output); + continue; + } + if (textInput.length() >= 6 && - textInput.substring(0, 4).equalsIgnoreCase("mark")) { + textInput.substring(0, 4).equalsIgnoreCase("mark")) { int i = Integer.parseInt(textInput.substring(5)); - Task currTask = taskList[i - 1]; + Task currTask = taskList.get(i - 1); currTask.markDone(); System.out.println("Nice! I've marked this task as done\n" + currTask.toString()); continue; } if (textInput.length() >= 8 && - textInput.substring(0, 6).equalsIgnoreCase("unmark")) { + textInput.substring(0, 6).equalsIgnoreCase("unmark")) { int i = Integer.parseInt(textInput.substring(7)); - Task currTask = taskList[i - 1]; + Task currTask = taskList.get(i - 1); currTask.markUndone(); System.out.println("OK, I've marked this task as not done yet:\n" + currTask.toString()); continue; } if (textInput.length() >= 4 && - textInput.substring(0, 4).equalsIgnoreCase("todo")) { + textInput.substring(0, 4).equalsIgnoreCase("todo")) { try { String[] parts = textInput.split(" ", 2); if (parts.length == 1 || parts[1] == "") { throw new DukeException("☹ OOPS!!! The description of a todo cannot be empty."); } Task t = new Task.Todo(textInput.substring(5)); - taskList[index] = t; - index++; - String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), index); + taskList.add(t); + String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), taskList.size()); System.out.println(output); continue; } catch (DukeException e) { @@ -62,23 +71,21 @@ public static void main(String[] args) { } if (textInput.length() >= 10 && - textInput.substring(0, 8).equalsIgnoreCase("deadline")) { + textInput.substring(0, 8).equalsIgnoreCase("deadline")) { String[] parts = textInput.split("/"); Task t = new Task.Deadline(parts[0].substring(9), parts[1].substring(3)); - taskList[index] = t; - index++; - String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), index); + taskList.add(t); + String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), taskList.size()); System.out.println(output); continue; } if (textInput.length() >= 7 && - textInput.substring(0, 5).equalsIgnoreCase("event")) { + textInput.substring(0, 5).equalsIgnoreCase("event")) { String[] parts = textInput.split("/"); Task t = new Task.Event(parts[0].substring(6), parts[1].substring(5), parts[2].substring(3)); - taskList[index] = t; - index++; - String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), index); + taskList.add(t); + String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), taskList.size()); System.out.println(output); continue; } From 4e33f21330ac910028c92e47d3a5bb5042d72e4c Mon Sep 17 00:00:00 2001 From: Shane Duggan <> Date: Fri, 27 Jan 2023 13:14:23 +0800 Subject: [PATCH 09/28] Add A-TextUiTesting to Duke environment --- text-ui-test/EXPECTED.TXT | 10 +++------- text-ui-test/input.txt | 1 + text-ui-test/runtest.sh | 4 ++-- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 657e74f6e7..47ec9d13eb 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,7 +1,3 @@ -Hello from - ____ _ -| _ \ _ _| | _____ -| | | | | | | |/ / _ \ -| |_| | |_| | < __/ -|____/ \__,_|_|\_\___| - +Hello I'm Duke +What can I do for you? +☹ OOPS!!! I'm sorry, but I don't know what that means :-( \ No newline at end of file diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index e69de29bb2..5ab2f8a432 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -0,0 +1 @@ +Hello \ No newline at end of file diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh index c9ec870033..30a4d732db 100644 --- a/text-ui-test/runtest.sh +++ b/text-ui-test/runtest.sh @@ -13,14 +13,14 @@ then fi # compile the code into the bin folder, terminates if error occurred -if ! javac -cp ../src/main/java -Xlint:none -d ../bin ../src/main/java/*.java +if ! javac -cp /Users/shane/Documents/NUS Y2S2/CS2103/ip/src/main/src/main/java -Xlint:none -d /Users/shane/Documents/NUS Y2S2/CS2103/ip/src/main/bin /Users/shane/Documents/NUS Y2S2/CS2103/ip/src/main/java/*.java then echo "********** BUILD FAILURE **********" exit 1 fi # run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT -java -classpath ../bin Duke < input.txt > ACTUAL.TXT +java -classpath /Users/shane/Documents/NUS Y2S2/CS2103/ip/src/main/bin Duke < input.txt > ACTUAL.TXT # convert to UNIX format cp EXPECTED.TXT EXPECTED-UNIX.TXT From a31cf0c3abb7bfc5fe05d6e146471c6243f9fa86 Mon Sep 17 00:00:00 2001 From: Shane Duggan <> Date: Fri, 10 Feb 2023 01:46:16 +0800 Subject: [PATCH 10/28] Changes until MoreOOP --- data/duke.txt | 3 + src/main/java/Duke.java | 116 ++++++++++++++++-------------------- src/main/java/Parser.java | 43 +++++++++++++ src/main/java/Storage.java | 62 +++++++++++++++++++ src/main/java/Task.java | 34 +++++++++++ src/main/java/TaskList.java | 76 +++++++++++++++++++++++ src/main/java/Ui.java | 38 ++++++++++++ 7 files changed, 306 insertions(+), 66 deletions(-) create mode 100644 data/duke.txt create mode 100644 src/main/java/Parser.java create mode 100644 src/main/java/Storage.java create mode 100644 src/main/java/TaskList.java create mode 100644 src/main/java/Ui.java diff --git a/data/duke.txt b/data/duke.txt new file mode 100644 index 0000000000..2b55d7135e --- /dev/null +++ b/data/duke.txt @@ -0,0 +1,3 @@ +T|1|read book +D|0|go to perth|today +E|1|play touch|today |tmr diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 94804b9e8e..7cf1202088 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,96 +1,80 @@ -import java.util.ArrayList; -import java.util.Scanner; - public class Duke { - public static void main(String[] args) { - ArrayList taskList = new ArrayList(); - System.out.println("Hello I'm Duke\nWhat can I do for you?"); - Scanner scan = new Scanner(System.in); + + private Ui ui; + private Storage storage; + private TaskList tasks; + private Parser parser; + + public Duke(String filePath) { + this.ui = new Ui(); + this.storage = new Storage(filePath); + this.tasks = new TaskList(storage.load()); + } + + public void run() { + + this.ui.welcomeUser(); while (true) { - String textInput = scan.nextLine(); + String textInput = this.ui.readInput(); + String response = ""; + this.parser = new Parser(); + this.parser.parse(textInput); - if (textInput.equalsIgnoreCase("bye")) { - System.out.println("Bye. Hope to see you again soon!"); - scan.close(); + if (this.parser.action == "bye") { + this.ui.goodbyeUser(); return; } - if (textInput.equalsIgnoreCase("list")) { - System.out.println("Here are the tasks in your list:"); - for (int i = 0; i < taskList.size(); i++) { - System.out.println(i + 1 + ". " + taskList.get(i).toString()); - } + else if (this.parser.action == "list") { + this.ui.listTasks(tasks); continue; } - if (textInput.length() >= 8 && - textInput.substring(0, 6).equalsIgnoreCase("delete")) { - int i = Integer.parseInt(textInput.substring(7)); - Task t = taskList.get(i - 1); - taskList.remove(i - 1); - String output = String.format("Got it. I've removed this task:\n%s\nNow you have %d tasks in the list", t.toString(), taskList.size()); - System.out.println(output); - continue; + else if (this.parser.action == "delete") { + response = this.tasks.delete(textInput); + this.storage.writeTxt(tasks); } - if (textInput.length() >= 6 && - textInput.substring(0, 4).equalsIgnoreCase("mark")) { - int i = Integer.parseInt(textInput.substring(5)); - Task currTask = taskList.get(i - 1); - currTask.markDone(); - System.out.println("Nice! I've marked this task as done\n" + currTask.toString()); - continue; + else if (this.parser.action == "mark") { + response = this.tasks.mark(textInput); + this.storage.writeTxt(tasks); } - if (textInput.length() >= 8 && - textInput.substring(0, 6).equalsIgnoreCase("unmark")) { - int i = Integer.parseInt(textInput.substring(7)); - Task currTask = taskList.get(i - 1); - currTask.markUndone(); - System.out.println("OK, I've marked this task as not done yet:\n" + currTask.toString()); - continue; + else if (this.parser.action == "unmark") { + response = this.tasks.unmark(textInput); + this.storage.writeTxt(tasks); } - if (textInput.length() >= 4 && - textInput.substring(0, 4).equalsIgnoreCase("todo")) { + else if (this.parser.action == "todo") { try { - String[] parts = textInput.split(" ", 2); - if (parts.length == 1 || parts[1] == "") { - throw new DukeException("☹ OOPS!!! The description of a todo cannot be empty."); - } - Task t = new Task.Todo(textInput.substring(5)); - taskList.add(t); - String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), taskList.size()); - System.out.println(output); - continue; + response = this.tasks.todo(textInput); + this.storage.writeTxt(tasks); } catch (DukeException e) { System.out.println(e); continue; } } - if (textInput.length() >= 10 && - textInput.substring(0, 8).equalsIgnoreCase("deadline")) { - String[] parts = textInput.split("/"); - Task t = new Task.Deadline(parts[0].substring(9), parts[1].substring(3)); - taskList.add(t); - String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), taskList.size()); - System.out.println(output); - continue; + else if (this.parser.action == "deadline") { + response = this.tasks.deadline(textInput); + this.storage.writeTxt(tasks); } - if (textInput.length() >= 7 && - textInput.substring(0, 5).equalsIgnoreCase("event")) { - String[] parts = textInput.split("/"); - Task t = new Task.Event(parts[0].substring(6), parts[1].substring(5), parts[2].substring(3)); - taskList.add(t); - String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), taskList.size()); - System.out.println(output); - continue; + else if (this.parser.action == "event") { + response = this.tasks.event(textInput); + this.storage.writeTxt(tasks); } - System.out.println("☹ OOPS!!! I'm sorry, but I don't know what that means :-("); + else { + response = "☹ OOPS!!! I'm sorry, but I don't know what that means :-("; + } + + this.ui.printResponse(response); } } + + public static void main(String[] args) { + new Duke("../../../data/duke.txt").run(); + } } \ No newline at end of file diff --git a/src/main/java/Parser.java b/src/main/java/Parser.java new file mode 100644 index 0000000000..89ccb2ca05 --- /dev/null +++ b/src/main/java/Parser.java @@ -0,0 +1,43 @@ +public class Parser { + String action; + + public void parse(String textInput) { + if (textInput.equalsIgnoreCase("bye")) { + this.action = "bye"; + } + + else if (textInput.equalsIgnoreCase("list")) { + this.action = "list"; + } + + else if (textInput.length() >= 8 && + textInput.substring(0, 6).equalsIgnoreCase("delete")) { + this.action = "delete"; + } + + else if (textInput.length() >= 6 && + textInput.substring(0, 4).equalsIgnoreCase("mark")) { + this.action = "mark"; + } + + else if (textInput.length() >= 8 && + textInput.substring(0, 6).equalsIgnoreCase("unmark")) { + this.action = "unmark"; + } + + else if (textInput.length() >= 4 && + textInput.substring(0, 4).equalsIgnoreCase("todo")) { + this.action = "todo"; + } + + else if (textInput.length() >= 10 && + textInput.substring(0, 8).equalsIgnoreCase("deadline")) { + this.action = "deadline"; + } + + else if (textInput.length() >= 7 && + textInput.substring(0, 5).equalsIgnoreCase("event")) { + this.action = "event"; + } + } +} diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java new file mode 100644 index 0000000000..da57257d84 --- /dev/null +++ b/src/main/java/Storage.java @@ -0,0 +1,62 @@ +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; + +public class Storage { + private String filePath; + + public Storage(String filePath) { + this.filePath = filePath; + } + + public ArrayList load() { + ArrayList taskList = new ArrayList<>(); + try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) { + String line; + while ((line = reader.readLine()) != null) { + String[] parts = line.split("\\|"); + if (parts[0].equalsIgnoreCase("T")) { + Task t = new Task.Todo(parts[2]); + taskList.add(t); + if (parts[1].equalsIgnoreCase("1")) { + t.markDone(); + } + } else if (parts[0].equalsIgnoreCase("D")) { + Task t = new Task.Deadline(parts[2], parts[3]); + taskList.add(t); + if (parts[1].equalsIgnoreCase("1")) { + t.markDone(); + } + } else { + Task t = new Task.Event(parts[2], parts[3] + " ", parts[4]); + taskList.add(t); + if (parts[1].equalsIgnoreCase("1")) { + t.markDone(); + } + } + } + return taskList; + } catch (IOException e) { + System.out.println("An error occurred while reading the file: " + e.getMessage()); + return new ArrayList<>(); + } + } + + public void writeTxt(TaskList list) { + ArrayList taskList = list.get(); + try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) { + int length = taskList.size(); + for (int i = 0; i < length; i++) { + String item = taskList.get(i).toData(); + writer.write(item); + writer.newLine(); + } + } catch (IOException e) { + System.out.println("An error occurred while writing to the file: " + e.getMessage()); + } +} + +} diff --git a/src/main/java/Task.java b/src/main/java/Task.java index ebcd1f6d9e..4f0d42629e 100644 --- a/src/main/java/Task.java +++ b/src/main/java/Task.java @@ -7,12 +7,26 @@ public Task(String description) { this.isDone = false; } + public String toData() { + return ""; + } + public static class Todo extends Task { public Todo(String description) { super(description); } + @Override + public String toData() { + int isDoneData = 0; + if (this.isDone) { + isDoneData = 1; + } + String result = String.format("T|%d|%s", isDoneData, this.description); + return result; + } + @Override public String toString() { return "[T]" + super.toString(); @@ -28,6 +42,16 @@ public Deadline(String description, String by) { this.by = by; } + @Override + public String toData() { + int isDoneData = 0; + if (this.isDone) { + isDoneData = 1; + } + String result = String.format("D|%d|%s|%s", isDoneData, this.description, this.by); + return result; + } + @Override public String toString() { return "[D]" + super.toString() + " (by: " + by + ")"; @@ -46,6 +70,16 @@ public Event(String description, String from, String to) { } + @Override + public String toData() { + int isDoneData = 0; + if (this.isDone) { + isDoneData = 1; + } + String result = String.format("E|%d|%s|%s|%s", isDoneData, this.description, this.from, this.to); + return result; + } + @Override public String toString() { return "[E]" + super.toString() + " (from: " + from + "to: " + to + ")"; diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java new file mode 100644 index 0000000000..1023a6469f --- /dev/null +++ b/src/main/java/TaskList.java @@ -0,0 +1,76 @@ +import java.util.ArrayList; + +public class TaskList { + private ArrayList taskList; + + public TaskList(ArrayList taskList) { + this.taskList = taskList; + } + + public ArrayList get() { + return this.taskList; + } + + public String delete(String textInput) { + int i = Integer.parseInt(textInput.substring(7)); + Task t = taskList.get(i - 1); + taskList.remove(i - 1); + String removedText = String.format("Got it. I've removed this task: %s\n", t.toString()); + String listSize = String.format("Now you have %d tasks in the list", taskList.size()); + return removedText + listSize; + } + + public String mark(String textInput) { + int i = Integer.parseInt(textInput.substring(5)); + Task currTask = taskList.get(i - 1); + currTask.markDone(); + String output = "Nice! I've marked this task as done\n" + currTask.toString(); + return output; + } + + public String unmark(String textInput) { + int i = Integer.parseInt(textInput.substring(7)); + Task currTask = taskList.get(i - 1); + currTask.markUndone(); + String output = "OK, I've marked this task as not done yet:\n" + currTask.toString(); + return output; + } + + public String todo(String textInput) throws DukeException { + String[] parts = textInput.split(" ", 2); + if (parts.length == 1 || parts[1] == "") { + throw new DukeException("☹ OOPS!!! The description of a todo cannot be empty."); + } + Task t = new Task.Todo(textInput.substring(5)); + taskList.add(t); + String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), taskList.size()); + return output; + } + + public String deadline(String textInput) { + String[] parts = textInput.split("/"); + Task t = new Task.Deadline(parts[0].substring(9), parts[1].substring(3)); + taskList.add(t); + String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), taskList.size()); + return output; + } + + public String event(String textInput) { + String[] parts = textInput.split("/"); + Task t = new Task.Event(parts[0].substring(6), parts[1].substring(5), parts[2].substring(3)); + taskList.add(t); + String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), taskList.size()); + return output; + } + + @Override + public String toString() { + String result = ""; + for (int i = 0; i < taskList.size(); i++) { + String description = taskList.get(i).toString(); + String output = String.format("%d. %s", i + 1, description + "\n"); + result += output; + } + return result; + } +} diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java new file mode 100644 index 0000000000..cc59faeeec --- /dev/null +++ b/src/main/java/Ui.java @@ -0,0 +1,38 @@ +import java.util.Scanner; + +public class Ui { + private String welcomeMessage = "Hey Buddy, I'm Duke\nWhat can I do for you?"; + private String goodbyeMessage = "Goodbye friend. Hope to see you again soon!"; + private Scanner scanner; + + public Ui() { + this.scanner = new Scanner(System.in); + } + + public void welcomeUser() { + System.out.println(welcomeMessage); + } + + public String readInput() { + System.out.println("=======ME======="); + String textInput = this.scanner.nextLine(); + return textInput; + } + + public void goodbyeUser() { + System.out.println("======DUKE======"); + System.out.println(goodbyeMessage); + this.scanner.close(); + System.out.println("================"); + } + + public void listTasks(TaskList taskList) { + System.out.println("======DUKE======"); + System.out.println(taskList.toString()); + } + + public void printResponse(String response) { + System.out.println("======DUKE======"); + System.out.println(response); + } +} \ No newline at end of file From 3d845a9184ee8b01cc107ae49cf7c5e88bb20f95 Mon Sep 17 00:00:00 2001 From: Shane Duggan <> Date: Wed, 15 Feb 2023 10:49:56 +0800 Subject: [PATCH 11/28] no message --- data/duke.txt | 5 ++++- src/main/java/Duke.java | 3 ++- src/main/java/Storage.java | 9 ++------- src/main/java/TaskList.java | 23 +++++++++++++++++++---- src/main/java/Ui.java | 8 ++++---- 5 files changed, 31 insertions(+), 17 deletions(-) diff --git a/data/duke.txt b/data/duke.txt index 2b55d7135e..eb6d63bb40 100644 --- a/data/duke.txt +++ b/data/duke.txt @@ -1,3 +1,6 @@ T|1|read book D|0|go to perth|today -E|1|play touch|today |tmr +E|1|play touch|today |tmr +T|0|fly back +D|1|task 3|tmr +E|0|ok|yes|yes \ No newline at end of file diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 7cf1202088..18b71cb44d 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -51,7 +51,8 @@ else if (this.parser.action == "todo") { response = this.tasks.todo(textInput); this.storage.writeTxt(tasks); } catch (DukeException e) { - System.out.println(e); + response = e.toString(); + this.ui.printResponse(response); continue; } } diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java index da57257d84..1dd7fbce1e 100644 --- a/src/main/java/Storage.java +++ b/src/main/java/Storage.java @@ -46,14 +46,9 @@ public ArrayList load() { } public void writeTxt(TaskList list) { - ArrayList taskList = list.get(); try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) { - int length = taskList.size(); - for (int i = 0; i < length; i++) { - String item = taskList.get(i).toData(); - writer.write(item); - writer.newLine(); - } + String toWrite = list.toWrite(); + writer.write(toWrite); } catch (IOException e) { System.out.println("An error occurred while writing to the file: " + e.getMessage()); } diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index 1023a6469f..1e6da28a35 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -7,10 +7,6 @@ public TaskList(ArrayList taskList) { this.taskList = taskList; } - public ArrayList get() { - return this.taskList; - } - public String delete(String textInput) { int i = Integer.parseInt(textInput.substring(7)); Task t = taskList.get(i - 1); @@ -63,11 +59,30 @@ public String event(String textInput) { return output; } + public String toWrite() { + int length = this.taskList.size(); + String result = ""; + for (int i = 0; i < length; i++) { + String item = taskList.get(i).toData(); + if (i == length - 1) { + result += item; + continue; + } + result += item + "\n"; + } + return result; + } + @Override public String toString() { String result = ""; for (int i = 0; i < taskList.size(); i++) { String description = taskList.get(i).toString(); + if (i == taskList.size() - 1) { + String output = String.format("%d. %s", i + 1, description); + result += output; + continue; + } String output = String.format("%d. %s", i + 1, description + "\n"); result += output; } diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java index cc59faeeec..272b23ba5f 100644 --- a/src/main/java/Ui.java +++ b/src/main/java/Ui.java @@ -1,8 +1,8 @@ import java.util.Scanner; public class Ui { - private String welcomeMessage = "Hey Buddy, I'm Duke\nWhat can I do for you?"; - private String goodbyeMessage = "Goodbye friend. Hope to see you again soon!"; + private final String WELCOME_MESSAGE = "Hey Buddy, I'm Duke\nWhat can I do for you?"; + private final String GOODBYE_MESSAGE = "Goodbye friend. Hope to see you again soon!"; private Scanner scanner; public Ui() { @@ -10,7 +10,7 @@ public Ui() { } public void welcomeUser() { - System.out.println(welcomeMessage); + System.out.println(WELCOME_MESSAGE); } public String readInput() { @@ -21,7 +21,7 @@ public String readInput() { public void goodbyeUser() { System.out.println("======DUKE======"); - System.out.println(goodbyeMessage); + System.out.println(GOODBYE_MESSAGE); this.scanner.close(); System.out.println("================"); } From d339498dc2af30c57bca8c88aa7014fb04516b01 Mon Sep 17 00:00:00 2001 From: Shane Duggan <> Date: Wed, 15 Feb 2023 11:44:17 +0800 Subject: [PATCH 12/28] Added "dates" feature --- data/duke.txt | 8 ++++---- src/main/java/Storage.java | 16 ++++++++-------- src/main/java/Task.java | 28 +++++++++++++++++----------- src/main/java/TaskList.java | 2 +- 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/data/duke.txt b/data/duke.txt index eb6d63bb40..477ec2e278 100644 --- a/data/duke.txt +++ b/data/duke.txt @@ -1,6 +1,6 @@ T|1|read book -D|0|go to perth|today -E|1|play touch|today |tmr +D|0|go to perth|2019-11-01 +E|1|play touch|2019-11-01|2019-12-02 T|0|fly back -D|1|task 3|tmr -E|0|ok|yes|yes \ No newline at end of file +D|1|send video|2021-10-25 +D|0|finish proj|2023-01-01 \ No newline at end of file diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java index 1dd7fbce1e..8a05a50138 100644 --- a/src/main/java/Storage.java +++ b/src/main/java/Storage.java @@ -18,22 +18,22 @@ public ArrayList load() { String line; while ((line = reader.readLine()) != null) { String[] parts = line.split("\\|"); - if (parts[0].equalsIgnoreCase("T")) { - Task t = new Task.Todo(parts[2]); + if (parts[0].strip().equalsIgnoreCase("T")) { + Task t = new Task.Todo(parts[2].strip()); taskList.add(t); - if (parts[1].equalsIgnoreCase("1")) { + if (parts[1].strip().equalsIgnoreCase("1")) { t.markDone(); } - } else if (parts[0].equalsIgnoreCase("D")) { - Task t = new Task.Deadline(parts[2], parts[3]); + } else if (parts[0].strip().equalsIgnoreCase("D")) { + Task t = new Task.Deadline(parts[2].strip(), parts[3].strip()); taskList.add(t); - if (parts[1].equalsIgnoreCase("1")) { + if (parts[1].strip().equalsIgnoreCase("1")) { t.markDone(); } } else { - Task t = new Task.Event(parts[2], parts[3] + " ", parts[4]); + Task t = new Task.Event(parts[2].strip(), parts[3].strip(), parts[4].strip()); taskList.add(t); - if (parts[1].equalsIgnoreCase("1")) { + if (parts[1].strip().equalsIgnoreCase("1")) { t.markDone(); } } diff --git a/src/main/java/Task.java b/src/main/java/Task.java index 4f0d42629e..8a3126a1ae 100644 --- a/src/main/java/Task.java +++ b/src/main/java/Task.java @@ -1,3 +1,6 @@ +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + public class Task { protected String description; protected boolean isDone; @@ -14,7 +17,7 @@ public String toData() { public static class Todo extends Task { public Todo(String description) { - super(description); + super(description.strip()); } @Override @@ -35,11 +38,11 @@ public String toString() { public static class Deadline extends Task { - protected String by; + protected LocalDate by; public Deadline(String description, String by) { - super(description); - this.by = by; + super(description.strip()); + this.by = LocalDate.parse(by); } @Override @@ -54,19 +57,20 @@ public String toData() { @Override public String toString() { - return "[D]" + super.toString() + " (by: " + by + ")"; + String byFormatted = by.format(DateTimeFormatter.ofPattern("MMM d yyyy")); + return "[D]" + super.toString() + " (by: " + byFormatted + ")"; } } public static class Event extends Task { - protected String from; - protected String to; + protected LocalDate from; + protected LocalDate to; public Event(String description, String from, String to) { - super(description); - this.from = from; - this.to = to; + super(description.strip()); + this.from = LocalDate.parse(from); + this.to = LocalDate.parse(to); } @@ -82,7 +86,9 @@ public String toData() { @Override public String toString() { - return "[E]" + super.toString() + " (from: " + from + "to: " + to + ")"; + String fromFormatted = from.format(DateTimeFormatter.ofPattern("MMM d yyyy")); + String toFormatted = to.format(DateTimeFormatter.ofPattern("MMM d yyyy")); + return "[E]" + super.toString() + " (from: " + fromFormatted + " to: " + toFormatted + ")"; } } diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index 1e6da28a35..8ecbd760ce 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -88,4 +88,4 @@ public String toString() { } return result; } -} +} From 5c3b10d6c91b5205d758aef9482f4b96196643aa Mon Sep 17 00:00:00 2001 From: Shane Duggan <> Date: Wed, 15 Feb 2023 15:44:42 +0800 Subject: [PATCH 13/28] Created package for "duke" --- data/duke.txt | 3 +- src/main/java/duke/DukeException.java | 7 ++ src/main/java/duke/Parser.java | 45 ++++++++++ src/main/java/duke/Storage.java | 59 +++++++++++++ src/main/java/duke/Task.java | 114 ++++++++++++++++++++++++++ src/main/java/duke/TaskList.java | 93 +++++++++++++++++++++ src/main/java/duke/Ui.java | 40 +++++++++ 7 files changed, 359 insertions(+), 2 deletions(-) create mode 100644 src/main/java/duke/DukeException.java create mode 100644 src/main/java/duke/Parser.java create mode 100644 src/main/java/duke/Storage.java create mode 100644 src/main/java/duke/Task.java create mode 100644 src/main/java/duke/TaskList.java create mode 100644 src/main/java/duke/Ui.java diff --git a/data/duke.txt b/data/duke.txt index 477ec2e278..bbdf4c7007 100644 --- a/data/duke.txt +++ b/data/duke.txt @@ -1,6 +1,5 @@ T|1|read book D|0|go to perth|2019-11-01 E|1|play touch|2019-11-01|2019-12-02 -T|0|fly back -D|1|send video|2021-10-25 +D|0|send video|2021-10-25 D|0|finish proj|2023-01-01 \ No newline at end of file diff --git a/src/main/java/duke/DukeException.java b/src/main/java/duke/DukeException.java new file mode 100644 index 0000000000..2b061ff9ca --- /dev/null +++ b/src/main/java/duke/DukeException.java @@ -0,0 +1,7 @@ +package duke; + +public class DukeException extends Exception{ + public DukeException(String e) { + super(e); + } +} \ No newline at end of file diff --git a/src/main/java/duke/Parser.java b/src/main/java/duke/Parser.java new file mode 100644 index 0000000000..5ffc779811 --- /dev/null +++ b/src/main/java/duke/Parser.java @@ -0,0 +1,45 @@ +package duke; + +public class Parser { + String action; + + public void parse(String textInput) { + if (textInput.equalsIgnoreCase("bye")) { + this.action = "bye"; + } + + else if (textInput.equalsIgnoreCase("list")) { + this.action = "list"; + } + + else if (textInput.length() >= 8 && + textInput.substring(0, 6).equalsIgnoreCase("delete")) { + this.action = "delete"; + } + + else if (textInput.length() >= 6 && + textInput.substring(0, 4).equalsIgnoreCase("mark")) { + this.action = "mark"; + } + + else if (textInput.length() >= 8 && + textInput.substring(0, 6).equalsIgnoreCase("unmark")) { + this.action = "unmark"; + } + + else if (textInput.length() >= 4 && + textInput.substring(0, 4).equalsIgnoreCase("todo")) { + this.action = "todo"; + } + + else if (textInput.length() >= 10 && + textInput.substring(0, 8).equalsIgnoreCase("deadline")) { + this.action = "deadline"; + } + + else if (textInput.length() >= 7 && + textInput.substring(0, 5).equalsIgnoreCase("event")) { + this.action = "event"; + } + } +} diff --git a/src/main/java/duke/Storage.java b/src/main/java/duke/Storage.java new file mode 100644 index 0000000000..752d53dc2a --- /dev/null +++ b/src/main/java/duke/Storage.java @@ -0,0 +1,59 @@ +package duke; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; + +public class Storage { + private final String FILE_PATH; + + public Storage(String filePath) { + this.FILE_PATH = filePath; + } + + public ArrayList load() { + ArrayList taskList = new ArrayList<>(); + try (BufferedReader reader = new BufferedReader(new FileReader(FILE_PATH))) { + String line; + while ((line = reader.readLine()) != null) { + String[] parts = line.split("\\|"); + if (parts[0].strip().equalsIgnoreCase("T")) { + Task t = new Task.Todo(parts[2]); + taskList.add(t); + if (parts[1].strip().equalsIgnoreCase("1")) { + t.markDone(); + } + } else if (parts[0].strip().equalsIgnoreCase("D")) { + Task t = new Task.Deadline(parts[2], parts[3]); + taskList.add(t); + if (parts[1].strip().equalsIgnoreCase("1")) { + t.markDone(); + } + } else { + Task t = new Task.Event(parts[2], parts[3], parts[4]); + taskList.add(t); + if (parts[1].strip().equalsIgnoreCase("1")) { + t.markDone(); + } + } + } + return taskList; + } catch (IOException e) { + System.out.println("An error occurred while reading the file: " + e.getMessage()); + return new ArrayList<>(); + } + } + + public void writeTxt(TaskList list) { + try (BufferedWriter writer = new BufferedWriter(new FileWriter(FILE_PATH))) { + String toWrite = list.toWrite(); + writer.write(toWrite); + } catch (IOException e) { + System.out.println("An error occurred while writing to the file: " + e.getMessage()); + } +} + +} diff --git a/src/main/java/duke/Task.java b/src/main/java/duke/Task.java new file mode 100644 index 0000000000..b72a71f547 --- /dev/null +++ b/src/main/java/duke/Task.java @@ -0,0 +1,114 @@ +package duke; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +public class Task { + protected String description; + protected boolean isDone; + + public Task(String description) { + this.description = description; + this.isDone = false; + } + + public String toData() { + return ""; + } + + public static class Todo extends Task { + + public Todo(String description) { + super(description.strip()); + } + + @Override + public String toData() { + int isDoneData = 0; + if (this.isDone) { + isDoneData = 1; + } + String result = String.format("T|%d|%s", isDoneData, this.description); + return result; + } + + @Override + public String toString() { + return "[T]" + super.toString(); + } + } + + public static class Deadline extends Task { + + protected LocalDate by; + + public Deadline(String description, String by) { + super(description.strip()); + this.by = LocalDate.parse(by.strip()); + } + + @Override + public String toData() { + int isDoneData = 0; + if (this.isDone) { + isDoneData = 1; + } + String result = String.format("D|%d|%s|%s", isDoneData, this.description, this.by); + return result; + } + + @Override + public String toString() { + String byFormatted = by.format(DateTimeFormatter.ofPattern("MMM d yyyy")); + return "[D]" + super.toString() + " (by: " + byFormatted + ")"; + } + } + + public static class Event extends Task { + + protected LocalDate from; + protected LocalDate to; + + public Event(String description, String from, String to) { + super(description.strip()); + this.from = LocalDate.parse(from.strip()); + this.to = LocalDate.parse(to.strip()); + + } + + @Override + public String toData() { + int isDoneData = 0; + if (this.isDone) { + isDoneData = 1; + } + String result = String.format("E|%d|%s|%s|%s", isDoneData, this.description, this.from, this.to); + return result; + } + + @Override + public String toString() { + String fromFormatted = from.format(DateTimeFormatter.ofPattern("MMM d yyyy")); + String toFormatted = to.format(DateTimeFormatter.ofPattern("MMM d yyyy")); + return "[E]" + super.toString() + " (from: " + fromFormatted + " to: " + toFormatted + ")"; + } + } + + public String getStatusIcon() { + return (isDone ? "X" : " "); // mark done task with X + } + + public void markDone() { + this.isDone = true; + } + + public void markUndone() { + this.isDone = false; + } + + @Override + public String toString() { + String result = String.format("[%s] %s", this.getStatusIcon(), this.description); + return result; + } +} \ No newline at end of file diff --git a/src/main/java/duke/TaskList.java b/src/main/java/duke/TaskList.java new file mode 100644 index 0000000000..45ddfc8607 --- /dev/null +++ b/src/main/java/duke/TaskList.java @@ -0,0 +1,93 @@ +package duke; + +import java.util.ArrayList; + +public class TaskList { + private ArrayList taskList; + + public TaskList(ArrayList taskList) { + this.taskList = taskList; + } + + public String delete(String textInput) { + int i = Integer.parseInt(textInput.substring(7)); + Task t = taskList.get(i - 1); + taskList.remove(i - 1); + String removedText = String.format("Got it. I've removed this task: %s\n", t.toString()); + String listSize = String.format("Now you have %d tasks in the list", taskList.size()); + return removedText + listSize; + } + + public String mark(String textInput) { + int i = Integer.parseInt(textInput.substring(5)); + Task currTask = taskList.get(i - 1); + currTask.markDone(); + String output = "Nice! I've marked this task as done\n" + currTask.toString(); + return output; + } + + public String unmark(String textInput) { + int i = Integer.parseInt(textInput.substring(7)); + Task currTask = taskList.get(i - 1); + currTask.markUndone(); + String output = "OK, I've marked this task as not done yet:\n" + currTask.toString(); + return output; + } + + public String todo(String textInput) throws DukeException { + String[] parts = textInput.split(" ", 2); + if (parts.length == 1 || parts[1] == "") { + throw new DukeException("☹ OOPS!!! The description of a todo cannot be empty."); + } + Task t = new Task.Todo(textInput.substring(5)); + taskList.add(t); + String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), taskList.size()); + return output; + } + + public String deadline(String textInput) { + String[] parts = textInput.split("/"); + Task t = new Task.Deadline(parts[0].substring(9), parts[1].substring(3)); + taskList.add(t); + String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), taskList.size()); + return output; + } + + public String event(String textInput) { + String[] parts = textInput.split("/"); + Task t = new Task.Event(parts[0].substring(6), parts[1].substring(5), parts[2].substring(3)); + taskList.add(t); + String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), taskList.size()); + return output; + } + + public String toWrite() { + int length = this.taskList.size(); + String result = ""; + for (int i = 0; i < length; i++) { + String item = taskList.get(i).toData(); + if (i == length - 1) { + result += item; + continue; + } + result += item + "\n"; + } + return result; + } + + @Override + public String toString() { + String result = ""; + for (int i = 0; i < taskList.size(); i++) { + String description = taskList.get(i).toString(); + if (i == taskList.size() - 1) { + String output = String.format("%d. %s", i + 1, description); + result += output; + continue; + } + String output = String.format("%d. %s", i + 1, description + "\n"); + result += output; + } + return result; + } +} diff --git a/src/main/java/duke/Ui.java b/src/main/java/duke/Ui.java new file mode 100644 index 0000000000..de63bfbca2 --- /dev/null +++ b/src/main/java/duke/Ui.java @@ -0,0 +1,40 @@ +package duke; + +import java.util.Scanner; + +public class Ui { + private final String WELCOME_MESSAGE = "Hey Buddy, I'm Duke\nWhat can I do for you?"; + private final String GOODBYE_MESSAGE = "Goodbye friend. Hope to see you again soon!"; + private Scanner scanner; + + public Ui() { + this.scanner = new Scanner(System.in); + } + + public void welcomeUser() { + System.out.println(WELCOME_MESSAGE); + } + + public String readInput() { + System.out.println("=======ME======="); + String textInput = this.scanner.nextLine(); + return textInput; + } + + public void goodbyeUser() { + System.out.println("======DUKE======"); + System.out.println(GOODBYE_MESSAGE); + this.scanner.close(); + System.out.println("================"); + } + + public void listTasks(TaskList taskList) { + System.out.println("======DUKE======"); + System.out.println(taskList.toString()); + } + + public void printResponse(String response) { + System.out.println("======DUKE======"); + System.out.println(response); + } +} \ No newline at end of file From 72d07600fcfaa1e65021dd007f2597f533f64c7d Mon Sep 17 00:00:00 2001 From: Shane Duggan <> Date: Wed, 15 Feb 2023 15:46:06 +0800 Subject: [PATCH 14/28] Moved files to package folder --- src/main/java/DukeException.java | 5 -- src/main/java/Parser.java | 43 ----------- src/main/java/Storage.java | 57 --------------- src/main/java/Task.java | 112 ----------------------------- src/main/java/TaskList.java | 91 ----------------------- src/main/java/Ui.java | 38 ---------- src/main/java/{ => duke}/Duke.java | 28 ++++---- 7 files changed, 15 insertions(+), 359 deletions(-) delete mode 100644 src/main/java/DukeException.java delete mode 100644 src/main/java/Parser.java delete mode 100644 src/main/java/Storage.java delete mode 100644 src/main/java/Task.java delete mode 100644 src/main/java/TaskList.java delete mode 100644 src/main/java/Ui.java rename src/main/java/{ => duke}/Duke.java (72%) diff --git a/src/main/java/DukeException.java b/src/main/java/DukeException.java deleted file mode 100644 index 4ecbe623d8..0000000000 --- a/src/main/java/DukeException.java +++ /dev/null @@ -1,5 +0,0 @@ -public class DukeException extends Exception{ - public DukeException(String e) { - super(e); - } -} diff --git a/src/main/java/Parser.java b/src/main/java/Parser.java deleted file mode 100644 index 89ccb2ca05..0000000000 --- a/src/main/java/Parser.java +++ /dev/null @@ -1,43 +0,0 @@ -public class Parser { - String action; - - public void parse(String textInput) { - if (textInput.equalsIgnoreCase("bye")) { - this.action = "bye"; - } - - else if (textInput.equalsIgnoreCase("list")) { - this.action = "list"; - } - - else if (textInput.length() >= 8 && - textInput.substring(0, 6).equalsIgnoreCase("delete")) { - this.action = "delete"; - } - - else if (textInput.length() >= 6 && - textInput.substring(0, 4).equalsIgnoreCase("mark")) { - this.action = "mark"; - } - - else if (textInput.length() >= 8 && - textInput.substring(0, 6).equalsIgnoreCase("unmark")) { - this.action = "unmark"; - } - - else if (textInput.length() >= 4 && - textInput.substring(0, 4).equalsIgnoreCase("todo")) { - this.action = "todo"; - } - - else if (textInput.length() >= 10 && - textInput.substring(0, 8).equalsIgnoreCase("deadline")) { - this.action = "deadline"; - } - - else if (textInput.length() >= 7 && - textInput.substring(0, 5).equalsIgnoreCase("event")) { - this.action = "event"; - } - } -} diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java deleted file mode 100644 index 8a05a50138..0000000000 --- a/src/main/java/Storage.java +++ /dev/null @@ -1,57 +0,0 @@ -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; - -public class Storage { - private String filePath; - - public Storage(String filePath) { - this.filePath = filePath; - } - - public ArrayList load() { - ArrayList taskList = new ArrayList<>(); - try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) { - String line; - while ((line = reader.readLine()) != null) { - String[] parts = line.split("\\|"); - if (parts[0].strip().equalsIgnoreCase("T")) { - Task t = new Task.Todo(parts[2].strip()); - taskList.add(t); - if (parts[1].strip().equalsIgnoreCase("1")) { - t.markDone(); - } - } else if (parts[0].strip().equalsIgnoreCase("D")) { - Task t = new Task.Deadline(parts[2].strip(), parts[3].strip()); - taskList.add(t); - if (parts[1].strip().equalsIgnoreCase("1")) { - t.markDone(); - } - } else { - Task t = new Task.Event(parts[2].strip(), parts[3].strip(), parts[4].strip()); - taskList.add(t); - if (parts[1].strip().equalsIgnoreCase("1")) { - t.markDone(); - } - } - } - return taskList; - } catch (IOException e) { - System.out.println("An error occurred while reading the file: " + e.getMessage()); - return new ArrayList<>(); - } - } - - public void writeTxt(TaskList list) { - try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) { - String toWrite = list.toWrite(); - writer.write(toWrite); - } catch (IOException e) { - System.out.println("An error occurred while writing to the file: " + e.getMessage()); - } -} - -} diff --git a/src/main/java/Task.java b/src/main/java/Task.java deleted file mode 100644 index 8a3126a1ae..0000000000 --- a/src/main/java/Task.java +++ /dev/null @@ -1,112 +0,0 @@ -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; - -public class Task { - protected String description; - protected boolean isDone; - - public Task(String description) { - this.description = description; - this.isDone = false; - } - - public String toData() { - return ""; - } - - public static class Todo extends Task { - - public Todo(String description) { - super(description.strip()); - } - - @Override - public String toData() { - int isDoneData = 0; - if (this.isDone) { - isDoneData = 1; - } - String result = String.format("T|%d|%s", isDoneData, this.description); - return result; - } - - @Override - public String toString() { - return "[T]" + super.toString(); - } - } - - public static class Deadline extends Task { - - protected LocalDate by; - - public Deadline(String description, String by) { - super(description.strip()); - this.by = LocalDate.parse(by); - } - - @Override - public String toData() { - int isDoneData = 0; - if (this.isDone) { - isDoneData = 1; - } - String result = String.format("D|%d|%s|%s", isDoneData, this.description, this.by); - return result; - } - - @Override - public String toString() { - String byFormatted = by.format(DateTimeFormatter.ofPattern("MMM d yyyy")); - return "[D]" + super.toString() + " (by: " + byFormatted + ")"; - } - } - - public static class Event extends Task { - - protected LocalDate from; - protected LocalDate to; - - public Event(String description, String from, String to) { - super(description.strip()); - this.from = LocalDate.parse(from); - this.to = LocalDate.parse(to); - - } - - @Override - public String toData() { - int isDoneData = 0; - if (this.isDone) { - isDoneData = 1; - } - String result = String.format("E|%d|%s|%s|%s", isDoneData, this.description, this.from, this.to); - return result; - } - - @Override - public String toString() { - String fromFormatted = from.format(DateTimeFormatter.ofPattern("MMM d yyyy")); - String toFormatted = to.format(DateTimeFormatter.ofPattern("MMM d yyyy")); - return "[E]" + super.toString() + " (from: " + fromFormatted + " to: " + toFormatted + ")"; - } - } - - public String getStatusIcon() { - return (isDone ? "X" : " "); // mark done task with X - } - - public void markDone() { - this.isDone = true; - } - - public void markUndone() { - this.isDone = false; - } - - @Override - public String toString() { - String result = String.format("[%s] %s", this.getStatusIcon(), this.description); - return result; - } -} \ No newline at end of file diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java deleted file mode 100644 index 8ecbd760ce..0000000000 --- a/src/main/java/TaskList.java +++ /dev/null @@ -1,91 +0,0 @@ -import java.util.ArrayList; - -public class TaskList { - private ArrayList taskList; - - public TaskList(ArrayList taskList) { - this.taskList = taskList; - } - - public String delete(String textInput) { - int i = Integer.parseInt(textInput.substring(7)); - Task t = taskList.get(i - 1); - taskList.remove(i - 1); - String removedText = String.format("Got it. I've removed this task: %s\n", t.toString()); - String listSize = String.format("Now you have %d tasks in the list", taskList.size()); - return removedText + listSize; - } - - public String mark(String textInput) { - int i = Integer.parseInt(textInput.substring(5)); - Task currTask = taskList.get(i - 1); - currTask.markDone(); - String output = "Nice! I've marked this task as done\n" + currTask.toString(); - return output; - } - - public String unmark(String textInput) { - int i = Integer.parseInt(textInput.substring(7)); - Task currTask = taskList.get(i - 1); - currTask.markUndone(); - String output = "OK, I've marked this task as not done yet:\n" + currTask.toString(); - return output; - } - - public String todo(String textInput) throws DukeException { - String[] parts = textInput.split(" ", 2); - if (parts.length == 1 || parts[1] == "") { - throw new DukeException("☹ OOPS!!! The description of a todo cannot be empty."); - } - Task t = new Task.Todo(textInput.substring(5)); - taskList.add(t); - String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), taskList.size()); - return output; - } - - public String deadline(String textInput) { - String[] parts = textInput.split("/"); - Task t = new Task.Deadline(parts[0].substring(9), parts[1].substring(3)); - taskList.add(t); - String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), taskList.size()); - return output; - } - - public String event(String textInput) { - String[] parts = textInput.split("/"); - Task t = new Task.Event(parts[0].substring(6), parts[1].substring(5), parts[2].substring(3)); - taskList.add(t); - String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), taskList.size()); - return output; - } - - public String toWrite() { - int length = this.taskList.size(); - String result = ""; - for (int i = 0; i < length; i++) { - String item = taskList.get(i).toData(); - if (i == length - 1) { - result += item; - continue; - } - result += item + "\n"; - } - return result; - } - - @Override - public String toString() { - String result = ""; - for (int i = 0; i < taskList.size(); i++) { - String description = taskList.get(i).toString(); - if (i == taskList.size() - 1) { - String output = String.format("%d. %s", i + 1, description); - result += output; - continue; - } - String output = String.format("%d. %s", i + 1, description + "\n"); - result += output; - } - return result; - } -} diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java deleted file mode 100644 index 272b23ba5f..0000000000 --- a/src/main/java/Ui.java +++ /dev/null @@ -1,38 +0,0 @@ -import java.util.Scanner; - -public class Ui { - private final String WELCOME_MESSAGE = "Hey Buddy, I'm Duke\nWhat can I do for you?"; - private final String GOODBYE_MESSAGE = "Goodbye friend. Hope to see you again soon!"; - private Scanner scanner; - - public Ui() { - this.scanner = new Scanner(System.in); - } - - public void welcomeUser() { - System.out.println(WELCOME_MESSAGE); - } - - public String readInput() { - System.out.println("=======ME======="); - String textInput = this.scanner.nextLine(); - return textInput; - } - - public void goodbyeUser() { - System.out.println("======DUKE======"); - System.out.println(GOODBYE_MESSAGE); - this.scanner.close(); - System.out.println("================"); - } - - public void listTasks(TaskList taskList) { - System.out.println("======DUKE======"); - System.out.println(taskList.toString()); - } - - public void printResponse(String response) { - System.out.println("======DUKE======"); - System.out.println(response); - } -} \ No newline at end of file diff --git a/src/main/java/Duke.java b/src/main/java/duke/Duke.java similarity index 72% rename from src/main/java/Duke.java rename to src/main/java/duke/Duke.java index 18b71cb44d..114395252d 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/duke/Duke.java @@ -1,8 +1,10 @@ +package duke; + public class Duke { - private Ui ui; - private Storage storage; - private TaskList tasks; + private final Ui ui; + private final Storage storage; + private final TaskList tasks; private Parser parser; public Duke(String filePath) { @@ -17,36 +19,36 @@ public void run() { while (true) { String textInput = this.ui.readInput(); - String response = ""; + String response; this.parser = new Parser(); this.parser.parse(textInput); - if (this.parser.action == "bye") { + if (this.parser.action.equals("bye")) { this.ui.goodbyeUser(); return; } - else if (this.parser.action == "list") { + else if (this.parser.action.equals("list")) { this.ui.listTasks(tasks); continue; } - else if (this.parser.action == "delete") { + else if (this.parser.action.equals("delete")) { response = this.tasks.delete(textInput); this.storage.writeTxt(tasks); } - else if (this.parser.action == "mark") { + else if (this.parser.action.equals("mark")) { response = this.tasks.mark(textInput); this.storage.writeTxt(tasks); } - else if (this.parser.action == "unmark") { + else if (this.parser.action.equals("unmark")) { response = this.tasks.unmark(textInput); this.storage.writeTxt(tasks); } - else if (this.parser.action == "todo") { + else if (this.parser.action.equals("todo")) { try { response = this.tasks.todo(textInput); this.storage.writeTxt(tasks); @@ -57,12 +59,12 @@ else if (this.parser.action == "todo") { } } - else if (this.parser.action == "deadline") { + else if (this.parser.action.equals("deadline")) { response = this.tasks.deadline(textInput); this.storage.writeTxt(tasks); } - else if (this.parser.action == "event") { + else if (this.parser.action.equals("event")) { response = this.tasks.event(textInput); this.storage.writeTxt(tasks); } @@ -76,6 +78,6 @@ else if (this.parser.action == "event") { } public static void main(String[] args) { - new Duke("../../../data/duke.txt").run(); + new Duke(System.getProperty("user.dir") + "/data/duke.txt").run(); } } \ No newline at end of file From f9a3ce9e3cd174beceeee8e93868ccea1101bce3 Mon Sep 17 00:00:00 2001 From: Shane Duggan <> Date: Wed, 15 Feb 2023 16:18:29 +0800 Subject: [PATCH 15/28] ADD gradle functionality --- build.gradle | 19 +++ data/duke.txt | 2 +- gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59536 bytes gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 185 +++++++++++++++++++++++ gradlew.bat | 89 +++++++++++ settings.gradle | 2 + 7 files changed, 301 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 100755 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000000..3cae2d720f --- /dev/null +++ b/build.gradle @@ -0,0 +1,19 @@ +plugins { + id 'java' +} + +group 'org.example' +version '1.0-SNAPSHOT' + +repositories { + mavenCentral() +} + +dependencies { + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/data/duke.txt b/data/duke.txt index bbdf4c7007..0066e20b70 100644 --- a/data/duke.txt +++ b/data/duke.txt @@ -2,4 +2,4 @@ T|1|read book D|0|go to perth|2019-11-01 E|1|play touch|2019-11-01|2019-12-02 D|0|send video|2021-10-25 -D|0|finish proj|2023-01-01 \ No newline at end of file +D|1|finish proj|2023-01-01 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..7454180f2ae8848c63b8b4dea2cb829da983f2fa GIT binary patch literal 59536 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 QuEJmfE|#`Dqx|px0L@K;Y5)KL literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..ffed3a254e --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000000..744e882ed5 --- /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 + ;; + MSYS* | 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..ac1b06f938 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@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 execute + +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 execute + +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 + +: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 %* + +: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 diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000000..972cd8b6b1 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'ip' + From 91d7ec71b4d67d6fadf25813d393102caf34d440 Mon Sep 17 00:00:00 2001 From: Shane Duggan <> Date: Wed, 15 Feb 2023 17:04:57 +0800 Subject: [PATCH 16/28] ADD JUnit tests --- build.gradle | 4 ++-- data/duke.txt | 4 ++-- src/test/java/duke/ParserTest.java | 31 ++++++++++++++++++++++++++++++ src/test/java/duke/TaskTest.java | 14 ++++++++++++++ 4 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 src/test/java/duke/ParserTest.java create mode 100644 src/test/java/duke/TaskTest.java diff --git a/build.gradle b/build.gradle index 3cae2d720f..add9804009 100644 --- a/build.gradle +++ b/build.gradle @@ -10,8 +10,8 @@ repositories { } dependencies { - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0' + testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.0' } test { diff --git a/data/duke.txt b/data/duke.txt index 0066e20b70..181983866b 100644 --- a/data/duke.txt +++ b/data/duke.txt @@ -1,5 +1,5 @@ T|1|read book D|0|go to perth|2019-11-01 E|1|play touch|2019-11-01|2019-12-02 -D|0|send video|2021-10-25 -D|1|finish proj|2023-01-01 \ No newline at end of file +D|1|send video|2021-10-25 +D|0|finish proj|2023-01-01 \ No newline at end of file diff --git a/src/test/java/duke/ParserTest.java b/src/test/java/duke/ParserTest.java new file mode 100644 index 0000000000..7d2139301e --- /dev/null +++ b/src/test/java/duke/ParserTest.java @@ -0,0 +1,31 @@ +package duke; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ParserTest { + @Test + public void parseTodoTest(){ + String textInput = "todo read book"; + Parser p = new Parser(); + p.parse(textInput); + assertEquals(p.action, "todo"); + } + + @Test + public void parseDeadlineTest(){ + String textInput = "deadline return book /by 2023-01-01"; + Parser p = new Parser(); + p.parse(textInput); + assertEquals(p.action, "deadline"); + } + + @Test + public void parseEventTest(){ + String textInput = "event career fair /from 2023-01-01 /to 2023-01-02"; + Parser p = new Parser(); + p.parse(textInput); + assertEquals(p.action, "event"); + } +} diff --git a/src/test/java/duke/TaskTest.java b/src/test/java/duke/TaskTest.java new file mode 100644 index 0000000000..83084bc5c6 --- /dev/null +++ b/src/test/java/duke/TaskTest.java @@ -0,0 +1,14 @@ +package duke; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TaskTest { + @Test + public void toStringTest(){ + Task t1 = new Task("read book"); + String result = "[ ] read book"; + assertEquals(t1.toString(), result); + } +} From 34281acb8812c623dd3fbea3b3e6fc1c01538272 Mon Sep 17 00:00:00 2001 From: Shane Duggan <> Date: Wed, 15 Feb 2023 18:13:42 +0800 Subject: [PATCH 17/28] ADD find feature --- build.gradle | 15 ++++++++++ data/duke.txt | 4 +-- src/main/java/META-INF/MANIFEST.MF | 3 ++ src/main/java/duke/Duke.java | 10 +++++++ src/main/java/duke/Parser.java | 9 ++++++ src/main/java/duke/TaskList.java | 45 +++++++++++++++++++----------- 6 files changed, 68 insertions(+), 18 deletions(-) create mode 100644 src/main/java/META-INF/MANIFEST.MF diff --git a/build.gradle b/build.gradle index add9804009..8850b91970 100644 --- a/build.gradle +++ b/build.gradle @@ -12,6 +12,21 @@ repositories { dependencies { testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0' testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.0' + + 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' } test { diff --git a/data/duke.txt b/data/duke.txt index 181983866b..ad7ca2c721 100644 --- a/data/duke.txt +++ b/data/duke.txt @@ -1,5 +1,5 @@ T|1|read book D|0|go to perth|2019-11-01 E|1|play touch|2019-11-01|2019-12-02 -D|1|send video|2021-10-25 -D|0|finish proj|2023-01-01 \ No newline at end of file +D|0|finish proj|2023-01-01 +E|0|book fair|2023-01-01|2023-01-02 \ No newline at end of file diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..6e864153e8 --- /dev/null +++ b/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: duke.Duke + diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 114395252d..3eedb7041e 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -48,6 +48,16 @@ else if (this.parser.action.equals("unmark")) { this.storage.writeTxt(tasks); } + else if (this.parser.action.equals("find")) { + try { + response = this.tasks.find(textInput); + } catch (DukeException e) { + response = e.toString(); + this.ui.printResponse(response); + continue; + } + } + else if (this.parser.action.equals("todo")) { try { response = this.tasks.todo(textInput); diff --git a/src/main/java/duke/Parser.java b/src/main/java/duke/Parser.java index 5ffc779811..223b62010d 100644 --- a/src/main/java/duke/Parser.java +++ b/src/main/java/duke/Parser.java @@ -27,6 +27,11 @@ else if (textInput.length() >= 8 && this.action = "unmark"; } + else if (textInput.length() >= 6 && + textInput.substring(0, 4).equalsIgnoreCase("find")) { + this.action = "find"; + } + else if (textInput.length() >= 4 && textInput.substring(0, 4).equalsIgnoreCase("todo")) { this.action = "todo"; @@ -41,5 +46,9 @@ else if (textInput.length() >= 7 && textInput.substring(0, 5).equalsIgnoreCase("event")) { this.action = "event"; } + + else { + this.action = "not found"; + } } } diff --git a/src/main/java/duke/TaskList.java b/src/main/java/duke/TaskList.java index 45ddfc8607..1ccba61d28 100644 --- a/src/main/java/duke/TaskList.java +++ b/src/main/java/duke/TaskList.java @@ -1,5 +1,6 @@ package duke; +import java.sql.Array; import java.util.ArrayList; public class TaskList { @@ -22,7 +23,7 @@ public String mark(String textInput) { int i = Integer.parseInt(textInput.substring(5)); Task currTask = taskList.get(i - 1); currTask.markDone(); - String output = "Nice! I've marked this task as done\n" + currTask.toString(); + String output = "Nice! I've marked this task as done\n" + currTask; return output; } @@ -30,10 +31,31 @@ public String unmark(String textInput) { int i = Integer.parseInt(textInput.substring(7)); Task currTask = taskList.get(i - 1); currTask.markUndone(); - String output = "OK, I've marked this task as not done yet:\n" + currTask.toString(); + String output = "OK, I've marked this task as not done yet:\n" + currTask; return output; } + public String find(String textInput) throws DukeException { + String[] parts = textInput.split(" ", 2); + if (parts.length == 1 || parts[1] == "") { + throw new DukeException("☹ OOPS!!! The description of find command cannot be empty."); + } + String keyword = "(.*)" + textInput.substring(5) + "(.*)"; + String result = "Here are the matching tasks in your list:\n"; + boolean found = false; + int index = 1; + for (int i = 0; i < taskList.size(); i++) { + String description = taskList.get(i).toString(); + if (description.matches(keyword)) { + found = true; + String output = String.format("%d. %s", index, description + "\n"); + result += output; + index++; + } + } + return found ? result.trim() : "Sorry, there are no matching tasks :-("; + } + public String todo(String textInput) throws DukeException { String[] parts = textInput.split(" ", 2); if (parts.length == 1 || parts[1] == "") { @@ -41,7 +63,7 @@ public String todo(String textInput) throws DukeException { } Task t = new Task.Todo(textInput.substring(5)); taskList.add(t); - String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), taskList.size()); + String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t, taskList.size()); return output; } @@ -49,7 +71,7 @@ public String deadline(String textInput) { String[] parts = textInput.split("/"); Task t = new Task.Deadline(parts[0].substring(9), parts[1].substring(3)); taskList.add(t); - String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), taskList.size()); + String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t, taskList.size()); return output; } @@ -57,7 +79,7 @@ public String event(String textInput) { String[] parts = textInput.split("/"); Task t = new Task.Event(parts[0].substring(6), parts[1].substring(5), parts[2].substring(3)); taskList.add(t); - String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t.toString(), taskList.size()); + String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t, taskList.size()); return output; } @@ -66,13 +88,9 @@ public String toWrite() { String result = ""; for (int i = 0; i < length; i++) { String item = taskList.get(i).toData(); - if (i == length - 1) { - result += item; - continue; - } result += item + "\n"; } - return result; + return result.trim(); } @Override @@ -80,14 +98,9 @@ public String toString() { String result = ""; for (int i = 0; i < taskList.size(); i++) { String description = taskList.get(i).toString(); - if (i == taskList.size() - 1) { - String output = String.format("%d. %s", i + 1, description); - result += output; - continue; - } String output = String.format("%d. %s", i + 1, description + "\n"); result += output; } - return result; + return result.trim(); } } From cb2ebec3496c3435b0cf5e3d8eadf8f490f2f774 Mon Sep 17 00:00:00 2001 From: Shane Duggan <> Date: Wed, 15 Feb 2023 23:55:19 +0800 Subject: [PATCH 18/28] ADD Javadocs to public methods and classes --- src/main/java/duke/Duke.java | 43 +++-- src/main/java/duke/DukeException.java | 9 + src/main/java/duke/Parser.java | 88 +++++----- src/main/java/duke/Storage.java | 102 ++++++----- src/main/java/duke/Task.java | 233 +++++++++++++++++--------- src/main/java/duke/TaskList.java | 196 ++++++++++++++-------- src/main/java/duke/Ui.java | 95 +++++++---- 7 files changed, 469 insertions(+), 297 deletions(-) diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 3eedb7041e..89ec93c27c 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -7,16 +7,24 @@ public class Duke { private final TaskList tasks; private Parser parser; + /** + * Creates a Duke object that references storage from the desired file path + * + * @param filePath the file path to the storage txt file + */ public Duke(String filePath) { this.ui = new Ui(); this.storage = new Storage(filePath); this.tasks = new TaskList(storage.load()); } + /** + * Begins the Duke chat loop + */ public void run() { this.ui.welcomeUser(); - + while (true) { String textInput = this.ui.readInput(); String response; @@ -26,29 +34,24 @@ public void run() { if (this.parser.action.equals("bye")) { this.ui.goodbyeUser(); return; - } - else if (this.parser.action.equals("list")) { + } else if (this.parser.action.equals("list")) { this.ui.listTasks(tasks); continue; - } - else if (this.parser.action.equals("delete")) { + } else if (this.parser.action.equals("delete")) { response = this.tasks.delete(textInput); this.storage.writeTxt(tasks); - } - else if (this.parser.action.equals("mark")) { + } else if (this.parser.action.equals("mark")) { response = this.tasks.mark(textInput); this.storage.writeTxt(tasks); - } - else if (this.parser.action.equals("unmark")) { + } else if (this.parser.action.equals("unmark")) { response = this.tasks.unmark(textInput); this.storage.writeTxt(tasks); - } - else if (this.parser.action.equals("find")) { + } else if (this.parser.action.equals("find")) { try { response = this.tasks.find(textInput); } catch (DukeException e) { @@ -56,37 +59,33 @@ else if (this.parser.action.equals("find")) { this.ui.printResponse(response); continue; } - } - else if (this.parser.action.equals("todo")) { + } else if (this.parser.action.equals("todo")) { try { response = this.tasks.todo(textInput); - this.storage.writeTxt(tasks); + this.storage.writeTxt(tasks); } catch (DukeException e) { response = e.toString(); this.ui.printResponse(response); continue; } - } - else if (this.parser.action.equals("deadline")) { + } else if (this.parser.action.equals("deadline")) { response = this.tasks.deadline(textInput); this.storage.writeTxt(tasks); - } - else if (this.parser.action.equals("event")) { + } else if (this.parser.action.equals("event")) { response = this.tasks.event(textInput); this.storage.writeTxt(tasks); - } - - else { + + } else { response = "☹ OOPS!!! I'm sorry, but I don't know what that means :-("; } this.ui.printResponse(response); } } - + public static void main(String[] args) { new Duke(System.getProperty("user.dir") + "/data/duke.txt").run(); } diff --git a/src/main/java/duke/DukeException.java b/src/main/java/duke/DukeException.java index 2b061ff9ca..181e951dee 100644 --- a/src/main/java/duke/DukeException.java +++ b/src/main/java/duke/DukeException.java @@ -1,6 +1,15 @@ package duke; +/** + * An exception for any errors in the Duke chat operation + */ public class DukeException extends Exception{ + + /** + * Creates an exception for the Duke chat + * + * @param e description of the exception to be thrown + */ public DukeException(String e) { super(e); } diff --git a/src/main/java/duke/Parser.java b/src/main/java/duke/Parser.java index 223b62010d..fa66e261d2 100644 --- a/src/main/java/duke/Parser.java +++ b/src/main/java/duke/Parser.java @@ -1,54 +1,44 @@ package duke; +/** + * A parser that helps to process user inputs into actions to follow up + */ public class Parser { - String action; - - public void parse(String textInput) { - if (textInput.equalsIgnoreCase("bye")) { - this.action = "bye"; - } - - else if (textInput.equalsIgnoreCase("list")) { - this.action = "list"; - } - - else if (textInput.length() >= 8 && - textInput.substring(0, 6).equalsIgnoreCase("delete")) { - this.action = "delete"; - } - - else if (textInput.length() >= 6 && - textInput.substring(0, 4).equalsIgnoreCase("mark")) { - this.action = "mark"; - } - - else if (textInput.length() >= 8 && - textInput.substring(0, 6).equalsIgnoreCase("unmark")) { - this.action = "unmark"; - } - - else if (textInput.length() >= 6 && - textInput.substring(0, 4).equalsIgnoreCase("find")) { - this.action = "find"; - } - - else if (textInput.length() >= 4 && - textInput.substring(0, 4).equalsIgnoreCase("todo")) { - this.action = "todo"; - } - - else if (textInput.length() >= 10 && - textInput.substring(0, 8).equalsIgnoreCase("deadline")) { - this.action = "deadline"; - } - - else if (textInput.length() >= 7 && - textInput.substring(0, 5).equalsIgnoreCase("event")) { - this.action = "event"; - } - - else { - this.action = "not found"; + String action; + + /** + * Parses the user's input to determine the next action to take + * + * @oaram textInput the input message from the user + */ + public void parse(String textInput) { + if (textInput.equalsIgnoreCase("bye")) { + this.action = "bye"; + } else if (textInput.equalsIgnoreCase("list")) { + this.action = "list"; + } else if (textInput.length() >= 8 && + textInput.substring(0, 6).equalsIgnoreCase("delete")) { + this.action = "delete"; + } else if (textInput.length() >= 6 && + textInput.substring(0, 4).equalsIgnoreCase("mark")) { + this.action = "mark"; + } else if (textInput.length() >= 8 && + textInput.substring(0, 6).equalsIgnoreCase("unmark")) { + this.action = "unmark"; + } else if (textInput.length() >= 6 && + textInput.substring(0, 4).equalsIgnoreCase("find")) { + this.action = "find"; + } else if (textInput.length() >= 4 && + textInput.substring(0, 4).equalsIgnoreCase("todo")) { + this.action = "todo"; + } else if (textInput.length() >= 10 && + textInput.substring(0, 8).equalsIgnoreCase("deadline")) { + this.action = "deadline"; + } else if (textInput.length() >= 7 && + textInput.substring(0, 5).equalsIgnoreCase("event")) { + this.action = "event"; + } else { + this.action = "not found"; + } } - } } diff --git a/src/main/java/duke/Storage.java b/src/main/java/duke/Storage.java index 752d53dc2a..a8af7ae442 100644 --- a/src/main/java/duke/Storage.java +++ b/src/main/java/duke/Storage.java @@ -7,53 +7,71 @@ import java.io.IOException; import java.util.ArrayList; +/** + * A storage object that stores the file location of the txt file to be used to log tasks + */ public class Storage { - private final String FILE_PATH; + private final String FILE_PATH; - public Storage(String filePath) { - this.FILE_PATH = filePath; - } + /** + * Creates a new Storage object + * + * @param filePath the txt file to be referenced as storage + */ + public Storage(String filePath) { + this.FILE_PATH = filePath; + } - public ArrayList load() { - ArrayList taskList = new ArrayList<>(); - try (BufferedReader reader = new BufferedReader(new FileReader(FILE_PATH))) { - String line; - while ((line = reader.readLine()) != null) { - String[] parts = line.split("\\|"); - if (parts[0].strip().equalsIgnoreCase("T")) { - Task t = new Task.Todo(parts[2]); - taskList.add(t); - if (parts[1].strip().equalsIgnoreCase("1")) { - t.markDone(); - } - } else if (parts[0].strip().equalsIgnoreCase("D")) { - Task t = new Task.Deadline(parts[2], parts[3]); - taskList.add(t); - if (parts[1].strip().equalsIgnoreCase("1")) { - t.markDone(); - } - } else { - Task t = new Task.Event(parts[2], parts[3], parts[4]); - taskList.add(t); - if (parts[1].strip().equalsIgnoreCase("1")) { - t.markDone(); - } - } - } - return taskList; - } catch (IOException e) { - System.out.println("An error occurred while reading the file: " + e.getMessage()); - return new ArrayList<>(); + /** + * Loads the tasks as an ArrayList from a referenced Storage object's txt file + * + * @return ArrayList of the referenced Storage object + */ + public ArrayList load() { + ArrayList taskList = new ArrayList<>(); + try (BufferedReader reader = new BufferedReader(new FileReader(FILE_PATH))) { + String line; + while ((line = reader.readLine()) != null) { + String[] parts = line.split("\\|"); + if (parts[0].strip().equalsIgnoreCase("T")) { + Task t = new Task.Todo(parts[2]); + taskList.add(t); + if (parts[1].strip().equalsIgnoreCase("1")) { + t.markDone(); + } + } else if (parts[0].strip().equalsIgnoreCase("D")) { + Task t = new Task.Deadline(parts[2], parts[3]); + taskList.add(t); + if (parts[1].strip().equalsIgnoreCase("1")) { + t.markDone(); + } + } else { + Task t = new Task.Event(parts[2], parts[3], parts[4]); + taskList.add(t); + if (parts[1].strip().equalsIgnoreCase("1")) { + t.markDone(); + } + } + } + return taskList; + } catch (IOException e) { + System.out.println("An error occurred while reading the file: " + e.getMessage()); + return new ArrayList<>(); + } } - } - public void writeTxt(TaskList list) { - try (BufferedWriter writer = new BufferedWriter(new FileWriter(FILE_PATH))) { - String toWrite = list.toWrite(); - writer.write(toWrite); - } catch (IOException e) { - System.out.println("An error occurred while writing to the file: " + e.getMessage()); + /** + * Writes a TaskList into the Storage object's txt file + * + * @param list the TaskList to be written into the referenced Storage object's txt file + */ + public void writeTxt(TaskList list) { + try (BufferedWriter writer = new BufferedWriter(new FileWriter(FILE_PATH))) { + String toWrite = list.toWrite(); + writer.write(toWrite); + } catch (IOException e) { + System.out.println("An error occurred while writing to the file: " + e.getMessage()); + } } -} } diff --git a/src/main/java/duke/Task.java b/src/main/java/duke/Task.java index b72a71f547..b100882e40 100644 --- a/src/main/java/duke/Task.java +++ b/src/main/java/duke/Task.java @@ -3,112 +3,185 @@ import java.time.LocalDate; import java.time.format.DateTimeFormatter; +/** + * Contains all information for tasks in the task list + */ public class Task { - protected String description; - protected boolean isDone; + protected String description; + protected boolean isDone; + + /** + * Creates a task object with a specific description + * + * @param description what the task is about + */ + public Task(String description) { + this.description = description; + this.isDone = false; + } - public Task(String description) { - this.description = description; - this.isDone = false; - } + /** + * Returns the txt formatted version of the referenced tasks + * + * @return txt formatted String of the referenced task + */ + public String toData() { + return ""; + } - public String toData() { - return ""; - } + public static class Todo extends Task { - public static class Todo extends Task { + /** + * Creates to-do object of the given description + * + * @param description what the to-do object is about + */ + public Todo(String description) { + super(description.strip()); + } - public Todo(String description) { - super(description.strip()); - } + /** + * Returns the txt formatted version of the referenced to-do task + * + * @return the txt formatted version of the referenced to-do task + */ + @Override + public String toData() { + int isDoneData = 0; + if (this.isDone) { + isDoneData = 1; + } + return String.format("T|%d|%s", isDoneData, this.description); + } - @Override - public String toData() { - int isDoneData = 0; - if (this.isDone) { - isDoneData = 1; + /** + * Returns the String of the referenced to-do task + * + * @return the String of the referenced to-do task + */ + @Override + public String toString() { + return "[T]" + super.toString(); } - String result = String.format("T|%d|%s", isDoneData, this.description); - return result; } - @Override - public String toString() { - return "[T]" + super.toString(); - } - } + public static class Deadline extends Task { - public static class Deadline extends Task { + protected LocalDate by; - protected LocalDate by; + /** + * Creates deadline object of the given description and finishing date + * + * @param description the description of the task + * @param by the deadline that the class is to be completed + */ + public Deadline(String description, String by) { + super(description.strip()); + this.by = LocalDate.parse(by.strip()); + } - public Deadline(String description, String by) { - super(description.strip()); - this.by = LocalDate.parse(by.strip()); - } + /** + * Returns the txt formatted version of the referenced deadline task + * + * @return the txt formatted version of the referenced deadline task + */ + @Override + public String toData() { + int isDoneData = 0; + if (this.isDone) { + isDoneData = 1; + } + return String.format("D|%d|%s|%s", isDoneData, this.description, this.by); + } - @Override - public String toData() { - int isDoneData = 0; - if (this.isDone) { - isDoneData = 1; + /** + * Returns the String of the referenced deadline task + * + * @return the String of the referenced deadline task + */ + @Override + public String toString() { + String byFormatted = by.format(DateTimeFormatter.ofPattern("MMM d yyyy")); + return "[D]" + super.toString() + " (by: " + byFormatted + ")"; } - String result = String.format("D|%d|%s|%s", isDoneData, this.description, this.by); - return result; } - @Override - public String toString() { - String byFormatted = by.format(DateTimeFormatter.ofPattern("MMM d yyyy")); - return "[D]" + super.toString() + " (by: " + byFormatted + ")"; - } - } + public static class Event extends Task { - public static class Event extends Task { + protected LocalDate from; + protected LocalDate to; - protected LocalDate from; - protected LocalDate to; + /** + * Creates an event object of the given description and time period + * + * @param description the description of the task + * @param from the start of the event + * @param to the end of the event + */ + public Event(String description, String from, String to) { + super(description.strip()); + this.from = LocalDate.parse(from.strip()); + this.to = LocalDate.parse(to.strip()); - public Event(String description, String from, String to) { - super(description.strip()); - this.from = LocalDate.parse(from.strip()); - this.to = LocalDate.parse(to.strip()); + } - } + /** + * Returns the txt formatted version of the referenced event task + * + * @return the txt formatted version of the referenced event task + */ + @Override + public String toData() { + int isDoneData = 0; + if (this.isDone) { + isDoneData = 1; + } + return String.format("E|%d|%s|%s|%s", isDoneData, this.description, this.from, this.to); + } - @Override - public String toData() { - int isDoneData = 0; - if (this.isDone) { - isDoneData = 1; + /** + * Returns the String of the referenced event task + * + * @return the String of the referenced event task + */ + @Override + public String toString() { + String fromFormatted = from.format(DateTimeFormatter.ofPattern("MMM d yyyy")); + String toFormatted = to.format(DateTimeFormatter.ofPattern("MMM d yyyy")); + return "[E]" + super.toString() + " (from: " + fromFormatted + " to: " + toFormatted + ")"; } - String result = String.format("E|%d|%s|%s|%s", isDoneData, this.description, this.from, this.to); - return result; } - @Override - public String toString() { - String fromFormatted = from.format(DateTimeFormatter.ofPattern("MMM d yyyy")); - String toFormatted = to.format(DateTimeFormatter.ofPattern("MMM d yyyy")); - return "[E]" + super.toString() + " (from: " + fromFormatted + " to: " + toFormatted + ")"; + /** + * Returns the status of the referenced task + * + * @return String representation of the status of the referenced task + */ + public String getStatusIcon() { + return (isDone ? "X" : " "); } - } - public String getStatusIcon() { - return (isDone ? "X" : " "); // mark done task with X - } - - public void markDone() { - this.isDone = true; - } + /** + * Marks the current task as done + */ + public void markDone() { + this.isDone = true; + } - public void markUndone() { - this.isDone = false; - } + /** + * Marks the current task as undone + */ + public void markUndone() { + this.isDone = false; + } - @Override - public String toString() { - String result = String.format("[%s] %s", this.getStatusIcon(), this.description); - return result; - } + /** + * Returns the String of the referenced task + * + * @return the String of the referenced task + */ + @Override + public String toString() { + return String.format("[%s] %s", this.getStatusIcon(), this.description); + } } \ No newline at end of file diff --git a/src/main/java/duke/TaskList.java b/src/main/java/duke/TaskList.java index 1ccba61d28..fd36807ae2 100644 --- a/src/main/java/duke/TaskList.java +++ b/src/main/java/duke/TaskList.java @@ -1,43 +1,73 @@ package duke; -import java.sql.Array; import java.util.ArrayList; +/** + * A task list that handles operations from the user to manage their tasks and interact with the storage + */ public class TaskList { - private ArrayList taskList; - - public TaskList(ArrayList taskList) { - this.taskList = taskList; - } + private ArrayList taskList; - public String delete(String textInput) { - int i = Integer.parseInt(textInput.substring(7)); - Task t = taskList.get(i - 1); - taskList.remove(i - 1); - String removedText = String.format("Got it. I've removed this task: %s\n", t.toString()); - String listSize = String.format("Now you have %d tasks in the list", taskList.size()); - return removedText + listSize; - } + /** + * Creates a new task list object to handle operations from the user + * + * @param taskList the initialised task list from the storage txt file + */ + public TaskList(ArrayList taskList) { + this.taskList = taskList; + } - public String mark(String textInput) { - int i = Integer.parseInt(textInput.substring(5)); - Task currTask = taskList.get(i - 1); - currTask.markDone(); - String output = "Nice! I've marked this task as done\n" + currTask; - return output; - } + /** + * Takes in a user text input, processes it to delete a record, and returns the response message + * + * @param textInput the input message from the user + * @return the response message to be printed + */ + public String delete(String textInput) { + int i = Integer.parseInt(textInput.substring(7)); + Task t = taskList.get(i - 1); + taskList.remove(i - 1); + String removedText = String.format("Got it. I've removed this task: %s\n", t.toString()); + String listSize = String.format("Now you have %d tasks in the list", taskList.size()); + return removedText + listSize; + } - public String unmark(String textInput) { - int i = Integer.parseInt(textInput.substring(7)); - Task currTask = taskList.get(i - 1); - currTask.markUndone(); - String output = "OK, I've marked this task as not done yet:\n" + currTask; - return output; - } + /** + * Takes in a user text input, processes it to mark a record as completed, and returns the response message + * + * @param textInput the input message from the user + * @return the response message to be printed + */ + public String mark(String textInput) { + int i = Integer.parseInt(textInput.substring(5)); + Task currTask = taskList.get(i - 1); + currTask.markDone(); + return "Nice! I've marked this task as done\n" + currTask; + } + /** + * Takes in a user text input, processes it to mark a record as uncompleted, and returns the response message + * + * @param textInput the input message from the user + * @return the response message to be printed + */ + public String unmark(String textInput) { + int i = Integer.parseInt(textInput.substring(7)); + Task currTask = taskList.get(i - 1); + currTask.markUndone(); + return "OK, I've marked this task as not done yet:\n" + currTask; + } + + /** + * Takes in a user text input, processes it to find matching records, and returns the response message + * + * @param textInput the input message from the user + * @return the response message to be printed + * @throws DukeException if no find keyword is given + */ public String find(String textInput) throws DukeException { String[] parts = textInput.split(" ", 2); - if (parts.length == 1 || parts[1] == "") { + if (parts.length == 1 || parts[1].equals("")) { throw new DukeException("☹ OOPS!!! The description of find command cannot be empty."); } String keyword = "(.*)" + textInput.substring(5) + "(.*)"; @@ -56,51 +86,77 @@ public String find(String textInput) throws DukeException { return found ? result.trim() : "Sorry, there are no matching tasks :-("; } - public String todo(String textInput) throws DukeException { - String[] parts = textInput.split(" ", 2); - if (parts.length == 1 || parts[1] == "") { - throw new DukeException("☹ OOPS!!! The description of a todo cannot be empty."); - } - Task t = new Task.Todo(textInput.substring(5)); - taskList.add(t); - String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t, taskList.size()); - return output; - } + /** + * Takes in a user text input, processes it add a to-do task, and returns the response message + * + * @param textInput the input message from the user + * @return the response message to be printed + * @throws DukeException if the text input is invalid + */ + public String todo(String textInput) throws DukeException { + String[] parts = textInput.split(" ", 2); + if (parts.length == 1 || parts[1].equals("")) { + throw new DukeException("☹ OOPS!!! The description of a todo cannot be empty."); + } + Task t = new Task.Todo(textInput.substring(5)); + taskList.add(t); + return String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t, taskList.size()); + } - public String deadline(String textInput) { - String[] parts = textInput.split("/"); - Task t = new Task.Deadline(parts[0].substring(9), parts[1].substring(3)); - taskList.add(t); - String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t, taskList.size()); - return output; + /** + * Takes in a user text input, processes it add a deadline task, and returns the response message + * + * @param textInput the input message from the user + * @return the response message to be printed + */ + public String deadline(String textInput) { + String[] parts = textInput.split("/"); + Task t = new Task.Deadline(parts[0].substring(9), parts[1].substring(3)); + taskList.add(t); + return String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t, taskList.size()); } - public String event(String textInput) { - String[] parts = textInput.split("/"); - Task t = new Task.Event(parts[0].substring(6), parts[1].substring(5), parts[2].substring(3)); - taskList.add(t); - String output = String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t, taskList.size()); - return output; - } + /** + * Takes in a user text input, processes it add an event task, and returns the response message + * + * @param textInput the input message from the user + * @return the response message to be printed + */ + public String event(String textInput) { + String[] parts = textInput.split("/"); + Task t = new Task.Event(parts[0].substring(6), parts[1].substring(5), parts[2].substring(3)); + taskList.add(t); + return String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t, taskList.size()); + } - public String toWrite() { - int length = this.taskList.size(); - String result = ""; - for (int i = 0; i < length; i++) { - String item = taskList.get(i).toData(); - result += item + "\n"; - } - return result.trim(); - } + /** + * Processes the current TaskList object into a string formatted for txt storage + * + * @return the referenced TaskList object as a string formatted for txt storage + */ + public String toWrite() { + int length = this.taskList.size(); + String result = ""; + for (int i = 0; i < length; i++) { + String item = taskList.get(i).toData(); + result += item + "\n"; + } + return result.trim(); + } - @Override - public String toString() { - String result = ""; - for (int i = 0; i < taskList.size(); i++) { - String description = taskList.get(i).toString(); - String output = String.format("%d. %s", i + 1, description + "\n"); - result += output; + /** + * Returns the String representation of the referenced TaskList + * + * @return the String representation of the TaskList + */ + @Override + public String toString() { + String result = ""; + for (int i = 0; i < taskList.size(); i++) { + String description = taskList.get(i).toString(); + String output = String.format("%d. %s", i + 1, description + "\n"); + result += output; + } + return result.trim(); } - return result.trim(); - } } diff --git a/src/main/java/duke/Ui.java b/src/main/java/duke/Ui.java index de63bfbca2..671115e3e5 100644 --- a/src/main/java/duke/Ui.java +++ b/src/main/java/duke/Ui.java @@ -2,39 +2,66 @@ import java.util.Scanner; +/** + * Handles all interactions with the user + */ public class Ui { - private final String WELCOME_MESSAGE = "Hey Buddy, I'm Duke\nWhat can I do for you?"; - private final String GOODBYE_MESSAGE = "Goodbye friend. Hope to see you again soon!"; - private Scanner scanner; - - public Ui() { - this.scanner = new Scanner(System.in); - } - - public void welcomeUser() { - System.out.println(WELCOME_MESSAGE); - } - - public String readInput() { - System.out.println("=======ME======="); - String textInput = this.scanner.nextLine(); - return textInput; - } - - public void goodbyeUser() { - System.out.println("======DUKE======"); - System.out.println(GOODBYE_MESSAGE); - this.scanner.close(); - System.out.println("================"); - } - - public void listTasks(TaskList taskList) { - System.out.println("======DUKE======"); - System.out.println(taskList.toString()); - } - - public void printResponse(String response) { - System.out.println("======DUKE======"); - System.out.println(response); - } + private final String WELCOME_MESSAGE = "Hey Buddy, I'm Duke\nWhat can I do for you?"; + private final String GOODBYE_MESSAGE = "Goodbye friend. Hope to see you again soon!"; + private Scanner scanner; + + /** + * Creates a new UI object to interact with the user + */ + public Ui() { + this.scanner = new Scanner(System.in); + } + + /** + * Prints the welcome message to the user upon starting + */ + public void welcomeUser() { + System.out.println(WELCOME_MESSAGE); + } + + /** + * Reads the input from the user through the interface + * + * @return the String input from the user + */ + public String readInput() { + System.out.println("=======ME======="); + String textInput = this.scanner.nextLine(); + return textInput; + } + + /** + * Prints the goodbye message to the user upon termination + */ + public void goodbyeUser() { + System.out.println("======DUKE======"); + System.out.println(GOODBYE_MESSAGE); + this.scanner.close(); + System.out.println("================"); + } + + /** + * Prints all the tasks inside a TaskList object + * + * @param taskList the TaskList object to be listed to the interface + */ + public void listTasks(TaskList taskList) { + System.out.println("======DUKE======"); + System.out.println(taskList.toString()); + } + + /** + * Reads an input and prints it as a response + * + * @param response the response to be printed + */ + public void printResponse(String response) { + System.out.println("======DUKE======"); + System.out.println(response); + } } \ No newline at end of file From b2049d69a475d5efb607957bf6d788713f2156fe Mon Sep 17 00:00:00 2001 From: Shane Duggan <> Date: Thu, 16 Feb 2023 00:07:52 +0800 Subject: [PATCH 19/28] IMPROVE code quality --- src/main/java/duke/Duke.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 89ec93c27c..175af1a8b9 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -34,23 +34,18 @@ public void run() { if (this.parser.action.equals("bye")) { this.ui.goodbyeUser(); return; - } else if (this.parser.action.equals("list")) { this.ui.listTasks(tasks); continue; - } else if (this.parser.action.equals("delete")) { response = this.tasks.delete(textInput); this.storage.writeTxt(tasks); - } else if (this.parser.action.equals("mark")) { response = this.tasks.mark(textInput); this.storage.writeTxt(tasks); - } else if (this.parser.action.equals("unmark")) { response = this.tasks.unmark(textInput); this.storage.writeTxt(tasks); - } else if (this.parser.action.equals("find")) { try { response = this.tasks.find(textInput); @@ -59,7 +54,6 @@ public void run() { this.ui.printResponse(response); continue; } - } else if (this.parser.action.equals("todo")) { try { response = this.tasks.todo(textInput); @@ -69,15 +63,12 @@ public void run() { this.ui.printResponse(response); continue; } - } else if (this.parser.action.equals("deadline")) { response = this.tasks.deadline(textInput); this.storage.writeTxt(tasks); - } else if (this.parser.action.equals("event")) { response = this.tasks.event(textInput); this.storage.writeTxt(tasks); - } else { response = "☹ OOPS!!! I'm sorry, but I don't know what that means :-("; } From 5baab089c0bd422f33102079529a701406fbaad5 Mon Sep 17 00:00:00 2001 From: Shane Duggan <> Date: Thu, 16 Feb 2023 01:29:28 +0800 Subject: [PATCH 20/28] ADD Varargs where applicable --- data/duke.txt | 5 +++-- src/main/java/duke/Duke.java | 10 +++++++--- src/main/java/duke/TaskList.java | 20 ++++++++------------ 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/data/duke.txt b/data/duke.txt index ad7ca2c721..2392b17a93 100644 --- a/data/duke.txt +++ b/data/duke.txt @@ -1,5 +1,6 @@ -T|1|read book D|0|go to perth|2019-11-01 E|1|play touch|2019-11-01|2019-12-02 D|0|finish proj|2023-01-01 -E|0|book fair|2023-01-01|2023-01-02 \ No newline at end of file +E|1|book fair|2023-01-01|2023-01-02 +T|0|read book +D|0|do homework|2023-01-02 \ No newline at end of file diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 175af1a8b9..b1804098f8 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -48,7 +48,8 @@ public void run() { this.storage.writeTxt(tasks); } else if (this.parser.action.equals("find")) { try { - response = this.tasks.find(textInput); + String[] parts = textInput.split(" ", 2); + response = this.tasks.find(parts); } catch (DukeException e) { response = e.toString(); this.ui.printResponse(response); @@ -56,7 +57,8 @@ public void run() { } } else if (this.parser.action.equals("todo")) { try { - response = this.tasks.todo(textInput); + String[] parts = textInput.split(" ", 2); + response = this.tasks.todo(parts); this.storage.writeTxt(tasks); } catch (DukeException e) { response = e.toString(); @@ -64,9 +66,11 @@ public void run() { continue; } } else if (this.parser.action.equals("deadline")) { - response = this.tasks.deadline(textInput); + String[] parts = textInput.split("/"); + response = this.tasks.deadline(parts); this.storage.writeTxt(tasks); } else if (this.parser.action.equals("event")) { + String[] parts = textInput.split("/"); response = this.tasks.event(textInput); this.storage.writeTxt(tasks); } else { diff --git a/src/main/java/duke/TaskList.java b/src/main/java/duke/TaskList.java index fd36807ae2..9fb0729a23 100644 --- a/src/main/java/duke/TaskList.java +++ b/src/main/java/duke/TaskList.java @@ -61,16 +61,15 @@ public String unmark(String textInput) { /** * Takes in a user text input, processes it to find matching records, and returns the response message * - * @param textInput the input message from the user + * @param parts the input message from the user * @return the response message to be printed * @throws DukeException if no find keyword is given */ - public String find(String textInput) throws DukeException { - String[] parts = textInput.split(" ", 2); + public String find(String... parts) throws DukeException { if (parts.length == 1 || parts[1].equals("")) { throw new DukeException("☹ OOPS!!! The description of find command cannot be empty."); } - String keyword = "(.*)" + textInput.substring(5) + "(.*)"; + String keyword = "(.*)" + parts[1] + "(.*)"; String result = "Here are the matching tasks in your list:\n"; boolean found = false; int index = 1; @@ -89,16 +88,15 @@ public String find(String textInput) throws DukeException { /** * Takes in a user text input, processes it add a to-do task, and returns the response message * - * @param textInput the input message from the user + * @param parts the input message from the user * @return the response message to be printed * @throws DukeException if the text input is invalid */ - public String todo(String textInput) throws DukeException { - String[] parts = textInput.split(" ", 2); + public String todo(String... parts) throws DukeException { if (parts.length == 1 || parts[1].equals("")) { throw new DukeException("☹ OOPS!!! The description of a todo cannot be empty."); } - Task t = new Task.Todo(textInput.substring(5)); + Task t = new Task.Todo(parts[1].trim()); taskList.add(t); return String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t, taskList.size()); } @@ -109,8 +107,7 @@ public String todo(String textInput) throws DukeException { * @param textInput the input message from the user * @return the response message to be printed */ - public String deadline(String textInput) { - String[] parts = textInput.split("/"); + public String deadline(String... parts) { Task t = new Task.Deadline(parts[0].substring(9), parts[1].substring(3)); taskList.add(t); return String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t, taskList.size()); @@ -122,8 +119,7 @@ public String deadline(String textInput) { * @param textInput the input message from the user * @return the response message to be printed */ - public String event(String textInput) { - String[] parts = textInput.split("/"); + public String event(String... parts) { Task t = new Task.Event(parts[0].substring(6), parts[1].substring(5), parts[2].substring(3)); taskList.add(t); return String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t, taskList.size()); From cf661a8b66ed63a2111b51f428a0223f5294910f Mon Sep 17 00:00:00 2001 From: Shane Duggan <> Date: Thu, 16 Feb 2023 01:38:23 +0800 Subject: [PATCH 21/28] no message --- build.gradle | 5 + config/checkstyle/checkstyle.xml | 429 +++++++++++++++++++++++++++++ config/checkstyle/suppressions.xml | 10 + 3 files changed, 444 insertions(+) create mode 100644 config/checkstyle/checkstyle.xml create mode 100644 config/checkstyle/suppressions.xml diff --git a/build.gradle b/build.gradle index 8850b91970..79b39c0d58 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,5 @@ plugins { + id 'checkstyle' id 'java' } @@ -9,6 +10,10 @@ repositories { mavenCentral() } +checkstyle { + toolVersion = '10.2' +} + dependencies { testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0' testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.0' diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml new file mode 100644 index 0000000000..e8ee76467b --- /dev/null +++ b/config/checkstyle/checkstyle.xml @@ -0,0 +1,429 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml new file mode 100644 index 0000000000..135ea49ee0 --- /dev/null +++ b/config/checkstyle/suppressions.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file From f16ad85e4949d78d64a0dcd2de67e8a4f1cebd59 Mon Sep 17 00:00:00 2001 From: Shane Duggan <> Date: Thu, 16 Feb 2023 23:52:23 +0800 Subject: [PATCH 22/28] ADD GUI feature --- build.gradle | 46 +++++++-- data/duke.txt | 7 +- src/main/java/duke/DialogBox.java | 61 ++++++++++++ src/main/java/duke/Duke.java | 123 ++++++++++++------------ src/main/java/duke/Launcher.java | 12 +++ src/main/java/duke/Main.java | 31 ++++++ src/main/java/duke/MainWindow.java | 54 +++++++++++ src/main/java/duke/TaskList.java | 11 ++- src/main/java/duke/Ui.java | 58 +++-------- src/main/resources/css/style.css | 0 src/main/resources/images/Eve.jpeg | Bin 0 -> 11692 bytes src/main/resources/images/Walle.jpeg | Bin 0 -> 76626 bytes src/main/resources/view/DialogBox.fxml | 20 ++++ src/main/resources/view/MainWindow.fxml | 19 ++++ 14 files changed, 322 insertions(+), 120 deletions(-) create mode 100644 src/main/java/duke/DialogBox.java create mode 100644 src/main/java/duke/Launcher.java create mode 100644 src/main/java/duke/Main.java create mode 100644 src/main/java/duke/MainWindow.java create mode 100644 src/main/resources/css/style.css create mode 100644 src/main/resources/images/Eve.jpeg create mode 100644 src/main/resources/images/Walle.jpeg 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 79b39c0d58..040b81eb93 100644 --- a/build.gradle +++ b/build.gradle @@ -1,23 +1,40 @@ plugins { - id 'checkstyle' + id "com.github.johnrengelman.shadow" version "5.1.0" id 'java' + id 'application' + id 'org.javamodularity.moduleplugin' version '1.8.12' + id 'org.openjfx.javafxplugin' version '0.0.13' + id 'org.beryx.jlink' version '2.25.0' } -group 'org.example' +group 'com.example' version '1.0-SNAPSHOT' repositories { mavenCentral() } -checkstyle { - toolVersion = '10.2' +ext { + junitVersion = '5.9.1' } -dependencies { - testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0' - testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.0' +application { + mainClassName = "duke.Launcher" +} + +sourceCompatibility = '11' +targetCompatibility = '11' + +tasks.withType(JavaCompile) { + options.encoding = 'UTF-8' +} + +javafx { + version = '17.0.2' + modules = ['javafx.controls', 'javafx.fxml'] +} +dependencies { String javaFxVersion = '11' implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'win' @@ -32,8 +49,23 @@ dependencies { 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' + + testImplementation("org.junit.jupiter:junit-jupiter-api:${junitVersion}") + testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${junitVersion}") + } test { useJUnitPlatform() +} + +jlink { + imageZip = project.file("${buildDir}/distributions/app-${javafx.platform.classifier}.zip") + options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages'] + launcher { + name = 'app' + } +} +jlinkZip { + group = 'distribution' } \ No newline at end of file diff --git a/data/duke.txt b/data/duke.txt index 2392b17a93..c98d5a032b 100644 --- a/data/duke.txt +++ b/data/duke.txt @@ -1,6 +1,5 @@ -D|0|go to perth|2019-11-01 +D|1|go to perth|2019-11-01 E|1|play touch|2019-11-01|2019-12-02 -D|0|finish proj|2023-01-01 -E|1|book fair|2023-01-01|2023-01-02 T|0|read book -D|0|do homework|2023-01-02 \ No newline at end of file +T|1|finish book +E|0|do tasks|2023-01-01|2023-01-02 \ No newline at end of file diff --git a/src/main/java/duke/DialogBox.java b/src/main/java/duke/DialogBox.java new file mode 100644 index 0000000000..d183f8252b --- /dev/null +++ b/src/main/java/duke/DialogBox.java @@ -0,0 +1,61 @@ +package duke; + +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; + } +} \ No newline at end of file diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index b1804098f8..ae815ed82f 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -2,6 +2,7 @@ public class Duke { + private final String FILE_PATH = System.getProperty("user.dir") + "/data/duke.txt"; private final Ui ui; private final Storage storage; private final TaskList tasks; @@ -9,79 +10,77 @@ public class Duke { /** * Creates a Duke object that references storage from the desired file path - * - * @param filePath the file path to the storage txt file */ - public Duke(String filePath) { + public Duke() { this.ui = new Ui(); - this.storage = new Storage(filePath); + this.storage = new Storage(FILE_PATH); this.tasks = new TaskList(storage.load()); } /** - * Begins the Duke chat loop + * Gets the response from the Duke bot + * + * @param textInput the input from the user + * @return the response from Duke */ - public void run() { - - this.ui.welcomeUser(); - - while (true) { - String textInput = this.ui.readInput(); - String response; - this.parser = new Parser(); - this.parser.parse(textInput); - - if (this.parser.action.equals("bye")) { - this.ui.goodbyeUser(); - return; - } else if (this.parser.action.equals("list")) { - this.ui.listTasks(tasks); - continue; - } else if (this.parser.action.equals("delete")) { - response = this.tasks.delete(textInput); - this.storage.writeTxt(tasks); - } else if (this.parser.action.equals("mark")) { - response = this.tasks.mark(textInput); - this.storage.writeTxt(tasks); - } else if (this.parser.action.equals("unmark")) { - response = this.tasks.unmark(textInput); - this.storage.writeTxt(tasks); - } else if (this.parser.action.equals("find")) { - try { - String[] parts = textInput.split(" ", 2); - response = this.tasks.find(parts); - } catch (DukeException e) { - response = e.toString(); - this.ui.printResponse(response); - continue; - } - } else if (this.parser.action.equals("todo")) { - try { - String[] parts = textInput.split(" ", 2); - response = this.tasks.todo(parts); - this.storage.writeTxt(tasks); - } catch (DukeException e) { - response = e.toString(); - this.ui.printResponse(response); - continue; - } - } else if (this.parser.action.equals("deadline")) { - String[] parts = textInput.split("/"); - response = this.tasks.deadline(parts); - this.storage.writeTxt(tasks); - } else if (this.parser.action.equals("event")) { - String[] parts = textInput.split("/"); - response = this.tasks.event(textInput); + public String getResponse(String textInput) { + String response; + this.parser = new Parser(); + this.parser.parse(textInput); + + if (this.parser.action.equals("bye")) { + response = this.ui.goodbyeUser(); + + } else if (this.parser.action.equals("hi")) { + response = this.ui.welcomeUser(); + + } else if (this.parser.action.equals("list")) { + response = this.ui.listTasks(tasks); + + } else if (this.parser.action.equals("delete")) { + response = this.tasks.delete(textInput); + this.storage.writeTxt(tasks); + + } else if (this.parser.action.equals("mark")) { + response = this.tasks.mark(textInput); + this.storage.writeTxt(tasks); + + } else if (this.parser.action.equals("unmark")) { + response = this.tasks.unmark(textInput); + this.storage.writeTxt(tasks); + + } else if (this.parser.action.equals("find")) { + try { + String[] parts = textInput.split(" ", 2); + response = this.tasks.find(parts); + } catch (DukeException e) { + response = e.toString(); + } + + } else if (this.parser.action.equals("todo")) { + try { + String[] parts = textInput.split(" ", 2); + response = this.tasks.todo(parts); this.storage.writeTxt(tasks); - } else { - response = "☹ OOPS!!! I'm sorry, but I don't know what that means :-("; + } catch (DukeException e) { + response = e.toString(); } - this.ui.printResponse(response); + } else if (this.parser.action.equals("deadline")) { + String[] parts = textInput.split("/"); + response = this.tasks.deadline(parts); + this.storage.writeTxt(tasks); + + } else if (this.parser.action.equals("event")) { + String[] parts = textInput.split("/"); + response = this.tasks.event(parts); + this.storage.writeTxt(tasks); + + } else { + response = "☹ OOPS!!! I'm sorry, but I don't know what that means :-("; } - } - public static void main(String[] args) { - new Duke(System.getProperty("user.dir") + "/data/duke.txt").run(); + return response; } + } \ No newline at end of file diff --git a/src/main/java/duke/Launcher.java b/src/main/java/duke/Launcher.java new file mode 100644 index 0000000000..5483e63637 --- /dev/null +++ b/src/main/java/duke/Launcher.java @@ -0,0 +1,12 @@ +package duke; + +import javafx.application.Application; + +/** + * A launcher class to workaround classpath issues. + */ +public class Launcher { + public static void main(String[] args) { + Application.launch(Main.class, args); + } +} \ No newline at end of file diff --git a/src/main/java/duke/Main.java b/src/main/java/duke/Main.java new file mode 100644 index 0000000000..db593707b5 --- /dev/null +++ b/src/main/java/duke/Main.java @@ -0,0 +1,31 @@ +package duke; + +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; + +/** + * A GUI for Duke using FXML. + */ +public class Main extends Application { + + private Duke duke = new Duke(); + + @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/java/duke/MainWindow.java b/src/main/java/duke/MainWindow.java new file mode 100644 index 0000000000..499542b50f --- /dev/null +++ b/src/main/java/duke/MainWindow.java @@ -0,0 +1,54 @@ +package duke; + +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.TextField; +import javafx.scene.image.Image; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.VBox; +/** + * Controller for MainWindow. Provides the layout for the other controls. + */ +public class MainWindow extends AnchorPane { + @FXML + private ScrollPane scrollPane; + @FXML + private VBox dialogContainer; + @FXML + private TextField userInput; + @FXML + private Button sendButton; + + private Duke duke; + + private Image userImage = new Image(this.getClass().getResourceAsStream("/images/Walle.jpeg")); + private Image dukeImage = new Image(this.getClass().getResourceAsStream("/images/Eve.jpeg")); + + @FXML + public void initialize() { + scrollPane.vvalueProperty().bind(dialogContainer.heightProperty()); + dialogContainer.getChildren().addAll( + DialogBox.getDukeDialog("Hi im duke", dukeImage) + ); + } + + 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(); + } +} \ No newline at end of file diff --git a/src/main/java/duke/TaskList.java b/src/main/java/duke/TaskList.java index 9fb0729a23..027708527c 100644 --- a/src/main/java/duke/TaskList.java +++ b/src/main/java/duke/TaskList.java @@ -1,9 +1,14 @@ package duke; +//import javafx.application.Application; +//import javafx.scene.Scene; +//import javafx.scene.control.Label; +//import javafx.stage.Stage; + import java.util.ArrayList; /** - * A task list that handles operations from the user to manage their tasks and interact with the storage + * A task list that handles operations from the user to manage their tasks and interact with storage */ public class TaskList { private ArrayList taskList; @@ -104,7 +109,7 @@ public String todo(String... parts) throws DukeException { /** * Takes in a user text input, processes it add a deadline task, and returns the response message * - * @param textInput the input message from the user + * @param parts the input message from the user * @return the response message to be printed */ public String deadline(String... parts) { @@ -116,7 +121,7 @@ public String deadline(String... parts) { /** * Takes in a user text input, processes it add an event task, and returns the response message * - * @param textInput the input message from the user + * @param parts the input message from the user * @return the response message to be printed */ public String event(String... parts) { diff --git a/src/main/java/duke/Ui.java b/src/main/java/duke/Ui.java index 671115e3e5..dce5d5bad7 100644 --- a/src/main/java/duke/Ui.java +++ b/src/main/java/duke/Ui.java @@ -1,67 +1,37 @@ package duke; -import java.util.Scanner; - /** - * Handles all interactions with the user + * Handles interactions with the user */ public class Ui { private final String WELCOME_MESSAGE = "Hey Buddy, I'm Duke\nWhat can I do for you?"; private final String GOODBYE_MESSAGE = "Goodbye friend. Hope to see you again soon!"; - private Scanner scanner; - - /** - * Creates a new UI object to interact with the user - */ - public Ui() { - this.scanner = new Scanner(System.in); - } /** - * Prints the welcome message to the user upon starting - */ - public void welcomeUser() { - System.out.println(WELCOME_MESSAGE); - } - - /** - * Reads the input from the user through the interface + * Returns the welcome message to the user upon starting * - * @return the String input from the user + * @return the welcome message */ - public String readInput() { - System.out.println("=======ME======="); - String textInput = this.scanner.nextLine(); - return textInput; + public String welcomeUser() { + return WELCOME_MESSAGE; } /** - * Prints the goodbye message to the user upon termination - */ - public void goodbyeUser() { - System.out.println("======DUKE======"); - System.out.println(GOODBYE_MESSAGE); - this.scanner.close(); - System.out.println("================"); - } - - /** - * Prints all the tasks inside a TaskList object + * Returns the goodbye message to the user upon termination * - * @param taskList the TaskList object to be listed to the interface + * @return the goodbye message */ - public void listTasks(TaskList taskList) { - System.out.println("======DUKE======"); - System.out.println(taskList.toString()); + public String goodbyeUser() { + return GOODBYE_MESSAGE; } /** - * Reads an input and prints it as a response + * Returns all the tasks inside a TaskList object * - * @param response the response to be printed + * @param taskList the TaskList object to be listed to the interface + * @return the string representation of the TaskList object */ - public void printResponse(String response) { - System.out.println("======DUKE======"); - System.out.println(response); + public String listTasks(TaskList taskList) { + return taskList.toString(); } } \ No newline at end of file diff --git a/src/main/resources/css/style.css b/src/main/resources/css/style.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/main/resources/images/Eve.jpeg b/src/main/resources/images/Eve.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..f71d041c3e5f53e78f35b4ff1529a99deab9e2fb GIT binary patch literal 11692 zcmb7pbwF0l^6&v3y1TnO1?iS26R!LPF}HOFAW$F6rL^-}m18 z{rSyVp0mvC&d$!x&d%()pSfQFuoRyuJOf~0U;ugW0q*AkX#fENj{pxrK!8U;L_|PB z!9qbnMn=KIz(m6$#3Ldi#3LXeA*ZJ#A*CfFAfRHSqGe!YW??3#WanaM;-Y6_W_n-( zgNTTTf`o#Lf`ZFLLO{aw{|)z@05%fLIm`qc3=IH_4FiV_bKeb+0Wbg@C@m=OzW@UZ z2g-|x1X76~DgQ$Q02o+!ILQ4RfCdKxz+%B+ftXwMf4c%mvB=m|APP`MmPmLkAOAxG zLad@q$G1kOV7TZY$T9&^G5`Sim;xw+YWfS<-(DY|ycjY(verJ<{XG#QU8L%3ZvQjc z(%};z@lgVR;ih2#fP{bA!zLZ~4RB98D*qy>jW@71H{x!ZsNyIx&X}vLBM48Ml?eWp zg7Yuyhqs06u}R!!V-G@$KkkwJ6=u|Nvz#-oOU5-|!X^mhruv7C)Jp&vAX^Y6Q|LdTl)fDDY2z>X?Jed}wy^pm zy;9W2&u#D;Gi~ejQ;uJM+WPiSo3DIENYi(iTYTCr?fZA{_I~@BUioL|PF2G)K)M6| z;R*mq^l*b~yK7BrH|?j(@5F>Y=l>`;rDUAA@bP~xMzHKJFbR%z4z zmTyd=HFWjY@xmWU@e9GKjV0^f3CTzEcR9V3nLiHdOoFppw#9|BCvPWj^3Evz^?&_{ z*Iu?s{RI360v;Bh=eRZJ*zg{(?zJB1Z6C6ZcbZXEI$+RgiS^!Z-1#v@{AMLNC*&8^ ze|kMsD$orxK6}NWW?bpt6ejsnm@tN)Wi0a|j>(Pedt;EJpL}4@^CDMT^|=1pE1=z7 zi}%01(LAqihOEhG-wQ3NlufmZuIJ7yx;Jp>n;njGsK&a^y*QpbtKn-$o);6SuKnMR zD4u@zzY>*4<0K_kj1>?aUPcIq?F_f9wyCsLCE2PPO#eW#GtW-*|mO;%%%}WL+t> z<8we_oW$w%D35XShq=#;qTKAq{^k)kh}O>W<-VLXM|ZndyYoW--LI?;7>4y7y!q2m z>ne1gX(QbvT@-w9J9W!sN*vj2D-7-MBG2NlJ2Q@f zUe}%@TL9Qp0Pv5y$l_>&&A3`g3`^%*I~Z=WkDodzk6uzu_2tOom^4mGHUKBAxtTm7 zJAJurJXNnI_J^F>5=U#xFRrND>+CKcHl)z6CsvAj4fcqpZ zqtQM{Gv0u)Dt=5Tcw*?ZPRu%V=ENhiS@1mhtFcqq59NBk3E|2#>zu;Wh0ktMnMBUW zL9==fqQUicEgerxMK-8|jI{MMEMK;0>(gK;Kl#oZ1oc`nDgFGMJ(0{ zSTV=i#6#?O0F?J>Q&p{>qvlu&p%W+OE+;N&x`)zk81EV=S@(vdqJa zjR6Z#2UYq2Fp@A5fFu)6AQw&`H2@F$5(o#RP?17`^q!&Cv}G0S_by3@$7TfDoagC;1xtHT>lB$+!W~Ac|{? z69}wwI+oPnFbgT!DYeD)m(>`DUthzqKdRzElWdQgl)*(pVum!!&`EtS?JPqnXXT;h z0zhTqb5Q}XLEs3VU||D*02)>sd4wDZWl$DL5c&9{3Hb=BRT&R}gvkfcm|=6lm`cDt z2=)H}5BSnoAdJ&s*}axRqFz^{yRfG#!hikRr>WAemnsO!vp>^yEnH?p<2gE4HieC* z*;FmF-L7Hdc;Te-6aljVNzqMEK8vzllEpX@l4l8dLBZ2p?HGGvlPJOdVGh^H=pGg( z18%WAOkF2lbd4j;^rj8&=EWE1T3@g$;%b%CCZA2?D+!=aOe1!l1+6=U#bBufz14u` zm_P5S{Pbx)2iuU5u{xI@f-;$*ZW3iikJg@zEO`F4ZlK5RDP9qaO^2kO7(*hTzE+4N zcS-frDpjrZ&l)%wgwJ=kZ}_&BPS{R86aA*1W99m#=Bj$jF3B%YypV zLMAg)6J#n#y0_a$WbANZB?DguEla3{U)L*#3&({`d`tp+Z`FA8dnisrsq=Ef$(}#Prpis>+){gx}|5(k=A4l4WYJJye$oE?q%-#uq z$|$*jad@ga=fF-3Bnj($t!y*-tZ~p#;zf1ihls}F!N^~e zMl!Sc8nQ*5SxTDj#e=7oi9!moK4J3XWb3|8`dL*p_2Ct<2%;`ot-=GR1^iJZ^)-;5 zCv6la9~Lq+ST!dbSj$eONDU{4Y}dNX7)5aT&bigm>fwQgA@D`HD>3*__T zQ;ygNxRe!*o4<*Ngt=Xf`)J73qQH1e2_)n^rAkXnpZ~-!DBHS+fv=t>1!JZ8+qgnYU{1RDMDk{>Sk5W~4rX|by_xO(OV|K|u zV!mt$>7-3r-p;T{`Jxit{U{z*l-XDEF5Zes+ZiFf1NX!tBJ#$+8)sIF>0erl__S_R+4!f zr>%+MSNJaAZ8_qU8vANFEsK;oEie+~NmZ!n7Lh*`6{+<} z=-GP`cII+8iYJLI+9mz(DY&D+w`Nf%H^!^o9?xNFOcf@NP?6{>ar3{@!NP)P$p4B5 zN+$sU&k<^F^_MOIk4FdWgLJp>-sRDZG`bcc%^C*Smt6UI+qS%kA+5Ps`|jpz1;!@z>GfIunDbXgip5;c&*WNhm zM=<5KIBPg_mU-_v>)r$C(%0YHvX3x9*+jrI4hGDw5fNb#|DJ*mnxp21!=mDmP{*O+ zk~Dn##_WNq^>-ARfg>z`N0tvd?Ugft|_6oTQd%}o(twpl=Lc+5=Qqjq!g@=MB zEE#D|ADccl5J6fI{+!DX*znww&@IZbsl zsR7%=CL-)jZ)q;aRa$`YSlyoOwFk!YLt>E^MQhVv(HaJs#$fvG8sta3-V2+&KcaXJ zmWpwbeN^3Xfu-hV1eiVU8e~fi)E7^bY*z8B{y@zra^M?FNWCWwg{SM()S;XBD^<** z-qn@xRA2Oi8YR~9a1$g4?7c3NzVZbes-shExR(_e*@6$tb7iK_xe7XzLw2aubqGcV>91%HqgzgtF2dO_m)U#kiQA z6VUwGu>e@mbASK=uVfwp1{;f-TT;VR{Z$}UYz~)1O~=^k(My-Zznc_{@5HI^0rRgG zqgj|cm^<%pY;!~+Zq>xv`nt`Jg%{^tl{F(+hTwCo7#fpbImoF=@sGw@9z0=R;Q2L$ zQjFi7hU2jlg%%wCJUm!Zb~H|=yNAd$crg56JeBS%otREE_9w&YU0fVTDFgUMj@mRL z(-2%9_GZ-uwvR99ZoXRwp8U+sS~M1F+ust(P}j= zBuB&DJET!ItX-OA&GO@k=@X-Q)5|YOO1N}QI%xlE$l#E>;mbbe)zI8Ld~X>Ir1O7+nB zgJc>Uu?3OREFLk^SL`|2q?lLT#xM}nkn|;Ds#lpAcddK`LbMa< zhZN6|RJG7vHP#g-D94%mOCkq5FWhZI<;_V#Dot>u9$IPU#Kbh-vO1*;yq&;q z%@7t>B)1;ZV2{Spvxv~ac)wI0fJL1( zN`L$$Zo)1y`&C#RfskURS`keGuH{D0$P8VdfZ{x%*p4jxQ-8hwo$Y8s%68bvuVrcO3QP;^_}a<7)++VMd)g z_UZy8O=CVzN77gYJ041TprT!%d(leC!J=tq_oCac44IkXw&3aI3YgvlDB^1h;xAQh z1M8N%hX@<%kuu+P=539SwFFaizgO|1mARCSDBF-iDrAi1eojqI4Z(UZ!(6NAHYP^R zLq$c!RZWOTjUPH(&s~M zM;FqSgRN%X54*A;NxwzPA`hlU9hJf=mMR?(j1GLy18Y71X{e@^=x5J+gW>U`(lX4W&19&%MwYuyFh{@5EFzm8>pu?8g7scr|FBmOrq2LP0Q(|8o#QL%Xpn!x738vPl%wXQzh(XRF zgJ6&&#kK9^J4>^F7DaouITI3Un?ysRPvXt=zz-ius$gKV2G29_3wQppH>_*hCf$NC zb+6W}T^g2wl~|0%ama(zD8VdWuZZB7oS)=zqV@*|V(we`v59h25rlPf)b&TKcq7V! zL$hF&`G*#i;DpyEBk(gga8o)7AU8ijlNz91Vqty7*LV6=s$VX zG)km!UfMrxcRMPl|k*1Am#U3UtqXsXhvIuP~_`?a9_9=&tb3*n&S~ z*CP`T-NfrnrE_tx!7<20GPj?=S42g_YoG+v*bI)m`74JCU7RgQ77KrnBdxvuNwFCL z4BZvJI2>8J8cU?KYDnEEK2lmkMO=5>XtoU4XxyG|+^@Z-xZCje**XkSB?hm8HlNTBzB5+JfRHo7r*+;7>_Z`1VtN5wG-Z zf8Qpudmgf9(@Y-V5VxLtrRYk}<6hOG3a6beTivBO%H7x}uii`nf6T8C3(dd9lOI>4 z_-TMD8yN&C4tR4&<5spEW`$rGUa54LuJ7xBa-E0A9duVco7s2vR7!#Ag~_Ee6IXvT z>UfU9&ju`i7H+g>n8n?J-@2H22KnwfZZ&R!%z!zX3k#>_C}?s%mRzM59hM}-Jq64Z zsA5j@Z=c=+K(@)hUr2z5cpeJ^ws$WjO9kBW&4A45%eoB~&u$O#k)%y5LF29KKduE_V%u)s!K4{GUzfrme{ zc)JlCnk|MD1>Ot8fXERv*!O6b$LDv(hC*NU?tyF@01!DDr0POK8bX7fzWd%C@GhG9 z<~%?GMok194+iBHN1prll3w#+KOANQc$o;`f@mV2&mv=si(cW5bImVHkt|C)*K*|O;?P)INsrN#zxuZJ}8 zpGfo}iv@#GE^Y}bNsX7L9ghjuLk^4e`^U3>Yg;=pSWF}Pm%rR9kxGM$gUiXEapjb6 zr0hq+aWJzbPQ48&_j;C#*KiYlk~0(a8sQvE`Q=V!jXg{M&NKSwp64@x^^tUt;%_@K zE=ka^m)dZHQsXY0s_B%$>nTqWG_~O0VN}RK6|L&@ly9ZNeT5SeV>XTT^$j9|;oUDC znWb!dMpLi7F%sH=GgU4m@vSYeYFm9&28a4!aqT#>A9&`UR*JcV& zwcawxqtz$Hd-jY@jUVz8pNtIO=Jh25m>pW_jC$A@_`U??sT~`8_cBY-{U!fCVwPIM7UtPX(RBu#Iu-wOA3pbH-5cZqpt1azAR| zH|{x-uw={mj75Ql@BumL>rnTR%AeS54tqOoAHMl=;lY>HTeg=huIFzW?dvU%)jvhv z+x{fusNruS7ic7NQ(XnwG_EsH52O#RF3 zYSo`oL-;aYDz*I+L1oEBtupZQN<(k=Jl+vxGfPvz;wZ&Wmtm>BE^};Q*e z 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/images/Walle.jpeg b/src/main/resources/images/Walle.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..144603ec2c8dae0e797c20c81abc45ed6e604b67 GIT binary patch literal 76626 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 + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml new file mode 100644 index 0000000000..832f84382e --- /dev/null +++ b/src/main/resources/view/MainWindow.fxml @@ -0,0 +1,19 @@ + + + + + + + + + + + +