From 65f72a8d7407cfc1d4ded97e87a8cbbbe6d16d8b Mon Sep 17 00:00:00 2001 From: Jeffry Lum <22460123+j-lum@users.noreply.github.com> Date: Tue, 6 Aug 2019 15:24:53 +0800 Subject: [PATCH 01/84] Add support for Gradle workflow --- build.gradle | 16 +++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 55190 bytes gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 172 +++++++++++++++++++++++ gradlew.bat | 84 +++++++++++ settings.gradle | 1 + 6 files changed, 278 insertions(+) create mode 100644 build.gradle create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000000..e5b8ce7e49 --- /dev/null +++ b/build.gradle @@ -0,0 +1,16 @@ +plugins { + id 'java' + id 'application' +} + +group 'seedu.duke' +version '0.1.0' + +repositories { + mavenCentral() +} + +application { + // Change this to your main class. + mainClassName = "seedu.duke.Duke" +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..87b738cbd051603d91cc39de6cb000dd98fe6b02 GIT binary patch literal 55190 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 z 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 \(.*\)$'` + 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"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; 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=$((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" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000000..6d57edc706 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@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 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" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000000..d1e92fe5db --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'duke' From 0112efe4f745ecd1985e5362f85e8ddc5facb02c Mon Sep 17 00:00:00 2001 From: Jeffry Lum <22460123+j-lum@users.noreply.github.com> Date: Mon, 12 Aug 2019 18:09:24 +0800 Subject: [PATCH 02/84] Add sample checkstyle configuration Add toolVersion block in to Gradle code sample to prevent errors. --- config/checkstyle/checkstyle.xml | 257 +++++++++++++++++++++++++++++++ tutorials/gradleTutorial.md | 7 +- 2 files changed, 263 insertions(+), 1 deletion(-) create mode 100644 config/checkstyle/checkstyle.xml diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml new file mode 100644 index 0000000000..b1a57ba6c0 --- /dev/null +++ b/config/checkstyle/checkstyle.xml @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tutorials/gradleTutorial.md b/tutorials/gradleTutorial.md index d16b72179a..fd6b043bf7 100644 --- a/tutorials/gradleTutorial.md +++ b/tutorials/gradleTutorial.md @@ -74,11 +74,16 @@ plugins { id 'application' id 'checkstyle' } + +checkstyle { + toolVersion = '8.23' +} + // ... ``` Checkstyle expects configuration files for checkstyle to be in `./config/checkstyle/` by convention. -For example, you can copy [these files from se-edu/addressbook-level3](https://github.com/se-edu/addressbook-level3/blob/master/config/checkstyle/) to your project. +A sample checkstyle rule configuration is provided in the branch. The plugin adds a few _tasks_ to your project. Run `gradlew checkstyleMain checkstyleTest` to verify that you have set up Checkstyle properly (the command will check your main code and test code against the style rules). From cfd6da79bab287c74d4b7f5666e61e686674fb29 Mon Sep 17 00:00:00 2001 From: Jeffry Lum <22460123+j-lum@users.noreply.github.com> Date: Sun, 18 Aug 2019 23:25:53 +0800 Subject: [PATCH 03/84] Change file mode on `gradle` to be executable --- gradlew | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 gradlew diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 From a3ca5a4e3fe35013f5690cacd168b19f7370a013 Mon Sep 17 00:00:00 2001 From: Jeffry Lum <22460123+j-lum@users.noreply.github.com> Date: Wed, 21 Aug 2019 00:32:40 +0800 Subject: [PATCH 04/84] Add configuration for console applications Gradle defaults to an empty stdin which results in runtime exceptions when attempting to read from `System.in`. Let's add some sensible defaults for students who may still need to work with the standard input stream. --- build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build.gradle b/build.gradle index e5b8ce7e49..ce97c7ba2e 100644 --- a/build.gradle +++ b/build.gradle @@ -14,3 +14,7 @@ application { // Change this to your main class. mainClassName = "seedu.duke.Duke" } + +run { + standardInput = System.in +} \ No newline at end of file From 2327b2af7a1d14d152a65d1b51642479d9eea923 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Thu, 29 Aug 2019 20:48:25 +0800 Subject: [PATCH 05/84] complete Level-1 --- src/main/java/Duke.java | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 5d313334cc..9c89740ef6 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,3 +1,5 @@ +import java.util.Scanner; + public class Duke { public static void main(String[] args) { String logo = " ____ _ \n" @@ -6,5 +8,38 @@ public static void main(String[] args) { + "| |_| | |_| | < __/\n" + "|____/ \\__,_|_|\\_\\___|\n"; System.out.println("Hello from\n" + logo); + System.out.println("What can I do for you?"); // todo: replace with configurable message + read(); + } + + /** + * Reads input from the user and passes it to process(). + */ + public static void read() { + String inputString; // stores input from user + Scanner in = new Scanner(System.in); + + // continuously take in user input until terminated + while(true) { + inputString = in.nextLine(); + if (inputString.equals("bye")) { + break; + } + process(inputString); + } + + // say goodbye upon exit + System.out.println("Bye. Hope to see you again soon!"); + } + + /** + * Creates the given input string. + * For Level-1, simply echoes the string. + * + * @param input input string given by user. + */ + public static void process(String input) { + // print given input to console + System.out.println(input); } } From 791010a429b35f1e9c39a83bcc9cc5c9ae789149 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Thu, 29 Aug 2019 23:20:17 +0800 Subject: [PATCH 06/84] add to process method, create DukeBot and TaskList classes --- src/main/java/Duke.java | 29 +++++++++++++++++++++-------- src/main/java/DukeBot.java | 6 ++++++ src/main/java/TaskList.java | 20 ++++++++++++++++++++ 3 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 src/main/java/DukeBot.java create mode 100644 src/main/java/TaskList.java diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 9c89740ef6..90afad6386 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,6 +1,9 @@ import java.util.Scanner; public class Duke { + private boolean isOngoing; + private TaskList taskList; + public static void main(String[] args) { String logo = " ____ _ \n" + "| _ \\ _ _| | _____ \n" @@ -15,16 +18,16 @@ public static void main(String[] args) { /** * Reads input from the user and passes it to process(). */ - public static void read() { + private void read() { String inputString; // stores input from user Scanner in = new Scanner(System.in); + this.isOngoing = true; + this.taskList = new TaskList(); + // continuously take in user input until terminated - while(true) { + while(isOngoing) { inputString = in.nextLine(); - if (inputString.equals("bye")) { - break; - } process(inputString); } @@ -38,8 +41,18 @@ public static void read() { * * @param input input string given by user. */ - public static void process(String input) { - // print given input to console - System.out.println(input); + private void process(String input) { + // terminate if "bye" + if (input.equals("bye")) { + this.isOngoing = false; + } + + // print list if "list" + if (input.equals("list")) { + this.taskList.printList(); + } + + // add to list otherwise + this.taskList.addToList(input); } } diff --git a/src/main/java/DukeBot.java b/src/main/java/DukeBot.java new file mode 100644 index 0000000000..82c4ad3800 --- /dev/null +++ b/src/main/java/DukeBot.java @@ -0,0 +1,6 @@ +public class DukeBot { + private TaskList taskList = new TaskList(); + + public DukeBot() { + } +} diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java new file mode 100644 index 0000000000..c3cf7dfedc --- /dev/null +++ b/src/main/java/TaskList.java @@ -0,0 +1,20 @@ +import java.util.ArrayList; +import java.util.Iterator; + +public class TaskList { + private ArrayList tasks = new ArrayList<>(); + + public void addToList(String taskDescription) { + tasks.add(taskDescription); + } + + public void printList() { + int i = 1; + for (Iterator iterator = this.tasks.iterator(); iterator.hasNext(); ) { + String s = iterator.next(); + System.out.println(i + ". " + s); + i++; + } + + } +} From 070f7e594502b634776c54de7cd74acea9840ea2 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Thu, 29 Aug 2019 23:28:30 +0800 Subject: [PATCH 07/84] encapsulate logic in DukeBot class, implement Level-2 --- src/main/java/Duke.java | 54 ++--------------------------------- src/main/java/DukeBot.java | 56 ++++++++++++++++++++++++++++++++++++- src/main/java/TaskList.java | 2 +- 3 files changed, 59 insertions(+), 53 deletions(-) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 90afad6386..cffbf21120 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,58 +1,10 @@ import java.util.Scanner; public class Duke { - private boolean isOngoing; - private TaskList taskList; + private static DukeBot dukeBot; public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); - System.out.println("What can I do for you?"); // todo: replace with configurable message - read(); - } - - /** - * Reads input from the user and passes it to process(). - */ - private void read() { - String inputString; // stores input from user - Scanner in = new Scanner(System.in); - - this.isOngoing = true; - this.taskList = new TaskList(); - - // continuously take in user input until terminated - while(isOngoing) { - inputString = in.nextLine(); - process(inputString); - } - - // say goodbye upon exit - System.out.println("Bye. Hope to see you again soon!"); - } - - /** - * Creates the given input string. - * For Level-1, simply echoes the string. - * - * @param input input string given by user. - */ - private void process(String input) { - // terminate if "bye" - if (input.equals("bye")) { - this.isOngoing = false; - } - - // print list if "list" - if (input.equals("list")) { - this.taskList.printList(); - } - - // add to list otherwise - this.taskList.addToList(input); + dukeBot = new DukeBot(); + dukeBot.initialise(); } } diff --git a/src/main/java/DukeBot.java b/src/main/java/DukeBot.java index 82c4ad3800..7073b0c9aa 100644 --- a/src/main/java/DukeBot.java +++ b/src/main/java/DukeBot.java @@ -1,6 +1,60 @@ +import java.util.Scanner; + public class DukeBot { private TaskList taskList = new TaskList(); + private Boolean isOngoing; + + /** + * Starts DukeBot and prints welcome message. + */ + + public void initialise() { + String logo = " ____ _ \n" + + "| _ \\ _ _| | _____ \n" + + "| | | | | | | |/ / _ \\\n" + + "| |_| | |_| | < __/\n" + + "|____/ \\__,_|_|\\_\\___|\n"; + System.out.println("Hello from\n" + logo); + System.out.println("What can I do for you?"); // todo: replace with configurable message + run(); + } + + /** + * Reads input from the user and passes it to process(). + */ + private void run() { + String inputString; // stores input from user + Scanner in = new Scanner(System.in); + + this.isOngoing = true; + this.taskList = new TaskList(); + + // continuously take in user input until terminated + while(isOngoing) { + inputString = in.nextLine(); + process(inputString); + } + + // say goodbye upon exit + System.out.println("Bye. Hope to see you again soon!"); + } - public DukeBot() { + /** + * Creates the given input string. + * For Level-1, simply echoes the string. + * + * @param input input string given by user. + */ + private void process(String input) { + if (input.equals("bye")) { + // terminate if "bye" + this.isOngoing = false; + } else if (input.equals("list")) { + // print list if "list" + this.taskList.printList(); + } else { + // add to list otherwise + this.taskList.addToList(input); + } } } diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index c3cf7dfedc..6d88187a35 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -6,6 +6,7 @@ public class TaskList { public void addToList(String taskDescription) { tasks.add(taskDescription); + System.out.println("added: " + taskDescription); } public void printList() { @@ -15,6 +16,5 @@ public void printList() { System.out.println(i + ". " + s); i++; } - } } From d4970401cddc501c27ed541a12a06b07a0ee0c27 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Thu, 29 Aug 2019 23:47:49 +0800 Subject: [PATCH 08/84] add Task class, implement Level-3 --- src/main/java/DukeBot.java | 3 +++ src/main/java/Task.java | 24 ++++++++++++++++++++++++ src/main/java/TaskList.java | 12 ++++++++---- 3 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 src/main/java/Task.java diff --git a/src/main/java/DukeBot.java b/src/main/java/DukeBot.java index 7073b0c9aa..02af5539a7 100644 --- a/src/main/java/DukeBot.java +++ b/src/main/java/DukeBot.java @@ -52,6 +52,9 @@ private void process(String input) { } else if (input.equals("list")) { // print list if "list" this.taskList.printList(); + } else if (input.startsWith("done")) { + int taskId = Integer.parseInt(input.substring(5)); + this.taskList.getTask(taskId).markAsDone(); } else { // add to list otherwise this.taskList.addToList(input); diff --git a/src/main/java/Task.java b/src/main/java/Task.java new file mode 100644 index 0000000000..b94b640380 --- /dev/null +++ b/src/main/java/Task.java @@ -0,0 +1,24 @@ +public class Task { + private String description; + private Boolean isDone; + + public Task(String description) { + this.description = description; + this.isDone = false; + } + + public String printTask() { + String taskString = "[" + this.getStatusIcon() + "] " + this.description; + return taskString; + } + + public String getStatusIcon() { + return (isDone ? "\u2713" : "\u2718"); // return tick or X symbols + } + + public void markAsDone() { + this.isDone = true; + System.out.println("Nice! I've marked this task as done:"); + System.out.println(this.printTask()); + } +} diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index 6d88187a35..bdee637faa 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -2,19 +2,23 @@ import java.util.Iterator; public class TaskList { - private ArrayList tasks = new ArrayList<>(); + private ArrayList tasks = new ArrayList<>(); public void addToList(String taskDescription) { - tasks.add(taskDescription); + tasks.add(new Task(taskDescription)); System.out.println("added: " + taskDescription); } public void printList() { int i = 1; - for (Iterator iterator = this.tasks.iterator(); iterator.hasNext(); ) { - String s = iterator.next(); + for (Iterator iterator = this.tasks.iterator(); iterator.hasNext(); ) { + String s = iterator.next().printTask(); System.out.println(i + ". " + s); i++; } } + + public Task getTask(int taskIndex) { + return tasks.get(taskIndex - 1); + } } From 17493be6e157aa39ba71762a5ccfe94efc606063 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Fri, 30 Aug 2019 00:17:45 +0800 Subject: [PATCH 09/84] add TaskType enum, welcomeMessage, and minor changes to comments --- src/main/java/Deadline.java | 15 +++++++++++++++ src/main/java/DukeBot.java | 14 ++++++++------ src/main/java/Event.java | 14 ++++++++++++++ src/main/java/Task.java | 11 +++++++---- src/main/java/TaskList.java | 21 +++++++++++++++++++-- src/main/java/Todo.java | 6 ++++++ 6 files changed, 69 insertions(+), 12 deletions(-) create mode 100644 src/main/java/Deadline.java create mode 100644 src/main/java/Event.java create mode 100644 src/main/java/Todo.java diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java new file mode 100644 index 0000000000..20c5dbc4dd --- /dev/null +++ b/src/main/java/Deadline.java @@ -0,0 +1,15 @@ +public class Deadline extends Task { + private String by; + + public Deadline(String description, String by) { + super(description); + this.by = by; + this.type = "D"; + + } + + @Override + public String toString() { + return super.toString() + "(by: " + by + ")"; + } +} diff --git a/src/main/java/DukeBot.java b/src/main/java/DukeBot.java index 02af5539a7..b1c06b1c7e 100644 --- a/src/main/java/DukeBot.java +++ b/src/main/java/DukeBot.java @@ -3,6 +3,7 @@ public class DukeBot { private TaskList taskList = new TaskList(); private Boolean isOngoing; + private String welcomeMessage = "What can I do for you?"; /** * Starts DukeBot and prints welcome message. @@ -15,7 +16,7 @@ public void initialise() { + "| |_| | |_| | < __/\n" + "|____/ \\__,_|_|\\_\\___|\n"; System.out.println("Hello from\n" + logo); - System.out.println("What can I do for you?"); // todo: replace with configurable message + System.out.println(welcomeMessage); run(); } @@ -41,22 +42,23 @@ private void run() { /** * Creates the given input string. - * For Level-1, simply echoes the string. * * @param input input string given by user. */ private void process(String input) { + // todo: extract list and done into TaskList class if (input.equals("bye")) { - // terminate if "bye" + // if "bye", terminate this.isOngoing = false; } else if (input.equals("list")) { - // print list if "list" + // if "list", print list this.taskList.printList(); } else if (input.startsWith("done")) { - int taskId = Integer.parseInt(input.substring(5)); + String s = input.substring(5); // extract the task ID entered by user + int taskId = Integer.parseInt(s); this.taskList.getTask(taskId).markAsDone(); } else { - // add to list otherwise + // otherwise, add to list this.taskList.addToList(input); } } diff --git a/src/main/java/Event.java b/src/main/java/Event.java new file mode 100644 index 0000000000..118f450317 --- /dev/null +++ b/src/main/java/Event.java @@ -0,0 +1,14 @@ +public class Event extends Task { + private String at; + + public Event(String description, String when) { + super(description); + this.at = at; + this.type = "E"; + } + + @Override + public String toString() { + return super.toString() + "(at: " + at + ")"; + } +} diff --git a/src/main/java/Task.java b/src/main/java/Task.java index b94b640380..efe34e5737 100644 --- a/src/main/java/Task.java +++ b/src/main/java/Task.java @@ -1,15 +1,18 @@ public class Task { private String description; private Boolean isDone; + protected String type; public Task(String description) { this.description = description; this.isDone = false; } - public String printTask() { - String taskString = "[" + this.getStatusIcon() + "] " + this.description; - return taskString; + @Override + public String toString() { + String type = "[" + this.type + "] "; + String status = "[" + this.getStatusIcon() + "] "; + return type + status + this.description; } public String getStatusIcon() { @@ -19,6 +22,6 @@ public String getStatusIcon() { public void markAsDone() { this.isDone = true; System.out.println("Nice! I've marked this task as done:"); - System.out.println(this.printTask()); + System.out.println(this.toString()); } } diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index bdee637faa..8e558646e8 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -4,7 +4,24 @@ public class TaskList { private ArrayList tasks = new ArrayList<>(); - public void addToList(String taskDescription) { + public enum TaskType { + DEADLINE, + EVENT, + TODO + } + + public void addToList(String input) { + // determine type of task + TaskType taskType; + if (input.startsWith("todo")) { + taskType = TaskType.TODO; + } else if (input.startsWith("deadline")) { + taskType = TaskType.DEADLINE; + } else if (input.startsWith("event")) { + taskType = TaskType.EVENT; + } + + // todo: split description and other info tasks.add(new Task(taskDescription)); System.out.println("added: " + taskDescription); } @@ -12,7 +29,7 @@ public void addToList(String taskDescription) { public void printList() { int i = 1; for (Iterator iterator = this.tasks.iterator(); iterator.hasNext(); ) { - String s = iterator.next().printTask(); + String s = iterator.next().toString(); System.out.println(i + ". " + s); i++; } diff --git a/src/main/java/Todo.java b/src/main/java/Todo.java new file mode 100644 index 0000000000..ab637b86d7 --- /dev/null +++ b/src/main/java/Todo.java @@ -0,0 +1,6 @@ +public class Todo extends Task { + public Todo(String description) { + super(description); + this.type = "T"; + } +} From f84bf5334b600b4dab526aba4c7302dc7ecc1ea5 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Fri, 30 Aug 2019 11:26:24 +0800 Subject: [PATCH 10/84] modify process() method (incomplete) --- src/main/java/DukeBot.java | 58 ++++++++++++++++++++++++++++--------- src/main/java/TaskList.java | 6 ++-- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/src/main/java/DukeBot.java b/src/main/java/DukeBot.java index b1c06b1c7e..b076873637 100644 --- a/src/main/java/DukeBot.java +++ b/src/main/java/DukeBot.java @@ -1,8 +1,11 @@ +import java.util.InputMismatchException; +import java.util.NoSuchElementException; import java.util.Scanner; +import java.util.regex.PatternSyntaxException; public class DukeBot { + private Scanner in; private TaskList taskList = new TaskList(); - private Boolean isOngoing; private String welcomeMessage = "What can I do for you?"; /** @@ -17,6 +20,7 @@ public void initialise() { + "|____/ \\__,_|_|\\_\\___|\n"; System.out.println("Hello from\n" + logo); System.out.println(welcomeMessage); + in = new Scanner(System.in); run(); } @@ -25,14 +29,18 @@ public void initialise() { */ private void run() { String inputString; // stores input from user - Scanner in = new Scanner(System.in); - this.isOngoing = true; this.taskList = new TaskList(); // continuously take in user input until terminated - while(isOngoing) { - inputString = in.nextLine(); + while (in.hasNextLine()) { + inputString = in.next(); + if (inputString.equals("bye")) { + // if "bye", terminate + // this would terminate if the user enters a line beginning with "bye" + // todo: check if this is expected behaviour? + break; + } process(inputString); } @@ -47,16 +55,40 @@ private void run() { */ private void process(String input) { // todo: extract list and done into TaskList class - if (input.equals("bye")) { - // if "bye", terminate - this.isOngoing = false; - } else if (input.equals("list")) { + if (input.equals("list")) { // if "list", print list this.taskList.printList(); - } else if (input.startsWith("done")) { - String s = input.substring(5); // extract the task ID entered by user - int taskId = Integer.parseInt(s); - this.taskList.getTask(taskId).markAsDone(); + } else if (input.equals("done")) { + try { + int taskId = in.nextInt(); // extract the task ID entered by user + this.taskList.getTask(taskId).markAsDone(); // mark task as done + } catch (InputMismatchException e) { + // user input after "done" is not an int + + } catch (NoSuchElementException e) { + // user input after "done" is blank + + } + } else if (input.equals("todo")) { + // get the rest of the line + String remainingInput; + String taskDescription; + String taskDeadline; + try { + remainingInput = in.nextLine(); + } catch (NoSuchElementException e) { + // user input after type of task is blank + } finally { + try { + // separate the remaining input + String[] remainingInputArray = remainingInput.split("/by"); + } catch (PatternSyntaxException e) { + + } + // what's with these nested try blocks??? fix it pls :( + // how to implement checks for different task types without repeating code? + } + } else { // otherwise, add to list this.taskList.addToList(input); diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index 8e558646e8..261305ea63 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -2,6 +2,7 @@ import java.util.Iterator; public class TaskList { + private ArrayList tasks = new ArrayList<>(); public enum TaskType { @@ -20,7 +21,7 @@ public void addToList(String input) { } else if (input.startsWith("event")) { taskType = TaskType.EVENT; } - + // todo: how to create corresponding subclass object based on enum? // todo: split description and other info tasks.add(new Task(taskDescription)); System.out.println("added: " + taskDescription); @@ -28,10 +29,9 @@ public void addToList(String input) { public void printList() { int i = 1; - for (Iterator iterator = this.tasks.iterator(); iterator.hasNext(); ) { + for (Iterator iterator = this.tasks.iterator(); iterator.hasNext(); i++) { String s = iterator.next().toString(); System.out.println(i + ". " + s); - i++; } } From 6bb6adf6370773aea2f2c26f92ab0261d0a68ac7 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Mon, 2 Sep 2019 10:47:53 +0800 Subject: [PATCH 11/84] implement Level-4, Level-5 and A-Exceptions --- src/main/java/DukeBot.java | 64 ++++----------------- src/main/java/Event.java | 2 +- src/main/java/TaskList.java | 111 +++++++++++++++++++++++++++++++----- 3 files changed, 108 insertions(+), 69 deletions(-) diff --git a/src/main/java/DukeBot.java b/src/main/java/DukeBot.java index b076873637..61dad8fe04 100644 --- a/src/main/java/DukeBot.java +++ b/src/main/java/DukeBot.java @@ -1,12 +1,11 @@ import java.util.InputMismatchException; import java.util.NoSuchElementException; import java.util.Scanner; -import java.util.regex.PatternSyntaxException; public class DukeBot { private Scanner in; private TaskList taskList = new TaskList(); - private String welcomeMessage = "What can I do for you?"; + private static final String welcomeMessage = "What can I do for you?"; /** * Starts DukeBot and prints welcome message. @@ -28,70 +27,27 @@ public void initialise() { * Reads input from the user and passes it to process(). */ private void run() { - String inputString; // stores input from user + String input; // stores input from user this.taskList = new TaskList(); // continuously take in user input until terminated while (in.hasNextLine()) { - inputString = in.next(); - if (inputString.equals("bye")) { + input = in.nextLine(); + if (input.equals("bye")) { // if "bye", terminate - // this would terminate if the user enters a line beginning with "bye" - // todo: check if this is expected behaviour? + // todo: is there a way to combine this into processInput()? break; } - process(inputString); - } - - // say goodbye upon exit - System.out.println("Bye. Hope to see you again soon!"); - } - /** - * Creates the given input string. - * - * @param input input string given by user. - */ - private void process(String input) { - // todo: extract list and done into TaskList class - if (input.equals("list")) { - // if "list", print list - this.taskList.printList(); - } else if (input.equals("done")) { try { - int taskId = in.nextInt(); // extract the task ID entered by user - this.taskList.getTask(taskId).markAsDone(); // mark task as done + this.taskList.processInput(input); } catch (InputMismatchException e) { - // user input after "done" is not an int - - } catch (NoSuchElementException e) { - // user input after "done" is blank - - } - } else if (input.equals("todo")) { - // get the rest of the line - String remainingInput; - String taskDescription; - String taskDeadline; - try { - remainingInput = in.nextLine(); - } catch (NoSuchElementException e) { - // user input after type of task is blank - } finally { - try { - // separate the remaining input - String[] remainingInputArray = remainingInput.split("/by"); - } catch (PatternSyntaxException e) { - - } - // what's with these nested try blocks??? fix it pls :( - // how to implement checks for different task types without repeating code? + System.out.println("Sorry! I don't know what that means :("); } - - } else { - // otherwise, add to list - this.taskList.addToList(input); } + + // say goodbye upon exit + System.out.println("Bye. Hope to see you again soon!"); } } diff --git a/src/main/java/Event.java b/src/main/java/Event.java index 118f450317..8faca780b2 100644 --- a/src/main/java/Event.java +++ b/src/main/java/Event.java @@ -1,7 +1,7 @@ public class Event extends Task { private String at; - public Event(String description, String when) { + public Event(String description, String at) { super(description); this.at = at; this.type = "E"; diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index 261305ea63..b2f684d7f8 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -1,5 +1,8 @@ import java.util.ArrayList; +import java.util.InputMismatchException; import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Scanner; public class TaskList { @@ -11,20 +14,32 @@ public enum TaskType { TODO } - public void addToList(String input) { - // determine type of task - TaskType taskType; - if (input.startsWith("todo")) { - taskType = TaskType.TODO; - } else if (input.startsWith("deadline")) { - taskType = TaskType.DEADLINE; - } else if (input.startsWith("event")) { - taskType = TaskType.EVENT; + public void addToList(TaskType taskType, String description, String deadline) + throws IllegalArgumentException { + Task newTask = null; // task to be added + + // based on task type, create corresponding subclass object + switch (taskType) { + case DEADLINE: + newTask = new Deadline(description, deadline); + break; + case EVENT: + newTask = new Event(description, deadline); + break; + case TODO: + newTask = new Todo(description); + break; + default: + // this should not happen; invalid task type should be caught in caller method already + System.out.println("Something went wrong!"); + break; } - // todo: how to create corresponding subclass object based on enum? - // todo: split description and other info - tasks.add(new Task(taskDescription)); - System.out.println("added: " + taskDescription); + + // add newTask to taskList + tasks.add(newTask); + System.out.println("Okay! I've added: " + description + + ". Use list to see all your tasks!"); + // todo: description has trailing space due to using /at or /by as delimiter. how? } public void printList() { @@ -35,7 +50,75 @@ public void printList() { } } - public Task getTask(int taskIndex) { + public Task getTask(int taskIndex) throws IndexOutOfBoundsException { return tasks.get(taskIndex - 1); } + + /** + * Processes the given input string. + * + * @param input input string given by user. + */ + public void processInput(String input) throws InputMismatchException { + Scanner inputReader = new Scanner(input); + String command = inputReader.next(); + String description; + String deadline; + + switch (command) { + case "list": + // if "list", print list + this.printList(); + break; + case "done": + try { + int taskId = inputReader.nextInt(); // extract the task ID entered by user + this.getTask(taskId).markAsDone(); // mark task as done + } catch (InputMismatchException e) { + // user input after "done" is not an int + System.out.println("Oops! You entered an invalid task ID!"); + } catch (NoSuchElementException e) { + // user input after "done" is blank + System.out.println("Oops! You did not enter a task ID!"); + } catch (IndexOutOfBoundsException e) { + // user input after "done" is an invalid task ID + System.out.println("Oops! You entered an invalid task ID!"); + } + break; + case "todo": + try { + description = inputReader.nextLine(); + deadline = "no deadline"; + this.addToList(TaskList.TaskType.TODO, description, deadline); + } catch (NoSuchElementException e) { + // user imput after task type is blank + System.out.println("Oops! You did not enter a description!"); + } + break; + case "event": + inputReader.useDelimiter("/at"); + try { + description = inputReader.next(); + deadline = inputReader.next(); + this.addToList(TaskList.TaskType.EVENT, description, deadline); + } catch (NoSuchElementException e) { + // user imput after task type is blank + System.out.println("Oops! You did not enter a description or deadline!"); + } + break; + case "deadline": + inputReader.useDelimiter("/by"); + try { + description = inputReader.next(); + deadline = inputReader.next(); + this.addToList(TaskList.TaskType.DEADLINE, description, deadline); + } catch (NoSuchElementException e) { + // user imput after task type is blank + System.out.println("Oops! You did not enter a description or deadline!"); + } + break; + default: + throw new InputMismatchException(); + } + } } From 6a07612c1b45c3bb4e939e7ebbd6f19d52b35b42 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Thu, 5 Sep 2019 22:05:09 +0800 Subject: [PATCH 12/84] implement Level-6, add deleteTask() method to TaskList class --- src/main/java/Deadline.java | 2 +- src/main/java/Event.java | 2 +- src/main/java/TaskList.java | 32 +++++++++++++++++++++++++++----- 3 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java index 20c5dbc4dd..508c81230c 100644 --- a/src/main/java/Deadline.java +++ b/src/main/java/Deadline.java @@ -10,6 +10,6 @@ public Deadline(String description, String by) { @Override public String toString() { - return super.toString() + "(by: " + by + ")"; + return super.toString() + " (by: " + by + ")"; } } diff --git a/src/main/java/Event.java b/src/main/java/Event.java index 8faca780b2..3602381f43 100644 --- a/src/main/java/Event.java +++ b/src/main/java/Event.java @@ -9,6 +9,6 @@ public Event(String description, String at) { @Override public String toString() { - return super.toString() + "(at: " + at + ")"; + return super.toString() + " (at: " + at + ")"; } } diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index b2f684d7f8..2f7813387d 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -54,6 +54,13 @@ public Task getTask(int taskIndex) throws IndexOutOfBoundsException { return tasks.get(taskIndex - 1); } + private void deleteTask(Task taskToDelete) { + String taskDescription = taskToDelete.toString(); + tasks.remove(taskToDelete); + System.out.println("Noted. I've removed this task: " + taskDescription); + System.out.println("Now you have " + tasks.size() + "items in this list."); + } + /** * Processes the given input string. * @@ -85,9 +92,24 @@ public void processInput(String input) throws InputMismatchException { System.out.println("Oops! You entered an invalid task ID!"); } break; + case "delete": + try { + int taskId = inputReader.nextInt(); // extract the task ID entered by user + this.deleteTask(getTask(taskId)); // mark task as done + } catch (InputMismatchException e) { + // user input after "done" is not an int + System.out.println("Oops! You entered an invalid task ID!"); + } catch (NoSuchElementException e) { + // user input after "done" is blank + System.out.println("Oops! You did not enter a task ID!"); + } catch (IndexOutOfBoundsException e) { + // user input after "done" is an invalid task ID + System.out.println("Oops! You entered an invalid task ID!"); + } + break; case "todo": try { - description = inputReader.nextLine(); + description = inputReader.nextLine().strip(); deadline = "no deadline"; this.addToList(TaskList.TaskType.TODO, description, deadline); } catch (NoSuchElementException e) { @@ -98,8 +120,8 @@ public void processInput(String input) throws InputMismatchException { case "event": inputReader.useDelimiter("/at"); try { - description = inputReader.next(); - deadline = inputReader.next(); + description = inputReader.next().strip(); + deadline = inputReader.next().strip(); this.addToList(TaskList.TaskType.EVENT, description, deadline); } catch (NoSuchElementException e) { // user imput after task type is blank @@ -109,8 +131,8 @@ public void processInput(String input) throws InputMismatchException { case "deadline": inputReader.useDelimiter("/by"); try { - description = inputReader.next(); - deadline = inputReader.next(); + description = inputReader.next().strip(); + deadline = inputReader.next().strip(); this.addToList(TaskList.TaskType.DEADLINE, description, deadline); } catch (NoSuchElementException e) { // user imput after task type is blank From 7e6ed3ae222641cd06e29e3673eec7f2e01a3e24 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Thu, 5 Sep 2019 22:47:15 +0800 Subject: [PATCH 13/84] merge branch 'gradle' --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index ce97c7ba2e..5ca4f90444 100644 --- a/build.gradle +++ b/build.gradle @@ -12,7 +12,7 @@ repositories { application { // Change this to your main class. - mainClassName = "seedu.duke.Duke" + mainClassName = "Duke" } run { From 070a1e28508043f2fd00c42528ad8fd9968cc00d Mon Sep 17 00:00:00 2001 From: nattanyz Date: Fri, 6 Sep 2019 00:01:18 +0800 Subject: [PATCH 14/84] start to implement gson for Level-7 --- build.gradle | 4 ++++ gradle/wrapper/gradle-wrapper.properties | 5 +++-- src/main/java/DukeBot.java | 1 + src/main/java/TaskList.java | 18 ++++++++++++++++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 5ca4f90444..7ece6faf24 100644 --- a/build.gradle +++ b/build.gradle @@ -17,4 +17,8 @@ application { run { standardInput = System.in +} + +dependencies { + implementation 'com.google.code.gson:gson:2.8.5' } \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4b7e1f3d38..b3338b157c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ +#Thu Sep 05 23:32:25 SGT 2019 +distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-all.zip distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-bin.zip -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/src/main/java/DukeBot.java b/src/main/java/DukeBot.java index 61dad8fe04..1b5049df0b 100644 --- a/src/main/java/DukeBot.java +++ b/src/main/java/DukeBot.java @@ -37,6 +37,7 @@ private void run() { if (input.equals("bye")) { // if "bye", terminate // todo: is there a way to combine this into processInput()? + this.taskList.saveToDisk(); break; } diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index 2f7813387d..b2307e0caf 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -3,6 +3,7 @@ import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Scanner; +import com.google.gson.Gson; public class TaskList { @@ -61,6 +62,23 @@ private void deleteTask(Task taskToDelete) { System.out.println("Now you have " + tasks.size() + "items in this list."); } + public void saveToDisk() { + // create gson to serialise taskList + Gson gson = new Gson(); + String taskListGson = gson.toJson(this); + + // write taskList to txt file + } + + public void readFromFile() { + // read json from file + // TODO + + // create type token to deal with Arraylist + // todo: why can't I use Type????? + Type taskListType = new TypeToken>(){}.getType(); + this.tasks = gson.fromJson(json, taskListType); + } /** * Processes the given input string. * From 148f51bde64bc4ca4c7cfcafac377aa654b8d9b1 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Fri, 6 Sep 2019 11:45:40 +0800 Subject: [PATCH 15/84] create Command, Parser, Storage, Ui classes and remove DukeBot class to implement A-MoreOOP --- src/main/java/Command.java | 11 ++++++++ src/main/java/Duke.java | 42 ++++++++++++++++++++++++++--- src/main/java/DukeBot.java | 54 ------------------------------------- src/main/java/Parser.java | 5 ++++ src/main/java/Storage.java | 41 ++++++++++++++++++++++++++++ src/main/java/Task.java | 1 + src/main/java/TaskList.java | 45 +++++++++++++++++++------------ src/main/java/Ui.java | 45 +++++++++++++++++++++++++++++++ 8 files changed, 170 insertions(+), 74 deletions(-) create mode 100644 src/main/java/Command.java delete mode 100644 src/main/java/DukeBot.java create mode 100644 src/main/java/Parser.java create mode 100644 src/main/java/Storage.java create mode 100644 src/main/java/Ui.java diff --git a/src/main/java/Command.java b/src/main/java/Command.java new file mode 100644 index 0000000000..4dd39e35a8 --- /dev/null +++ b/src/main/java/Command.java @@ -0,0 +1,11 @@ +public class Command { + private boolean isExit = false; + + public void execute(TaskList tasks, Ui ui, Storage storage) { + // implementation varies for each subclass of Command + } + + public boolean isExit() { + return this.isExit; + } +} diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index cffbf21120..fe5ad58cbf 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,10 +1,46 @@ import java.util.Scanner; public class Duke { - private static DukeBot dukeBot; +// private static DukeBot dukeBot; + private Storage storage; + private TaskList tasks; + private Ui ui; + + public Duke(String filePath) { + ui = new Ui(); + storage = new Storage(filePath); + try { + tasks = new TaskList(storage.load()); + } catch (Exception e) { + ui.showLoadingError(); + tasks = new TaskList(); + } + } + + public void run() { + ui.showWelcome(); + boolean isExit = false; + while (!isExit) { + try { + String fullCommand = ui.readCommand(); + ui.showLine(); // show the divider line ("_______") + Command c = Parser.parse(fullCommand); + c.execute(tasks, ui, storage); + isExit = c.isExit(); + } catch (Exception e) { + ui.showError(e.getMessage()); + } finally { + ui.showLine(); + } + } + } public static void main(String[] args) { - dukeBot = new DukeBot(); - dukeBot.initialise(); + new Duke("data/tasks.txt").run(); } + +// public static void main(String[] args) { +// dukeBot = new DukeBot(); +// dukeBot.initialise(); +// } } diff --git a/src/main/java/DukeBot.java b/src/main/java/DukeBot.java deleted file mode 100644 index 1b5049df0b..0000000000 --- a/src/main/java/DukeBot.java +++ /dev/null @@ -1,54 +0,0 @@ -import java.util.InputMismatchException; -import java.util.NoSuchElementException; -import java.util.Scanner; - -public class DukeBot { - private Scanner in; - private TaskList taskList = new TaskList(); - private static final String welcomeMessage = "What can I do for you?"; - - /** - * Starts DukeBot and prints welcome message. - */ - - public void initialise() { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); - System.out.println(welcomeMessage); - in = new Scanner(System.in); - run(); - } - - /** - * Reads input from the user and passes it to process(). - */ - private void run() { - String input; // stores input from user - - this.taskList = new TaskList(); - - // continuously take in user input until terminated - while (in.hasNextLine()) { - input = in.nextLine(); - if (input.equals("bye")) { - // if "bye", terminate - // todo: is there a way to combine this into processInput()? - this.taskList.saveToDisk(); - break; - } - - try { - this.taskList.processInput(input); - } catch (InputMismatchException e) { - System.out.println("Sorry! I don't know what that means :("); - } - } - - // say goodbye upon exit - System.out.println("Bye. Hope to see you again soon!"); - } -} diff --git a/src/main/java/Parser.java b/src/main/java/Parser.java new file mode 100644 index 0000000000..41750d9613 --- /dev/null +++ b/src/main/java/Parser.java @@ -0,0 +1,5 @@ +public class Parser { + + public static Command parse(String fullCommand) { + } +} diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java new file mode 100644 index 0000000000..1f2c13579c --- /dev/null +++ b/src/main/java/Storage.java @@ -0,0 +1,41 @@ +import java.io.BufferedReader; +import java.io.FileNotFoundException; +import java.io.FileReader; +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 tasks = new ArrayList(); + try { + // create buffered reader from file + BufferedReader br = new BufferedReader(new FileReader(this.filePath)); + + // load tasks from file + for (String line = br.readLine(); line != null; line = br.readLine()) { + tasks.add(loadTask(line)); + } + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + return tasks; + } + + private Task loadTask(String line) { + // use Task class's constructor from String + Task task = new Task(line); + return task; + } + + public void save(ArrayList tasks) { + // create json representation and save to given file + } +} diff --git a/src/main/java/Task.java b/src/main/java/Task.java index efe34e5737..b487e60de0 100644 --- a/src/main/java/Task.java +++ b/src/main/java/Task.java @@ -4,6 +4,7 @@ public class Task { protected String type; public Task(String description) { + // todo: modify constructor to create new task from String this.description = description; this.isDone = false; } diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index b2307e0caf..a9cd5efc91 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -1,3 +1,5 @@ +import com.google.gson.reflect.TypeToken; +import java.lang.reflect.Array; import java.util.ArrayList; import java.util.InputMismatchException; import java.util.Iterator; @@ -7,7 +9,15 @@ public class TaskList { - private ArrayList tasks = new ArrayList<>(); + private ArrayList tasks; + + public TaskList(ArrayList tasks) { + this.tasks = tasks; + } + + public TaskList() { + this.tasks = new ArrayList(); + } public enum TaskType { DEADLINE, @@ -62,23 +72,24 @@ private void deleteTask(Task taskToDelete) { System.out.println("Now you have " + tasks.size() + "items in this list."); } - public void saveToDisk() { - // create gson to serialise taskList - Gson gson = new Gson(); - String taskListGson = gson.toJson(this); +// public void saveToDisk() { +//// // create gson to serialise taskList +//// Gson gson = new Gson(); +//// String taskListGson = gson.toJson(this); +//// +//// // write taskList to txt file +//// } +//// +//// public void readFromFile() { +//// // read json from file +//// // TODO +//// +//// // create type token to deal with Arraylist +//// // todo: why can't I use Type????? +//// Type taskListType = new TypeToken>(){}.getType(); +//// this.tasks = Gson.fromJson(json, taskListType); +//// } - // write taskList to txt file - } - - public void readFromFile() { - // read json from file - // TODO - - // create type token to deal with Arraylist - // todo: why can't I use Type????? - Type taskListType = new TypeToken>(){}.getType(); - this.tasks = gson.fromJson(json, taskListType); - } /** * Processes the given input string. * diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java new file mode 100644 index 0000000000..92808f6f56 --- /dev/null +++ b/src/main/java/Ui.java @@ -0,0 +1,45 @@ +import java.util.Scanner; + +public class Ui { + private Scanner in; + private String loadingErrorMessage = "Oh no! Could not load tasks from file :("; + private String logo = " ____ _ \n" + + "| _ \\ _ _| | _____ \n" + + "| | | | | | | |/ / _ \\\n" + + "| |_| | |_| | < __/\n" + + "|____/ \\__,_|_|\\_\\___|\n"; + private String welcomeMessage = "Hello from \n" + logo + "What can I do for you?"; + private String line = "____________________________________________________________"; + private String filePath; + private String goodbyeMessage = "Your tasks have been saved to: " + filePath + "\n" + + "Bye. Hope to see you again soon!"; + + public Ui() { + this.in = new Scanner(System.in); + } + + public void showLoadingError() { + System.out.println(loadingErrorMessage); + } + + public void showWelcome() { + System.out.println(welcomeMessage); + } + + public String readCommand() { + return in.nextLine(); + } + + public void showLine() { + System.out.println(line); + } + + public void showError(String message) { + System.out.println(message); + } + + public void showGoodbye(String filePath) { + this.filePath = filePath; + System.out.println(goodbyeMessage); + } +} From 54e64587a3aa6ae38e60eace11b36059021edd42 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Fri, 6 Sep 2019 15:31:03 +0800 Subject: [PATCH 16/84] create and update classes for each type of Command with working implementation(s) of execute() from previous version. currently unable to run: encountered "could not find or load main class Duke" error :( --- src/main/java/AddDeadlineCommand.java | 36 +++++++++++++++++++++++++++ src/main/java/AddEventCommand.java | 36 +++++++++++++++++++++++++++ src/main/java/AddTaskCommand.java | 11 ++++++++ src/main/java/AddTodoCommand.java | 33 ++++++++++++++++++++++++ src/main/java/Command.java | 13 ++++------ src/main/java/DeleteCommand.java | 28 +++++++++++++++++++++ src/main/java/DoneCommand.java | 27 ++++++++++++++++++++ src/main/java/Duke.java | 11 ++------ src/main/java/ExitCommand.java | 13 ++++++++++ src/main/java/ListCommand.java | 7 ++++++ src/main/java/Parser.java | 31 ++++++++++++++++++++++- src/main/java/Storage.java | 20 +++++++++++++-- src/main/java/Task.java | 3 +++ src/main/java/TaskList.java | 10 +++++++- src/main/java/Ui.java | 7 ++---- 15 files changed, 260 insertions(+), 26 deletions(-) create mode 100644 src/main/java/AddDeadlineCommand.java create mode 100644 src/main/java/AddEventCommand.java create mode 100644 src/main/java/AddTaskCommand.java create mode 100644 src/main/java/AddTodoCommand.java create mode 100644 src/main/java/DeleteCommand.java create mode 100644 src/main/java/DoneCommand.java create mode 100644 src/main/java/ExitCommand.java create mode 100644 src/main/java/ListCommand.java diff --git a/src/main/java/AddDeadlineCommand.java b/src/main/java/AddDeadlineCommand.java new file mode 100644 index 0000000000..5b87f62639 --- /dev/null +++ b/src/main/java/AddDeadlineCommand.java @@ -0,0 +1,36 @@ +import java.util.NoSuchElementException; +import java.util.Scanner; + +public class AddDeadlineCommand extends AddTaskCommand { + Scanner s = new Scanner(restOfCommand); + + public AddDeadlineCommand(String restOfCommand) { + super(restOfCommand); + s.useDelimiter("/by"); + } + + @Override + public String getDescription() { + return this.s.next().strip(); + } + + @Override + public String getDeadline() { + return this.s.next().strip(); + } + + @Override + public Task createTask() { + return null; + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + try { + tasks.addToList(TaskList.TaskType.DEADLINE, getDescription(), getDeadline()); + } catch (NoSuchElementException e) { + // user imput after task type is blank + System.out.println("Oops! You did not enter a description or deadline!"); + } + } +} diff --git a/src/main/java/AddEventCommand.java b/src/main/java/AddEventCommand.java new file mode 100644 index 0000000000..608cfac2f0 --- /dev/null +++ b/src/main/java/AddEventCommand.java @@ -0,0 +1,36 @@ +import java.util.NoSuchElementException; +import java.util.Scanner; + +public class AddEventCommand extends AddTaskCommand { + Scanner s = new Scanner(restOfCommand); + + public AddEventCommand(String restOfCommand) { + super(restOfCommand); + s.useDelimiter("/at"); + } + + @Override + public String getDescription() { + return this.s.next().strip(); + } + + @Override + public String getDeadline() { + return this.s.next().strip(); + } + + @Override + public Task createTask() { + return null; + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + try { + tasks.addToList(TaskList.TaskType.EVENT, getDescription(), getDeadline()); + } catch (NoSuchElementException e) { + // user imput after task type is blank + System.out.println("Oops! You did not enter a description or deadline!"); + } + } +} diff --git a/src/main/java/AddTaskCommand.java b/src/main/java/AddTaskCommand.java new file mode 100644 index 0000000000..f1782ac298 --- /dev/null +++ b/src/main/java/AddTaskCommand.java @@ -0,0 +1,11 @@ +public abstract class AddTaskCommand implements Command { + String restOfCommand; + + public AddTaskCommand(String restOfCommand) { + this.restOfCommand = restOfCommand; + } + + abstract String getDescription(); + abstract String getDeadline(); + abstract Task createTask(); +} diff --git a/src/main/java/AddTodoCommand.java b/src/main/java/AddTodoCommand.java new file mode 100644 index 0000000000..9299c56381 --- /dev/null +++ b/src/main/java/AddTodoCommand.java @@ -0,0 +1,33 @@ +import java.util.NoSuchElementException; + +public class AddTodoCommand extends AddTaskCommand { + + public AddTodoCommand(String restOfCommand) { + super(restOfCommand); + } + + @Override + public String getDescription() { + return this.restOfCommand.strip(); + } + + @Override + public String getDeadline() { + return "no deadline"; + } + + @Override + public Task createTask() { + return null; + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + try { + tasks.addToList(TaskList.TaskType.TODO, getDescription(), getDeadline()); + } catch (NoSuchElementException e) { + // user imput after task type is blank + System.out.println("Oops! You did not enter a description!"); + } + } +} diff --git a/src/main/java/Command.java b/src/main/java/Command.java index 4dd39e35a8..fa5939a3a6 100644 --- a/src/main/java/Command.java +++ b/src/main/java/Command.java @@ -1,11 +1,8 @@ -public class Command { - private boolean isExit = false; +public interface Command { + void execute(TaskList tasks, Ui ui, Storage storage); + // implementation varies for each subclass of Command - public void execute(TaskList tasks, Ui ui, Storage storage) { - // implementation varies for each subclass of Command - } - - public boolean isExit() { - return this.isExit; + default boolean isExit() { + return false; } } diff --git a/src/main/java/DeleteCommand.java b/src/main/java/DeleteCommand.java new file mode 100644 index 0000000000..f28b4d3008 --- /dev/null +++ b/src/main/java/DeleteCommand.java @@ -0,0 +1,28 @@ +import java.util.InputMismatchException; +import java.util.NoSuchElementException; + +public class DeleteCommand implements Command { + private int taskId; + + public DeleteCommand(int taskId) { + super(); + this.taskId = taskId; + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + try { + Task task = tasks.getTask(taskId); + tasks.deleteTask(task); // mark task as done + } catch (InputMismatchException e) { + // user input after "done" is not an int + System.out.println("Oops! You entered an invalid task ID!"); + } catch (NoSuchElementException e) { + // user input after "done" is blank + System.out.println("Oops! You did not enter a task ID!"); + } catch (IndexOutOfBoundsException e) { + // user input after "done" is an invalid task ID + System.out.println("Oops! You entered an invalid task ID!"); + } + } +} diff --git a/src/main/java/DoneCommand.java b/src/main/java/DoneCommand.java new file mode 100644 index 0000000000..98f0c40e42 --- /dev/null +++ b/src/main/java/DoneCommand.java @@ -0,0 +1,27 @@ +import java.util.InputMismatchException; +import java.util.NoSuchElementException; + +public class DoneCommand implements Command { + private int taskId; + + public DoneCommand(int taskId) { + super(); + this.taskId = taskId; + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + try { + tasks.getTask(this.taskId).markAsDone(); // mark task as done + } catch (InputMismatchException e) { + // user input after "done" is not an int + System.out.println("Oops! You entered an invalid task ID!"); + } catch (NoSuchElementException e) { + // user input after "done" is blank + System.out.println("Oops! You did not enter a task ID!"); + } catch (IndexOutOfBoundsException e) { + // user input after "done" is an invalid task ID + System.out.println("Oops! You entered an invalid task ID!"); + } + } +} diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index fe5ad58cbf..e8e3677074 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,7 +1,4 @@ -import java.util.Scanner; - public class Duke { -// private static DukeBot dukeBot; private Storage storage; private TaskList tasks; private Ui ui; @@ -36,11 +33,7 @@ public void run() { } public static void main(String[] args) { - new Duke("data/tasks.txt").run(); + Duke duke = new Duke("data/tasks.txt"); + duke.run(); } - -// public static void main(String[] args) { -// dukeBot = new DukeBot(); -// dukeBot.initialise(); -// } } diff --git a/src/main/java/ExitCommand.java b/src/main/java/ExitCommand.java new file mode 100644 index 0000000000..aeff324118 --- /dev/null +++ b/src/main/java/ExitCommand.java @@ -0,0 +1,13 @@ +public class ExitCommand implements Command { + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + storage.save(tasks); + ui.showGoodbye(); + } + + @Override + public boolean isExit() { + return true; + } +} diff --git a/src/main/java/ListCommand.java b/src/main/java/ListCommand.java new file mode 100644 index 0000000000..90246d961b --- /dev/null +++ b/src/main/java/ListCommand.java @@ -0,0 +1,7 @@ +public class ListCommand implements Command { + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + tasks.printList(); + } +} diff --git a/src/main/java/Parser.java b/src/main/java/Parser.java index 41750d9613..dddb0b4e18 100644 --- a/src/main/java/Parser.java +++ b/src/main/java/Parser.java @@ -1,5 +1,34 @@ +import java.util.InputMismatchException; +import java.util.NoSuchElementException; +import java.util.Scanner; + public class Parser { - public static Command parse(String fullCommand) { + public static Command parse(String fullCommand) throws InputMismatchException { + Scanner commandReader = new Scanner(fullCommand); + String command = commandReader.next(); + + if (command == "bye") { + return new ExitCommand(); + } else if (command == "list") { + return new ListCommand(); + } else if (command == "done") { + int taskId = commandReader.nextInt(); // extract the task ID entered by user + return new DoneCommand(taskId); + } else if (command == "delete") { + int taskId = commandReader.nextInt(); + return new DeleteCommand(taskId); + } else if (command == "todo") { + String restOfCommand = commandReader.nextLine(); + return new AddTodoCommand(restOfCommand); + } else if (command == "event") { + String restOfCommand = commandReader.nextLine(); + return new AddEventCommand(restOfCommand); + } else if (command == "deadline") { + String restofCommand = commandReader.nextLine(); + return new AddDeadlineCommand(restofCommand); + } else { + throw new InputMismatchException(); + } } } diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java index 1f2c13579c..2cbcdf36d6 100644 --- a/src/main/java/Storage.java +++ b/src/main/java/Storage.java @@ -1,11 +1,15 @@ import java.io.BufferedReader; +import java.io.BufferedWriter; import java.io.FileNotFoundException; import java.io.FileReader; +import java.io.FileWriter; import java.io.IOException; +import java.io.PrintWriter; import java.util.ArrayList; public class Storage { private String filePath; + private String doneMessage = "Success! Your tasks have been saved to: "; // should be in Ui class? public Storage(String filePath) { this.filePath = filePath; @@ -17,7 +21,7 @@ public ArrayList load() { // create buffered reader from file BufferedReader br = new BufferedReader(new FileReader(this.filePath)); - // load tasks from file + // load tasks from file while file is not empty for (String line = br.readLine(); line != null; line = br.readLine()) { tasks.add(loadTask(line)); } @@ -35,7 +39,19 @@ private Task loadTask(String line) { return task; } - public void save(ArrayList tasks) { + public void save(TaskList tasks) { // create json representation and save to given file + try { + PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(this.filePath))); + + // for each task in tasks, create its string representation for storage + + // write string to file + + // print done + System.out.println(doneMessage + filePath); + } catch (IOException e) { + e.printStackTrace(); + } } } diff --git a/src/main/java/Task.java b/src/main/java/Task.java index b487e60de0..eace1b901a 100644 --- a/src/main/java/Task.java +++ b/src/main/java/Task.java @@ -25,4 +25,7 @@ public void markAsDone() { System.out.println("Nice! I've marked this task as done:"); System.out.println(this.toString()); } + +// public String printToFile() { +// } } diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index a9cd5efc91..851cd5c291 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -61,11 +61,19 @@ public void printList() { } } +// public String printToFile() { +// Task task; +// for (Iterator iterator = this.tasks.iterator(); iterator.hasNext(); task = iterator.next()) { +// String s = iterator.next().printToFile(); +// return s; +// } +// } + public Task getTask(int taskIndex) throws IndexOutOfBoundsException { return tasks.get(taskIndex - 1); } - private void deleteTask(Task taskToDelete) { + public void deleteTask(Task taskToDelete) { String taskDescription = taskToDelete.toString(); tasks.remove(taskToDelete); System.out.println("Noted. I've removed this task: " + taskDescription); diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java index 92808f6f56..b8b00aaa7f 100644 --- a/src/main/java/Ui.java +++ b/src/main/java/Ui.java @@ -10,9 +10,7 @@ public class Ui { + "|____/ \\__,_|_|\\_\\___|\n"; private String welcomeMessage = "Hello from \n" + logo + "What can I do for you?"; private String line = "____________________________________________________________"; - private String filePath; - private String goodbyeMessage = "Your tasks have been saved to: " + filePath + "\n" + - "Bye. Hope to see you again soon!"; + private String goodbyeMessage = "Bye. Hope to see you again soon!"; public Ui() { this.in = new Scanner(System.in); @@ -38,8 +36,7 @@ public void showError(String message) { System.out.println(message); } - public void showGoodbye(String filePath) { - this.filePath = filePath; + public void showGoodbye() { System.out.println(goodbyeMessage); } } From 8eafe915868f05ebf6e83340c96344a9fbccd02a Mon Sep 17 00:00:00 2001 From: nattanyz Date: Fri, 6 Sep 2019 16:31:02 +0800 Subject: [PATCH 17/84] something's wrong :( --- src/main/java/AddTodoCommand.java | 2 ++ src/main/java/Duke.java | 2 +- src/main/java/Parser.java | 5 +++++ src/main/java/TaskList.java | 8 ++++---- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/main/java/AddTodoCommand.java b/src/main/java/AddTodoCommand.java index 9299c56381..10fccf0f23 100644 --- a/src/main/java/AddTodoCommand.java +++ b/src/main/java/AddTodoCommand.java @@ -24,6 +24,8 @@ public Task createTask() { @Override public void execute(TaskList tasks, Ui ui, Storage storage) { try { + // debug + System.out.println("at execute of add todo"); tasks.addToList(TaskList.TaskType.TODO, getDescription(), getDeadline()); } catch (NoSuchElementException e) { // user imput after task type is blank diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index e8e3677074..88a525f8f3 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -25,7 +25,7 @@ public void run() { c.execute(tasks, ui, storage); isExit = c.isExit(); } catch (Exception e) { - ui.showError(e.getMessage()); + ui.showError("exception caught in run()"); } finally { ui.showLine(); } diff --git a/src/main/java/Parser.java b/src/main/java/Parser.java index dddb0b4e18..058daca89f 100644 --- a/src/main/java/Parser.java +++ b/src/main/java/Parser.java @@ -5,9 +5,14 @@ public class Parser { public static Command parse(String fullCommand) throws InputMismatchException { + // debug + System.out.println("at parse method"); Scanner commandReader = new Scanner(fullCommand); String command = commandReader.next(); + // debug + System.out.println("command = " + command); + if (command == "bye") { return new ExitCommand(); } else if (command == "list") { diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index 851cd5c291..40a5b7c443 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -1,11 +1,9 @@ -import com.google.gson.reflect.TypeToken; -import java.lang.reflect.Array; import java.util.ArrayList; import java.util.InputMismatchException; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Scanner; -import com.google.gson.Gson; +//import com.google.gson.Gson; public class TaskList { @@ -27,6 +25,9 @@ public enum TaskType { public void addToList(TaskType taskType, String description, String deadline) throws IllegalArgumentException { + // debug + System.out.println("at addToList method"); + Task newTask = null; // task to be added // based on task type, create corresponding subclass object @@ -50,7 +51,6 @@ public void addToList(TaskType taskType, String description, String deadline) tasks.add(newTask); System.out.println("Okay! I've added: " + description + ". Use list to see all your tasks!"); - // todo: description has trailing space due to using /at or /by as delimiter. how? } public void printList() { From 06492d252fbd45bbf979be8c1e60a61d4cd58c90 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Sun, 8 Sep 2019 18:53:34 +0800 Subject: [PATCH 18/84] remove no-longer-used processInput method in TaskList class, implement Level-9 (find), fix String comparison bug --- src/main/java/AddDeadlineCommand.java | 2 +- src/main/java/AddTaskCommand.java | 2 + src/main/java/Duke.java | 3 +- src/main/java/Parser.java | 23 +++--- src/main/java/Storage.java | 3 + src/main/java/TaskList.java | 113 ++++++-------------------- src/main/java/Ui.java | 5 ++ 7 files changed, 47 insertions(+), 104 deletions(-) diff --git a/src/main/java/AddDeadlineCommand.java b/src/main/java/AddDeadlineCommand.java index 5b87f62639..7d9c5de015 100644 --- a/src/main/java/AddDeadlineCommand.java +++ b/src/main/java/AddDeadlineCommand.java @@ -29,7 +29,7 @@ public void execute(TaskList tasks, Ui ui, Storage storage) { try { tasks.addToList(TaskList.TaskType.DEADLINE, getDescription(), getDeadline()); } catch (NoSuchElementException e) { - // user imput after task type is blank + // user input after task type is blank System.out.println("Oops! You did not enter a description or deadline!"); } } diff --git a/src/main/java/AddTaskCommand.java b/src/main/java/AddTaskCommand.java index f1782ac298..4b1113dc33 100644 --- a/src/main/java/AddTaskCommand.java +++ b/src/main/java/AddTaskCommand.java @@ -7,5 +7,7 @@ public AddTaskCommand(String restOfCommand) { abstract String getDescription(); abstract String getDeadline(); + + // to abstract out creating the task vs adding it to list abstract Task createTask(); } diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 88a525f8f3..8a77e89ed7 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -25,7 +25,8 @@ public void run() { c.execute(tasks, ui, storage); isExit = c.isExit(); } catch (Exception e) { - ui.showError("exception caught in run()"); + // temporary haxx + System.out.println(e); } finally { ui.showLine(); } diff --git a/src/main/java/Parser.java b/src/main/java/Parser.java index 058daca89f..64825a7b98 100644 --- a/src/main/java/Parser.java +++ b/src/main/java/Parser.java @@ -1,37 +1,34 @@ import java.util.InputMismatchException; -import java.util.NoSuchElementException; import java.util.Scanner; public class Parser { public static Command parse(String fullCommand) throws InputMismatchException { - // debug - System.out.println("at parse method"); Scanner commandReader = new Scanner(fullCommand); String command = commandReader.next(); - // debug - System.out.println("command = " + command); - - if (command == "bye") { + if (command.equals("bye")) { return new ExitCommand(); - } else if (command == "list") { + } else if (command.equals("list")) { return new ListCommand(); - } else if (command == "done") { + } else if (command.equals("done")) { int taskId = commandReader.nextInt(); // extract the task ID entered by user return new DoneCommand(taskId); - } else if (command == "delete") { + } else if (command.equals("delete")) { int taskId = commandReader.nextInt(); return new DeleteCommand(taskId); - } else if (command == "todo") { + } else if (command.equals("todo")) { String restOfCommand = commandReader.nextLine(); return new AddTodoCommand(restOfCommand); - } else if (command == "event") { + } else if (command.equals("event")) { String restOfCommand = commandReader.nextLine(); return new AddEventCommand(restOfCommand); - } else if (command == "deadline") { + } else if (command.equals("deadline")) { String restofCommand = commandReader.nextLine(); return new AddDeadlineCommand(restofCommand); + } else if (command.equals("find")) { + String keyword = commandReader.nextLine(); + return new FindCommand(keyword); } else { throw new InputMismatchException(); } diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java index 2cbcdf36d6..fb423d93e5 100644 --- a/src/main/java/Storage.java +++ b/src/main/java/Storage.java @@ -26,8 +26,10 @@ public ArrayList load() { tasks.add(loadTask(line)); } } catch (FileNotFoundException e) { + // temporary haxx e.printStackTrace(); } catch (IOException e) { + // temporary haxx e.printStackTrace(); } return tasks; @@ -51,6 +53,7 @@ public void save(TaskList tasks) { // print done System.out.println(doneMessage + filePath); } catch (IOException e) { + // temporary haxx e.printStackTrace(); } } diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index 40a5b7c443..38e2b91a16 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -1,8 +1,5 @@ import java.util.ArrayList; -import java.util.InputMismatchException; import java.util.Iterator; -import java.util.NoSuchElementException; -import java.util.Scanner; //import com.google.gson.Gson; public class TaskList { @@ -23,6 +20,12 @@ public enum TaskType { TODO } + // ideal implementation of addToList + public void add(Task task) { + this.tasks.add(task); + } + + // temporary until I figure out how to abstract out task creation from adding to list public void addToList(TaskType taskType, String description, String deadline) throws IllegalArgumentException { // debug @@ -31,6 +34,8 @@ public void addToList(TaskType taskType, String description, String deadline) Task newTask = null; // task to be added // based on task type, create corresponding subclass object + // todo: how to call subclass constructor from parent class? + // want to move this to the Task class switch (taskType) { case DEADLINE: newTask = new Deadline(description, deadline); @@ -48,7 +53,7 @@ public void addToList(TaskType taskType, String description, String deadline) } // add newTask to taskList - tasks.add(newTask); + this.tasks.add(newTask); System.out.println("Okay! I've added: " + description + ". Use list to see all your tasks!"); } @@ -61,7 +66,7 @@ public void printList() { } } -// public String printToFile() { +// public String writeToFile() { // Task task; // for (Iterator iterator = this.tasks.iterator(); iterator.hasNext(); task = iterator.next()) { // String s = iterator.next().printToFile(); @@ -77,9 +82,22 @@ public void deleteTask(Task taskToDelete) { String taskDescription = taskToDelete.toString(); tasks.remove(taskToDelete); System.out.println("Noted. I've removed this task: " + taskDescription); - System.out.println("Now you have " + tasks.size() + "items in this list."); + System.out.println("Now you have " + tasks.size() + " items in this list."); + } + + public boolean isEmpty() { + return this.tasks.isEmpty(); } + public TaskList findTasks(String keyword) { + TaskList matchingTasks = new TaskList(); + for (Task task : this.tasks) { + if (task.toString().contains(keyword)) { + matchingTasks.add(task); + } + } + return matchingTasks; + } // public void saveToDisk() { //// // create gson to serialise taskList //// Gson gson = new Gson(); @@ -97,87 +115,4 @@ public void deleteTask(Task taskToDelete) { //// Type taskListType = new TypeToken>(){}.getType(); //// this.tasks = Gson.fromJson(json, taskListType); //// } - - /** - * Processes the given input string. - * - * @param input input string given by user. - */ - public void processInput(String input) throws InputMismatchException { - Scanner inputReader = new Scanner(input); - String command = inputReader.next(); - String description; - String deadline; - - switch (command) { - case "list": - // if "list", print list - this.printList(); - break; - case "done": - try { - int taskId = inputReader.nextInt(); // extract the task ID entered by user - this.getTask(taskId).markAsDone(); // mark task as done - } catch (InputMismatchException e) { - // user input after "done" is not an int - System.out.println("Oops! You entered an invalid task ID!"); - } catch (NoSuchElementException e) { - // user input after "done" is blank - System.out.println("Oops! You did not enter a task ID!"); - } catch (IndexOutOfBoundsException e) { - // user input after "done" is an invalid task ID - System.out.println("Oops! You entered an invalid task ID!"); - } - break; - case "delete": - try { - int taskId = inputReader.nextInt(); // extract the task ID entered by user - this.deleteTask(getTask(taskId)); // mark task as done - } catch (InputMismatchException e) { - // user input after "done" is not an int - System.out.println("Oops! You entered an invalid task ID!"); - } catch (NoSuchElementException e) { - // user input after "done" is blank - System.out.println("Oops! You did not enter a task ID!"); - } catch (IndexOutOfBoundsException e) { - // user input after "done" is an invalid task ID - System.out.println("Oops! You entered an invalid task ID!"); - } - break; - case "todo": - try { - description = inputReader.nextLine().strip(); - deadline = "no deadline"; - this.addToList(TaskList.TaskType.TODO, description, deadline); - } catch (NoSuchElementException e) { - // user imput after task type is blank - System.out.println("Oops! You did not enter a description!"); - } - break; - case "event": - inputReader.useDelimiter("/at"); - try { - description = inputReader.next().strip(); - deadline = inputReader.next().strip(); - this.addToList(TaskList.TaskType.EVENT, description, deadline); - } catch (NoSuchElementException e) { - // user imput after task type is blank - System.out.println("Oops! You did not enter a description or deadline!"); - } - break; - case "deadline": - inputReader.useDelimiter("/by"); - try { - description = inputReader.next().strip(); - deadline = inputReader.next().strip(); - this.addToList(TaskList.TaskType.DEADLINE, description, deadline); - } catch (NoSuchElementException e) { - // user imput after task type is blank - System.out.println("Oops! You did not enter a description or deadline!"); - } - break; - default: - throw new InputMismatchException(); - } - } } diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java index b8b00aaa7f..990c9602d7 100644 --- a/src/main/java/Ui.java +++ b/src/main/java/Ui.java @@ -36,6 +36,11 @@ public void showError(String message) { System.out.println(message); } + // probably would want to abstract these messages out into Ui class +// public void showTasks() { +// System.out.println() +// } + public void showGoodbye() { System.out.println(goodbyeMessage); } From d89a23a8ff481a94d340277d949f571181ca3605 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Sun, 8 Sep 2019 19:15:32 +0800 Subject: [PATCH 19/84] place java files in packages --- src/main/java/Duke.java | 6 +++++ .../command}/AddDeadlineCommand.java | 6 +++++ .../{ => duke/command}/AddEventCommand.java | 6 +++++ .../{ => duke/command}/AddTaskCommand.java | 4 +++ .../{ => duke/command}/AddTodoCommand.java | 8 ++++-- src/main/java/{ => duke/command}/Command.java | 6 +++++ .../{ => duke/command}/DeleteCommand.java | 6 +++++ .../java/{ => duke/command}/DoneCommand.java | 5 ++++ .../java/{ => duke/command}/ExitCommand.java | 6 +++++ src/main/java/duke/command/FindCommand.java | 25 +++++++++++++++++++ .../java/{ => duke/command}/ListCommand.java | 6 +++++ src/main/java/{ => duke/task}/Deadline.java | 1 + src/main/java/{ => duke/task}/Event.java | 2 ++ src/main/java/{ => duke/task}/Task.java | 2 ++ src/main/java/{ => duke/task}/TaskList.java | 5 ++-- src/main/java/{ => duke/task}/Todo.java | 2 ++ src/main/java/{ => duke/util}/Parser.java | 3 +++ src/main/java/{ => duke/util}/Storage.java | 4 +++ src/main/java/{ => duke/util}/Ui.java | 1 + 19 files changed, 99 insertions(+), 5 deletions(-) rename src/main/java/{ => duke/command}/AddDeadlineCommand.java (88%) rename src/main/java/{ => duke/command}/AddEventCommand.java (88%) rename src/main/java/{ => duke/command}/AddTaskCommand.java (88%) rename src/main/java/{ => duke/command}/AddTodoCommand.java (87%) rename src/main/java/{ => duke/command}/Command.java (67%) rename src/main/java/{ => duke/command}/DeleteCommand.java (89%) rename src/main/java/{ => duke/command}/DoneCommand.java (90%) rename src/main/java/{ => duke/command}/ExitCommand.java (72%) create mode 100644 src/main/java/duke/command/FindCommand.java rename src/main/java/{ => duke/command}/ListCommand.java (62%) rename src/main/java/{ => duke/task}/Deadline.java (94%) rename src/main/java/{ => duke/task}/Event.java (93%) rename src/main/java/{ => duke/task}/Task.java (97%) rename src/main/java/{ => duke/task}/TaskList.java (97%) rename src/main/java/{ => duke/task}/Todo.java (86%) rename src/main/java/{ => duke/util}/Parser.java (97%) rename src/main/java/{ => duke/util}/Storage.java (96%) rename src/main/java/{ => duke/util}/Ui.java (98%) diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 8a77e89ed7..c212e7432f 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,3 +1,9 @@ +import duke.command.Command; +import duke.task.TaskList; +import duke.util.Parser; +import duke.util.Storage; +import duke.util.Ui; + public class Duke { private Storage storage; private TaskList tasks; diff --git a/src/main/java/AddDeadlineCommand.java b/src/main/java/duke/command/AddDeadlineCommand.java similarity index 88% rename from src/main/java/AddDeadlineCommand.java rename to src/main/java/duke/command/AddDeadlineCommand.java index 7d9c5de015..3ff1417105 100644 --- a/src/main/java/AddDeadlineCommand.java +++ b/src/main/java/duke/command/AddDeadlineCommand.java @@ -1,3 +1,9 @@ +package duke.command; + +import duke.task.Task; +import duke.task.TaskList; +import duke.util.Storage; +import duke.util.Ui; import java.util.NoSuchElementException; import java.util.Scanner; diff --git a/src/main/java/AddEventCommand.java b/src/main/java/duke/command/AddEventCommand.java similarity index 88% rename from src/main/java/AddEventCommand.java rename to src/main/java/duke/command/AddEventCommand.java index 608cfac2f0..dd86b4e727 100644 --- a/src/main/java/AddEventCommand.java +++ b/src/main/java/duke/command/AddEventCommand.java @@ -1,3 +1,9 @@ +package duke.command; + +import duke.task.Task; +import duke.task.TaskList; +import duke.util.Storage; +import duke.util.Ui; import java.util.NoSuchElementException; import java.util.Scanner; diff --git a/src/main/java/AddTaskCommand.java b/src/main/java/duke/command/AddTaskCommand.java similarity index 88% rename from src/main/java/AddTaskCommand.java rename to src/main/java/duke/command/AddTaskCommand.java index 4b1113dc33..611c7088d6 100644 --- a/src/main/java/AddTaskCommand.java +++ b/src/main/java/duke/command/AddTaskCommand.java @@ -1,3 +1,7 @@ +package duke.command; + +import duke.task.Task; + public abstract class AddTaskCommand implements Command { String restOfCommand; diff --git a/src/main/java/AddTodoCommand.java b/src/main/java/duke/command/AddTodoCommand.java similarity index 87% rename from src/main/java/AddTodoCommand.java rename to src/main/java/duke/command/AddTodoCommand.java index 10fccf0f23..a2ec6e213a 100644 --- a/src/main/java/AddTodoCommand.java +++ b/src/main/java/duke/command/AddTodoCommand.java @@ -1,3 +1,9 @@ +package duke.command; + +import duke.task.Task; +import duke.task.TaskList; +import duke.util.Storage; +import duke.util.Ui; import java.util.NoSuchElementException; public class AddTodoCommand extends AddTaskCommand { @@ -24,8 +30,6 @@ public Task createTask() { @Override public void execute(TaskList tasks, Ui ui, Storage storage) { try { - // debug - System.out.println("at execute of add todo"); tasks.addToList(TaskList.TaskType.TODO, getDescription(), getDeadline()); } catch (NoSuchElementException e) { // user imput after task type is blank diff --git a/src/main/java/Command.java b/src/main/java/duke/command/Command.java similarity index 67% rename from src/main/java/Command.java rename to src/main/java/duke/command/Command.java index fa5939a3a6..552e5089dc 100644 --- a/src/main/java/Command.java +++ b/src/main/java/duke/command/Command.java @@ -1,3 +1,9 @@ +package duke.command; + +import duke.task.TaskList; +import duke.util.Storage; +import duke.util.Ui; + public interface Command { void execute(TaskList tasks, Ui ui, Storage storage); // implementation varies for each subclass of Command diff --git a/src/main/java/DeleteCommand.java b/src/main/java/duke/command/DeleteCommand.java similarity index 89% rename from src/main/java/DeleteCommand.java rename to src/main/java/duke/command/DeleteCommand.java index f28b4d3008..7e1f6bac2e 100644 --- a/src/main/java/DeleteCommand.java +++ b/src/main/java/duke/command/DeleteCommand.java @@ -1,3 +1,9 @@ +package duke.command; + +import duke.task.Task; +import duke.task.TaskList; +import duke.util.Storage; +import duke.util.Ui; import java.util.InputMismatchException; import java.util.NoSuchElementException; diff --git a/src/main/java/DoneCommand.java b/src/main/java/duke/command/DoneCommand.java similarity index 90% rename from src/main/java/DoneCommand.java rename to src/main/java/duke/command/DoneCommand.java index 98f0c40e42..729e31fd10 100644 --- a/src/main/java/DoneCommand.java +++ b/src/main/java/duke/command/DoneCommand.java @@ -1,3 +1,8 @@ +package duke.command; + +import duke.task.TaskList; +import duke.util.Storage; +import duke.util.Ui; import java.util.InputMismatchException; import java.util.NoSuchElementException; diff --git a/src/main/java/ExitCommand.java b/src/main/java/duke/command/ExitCommand.java similarity index 72% rename from src/main/java/ExitCommand.java rename to src/main/java/duke/command/ExitCommand.java index aeff324118..dcdc1f7f72 100644 --- a/src/main/java/ExitCommand.java +++ b/src/main/java/duke/command/ExitCommand.java @@ -1,3 +1,9 @@ +package duke.command; + +import duke.task.TaskList; +import duke.util.Storage; +import duke.util.Ui; + public class ExitCommand implements Command { @Override diff --git a/src/main/java/duke/command/FindCommand.java b/src/main/java/duke/command/FindCommand.java new file mode 100644 index 0000000000..d5c1b8785e --- /dev/null +++ b/src/main/java/duke/command/FindCommand.java @@ -0,0 +1,25 @@ +package duke.command; + +import duke.task.TaskList; +import duke.util.Storage; +import duke.util.Ui; + +public class FindCommand implements Command { + private String keyword; + + public FindCommand(String keyword) { + super(); + this.keyword = keyword; + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + TaskList matchingTasks = tasks.findTasks(this.keyword); + if (matchingTasks.isEmpty()) { + System.out.println("There are no tasks matching your query :("); + } else { + System.out.println("Here are the matching tasks in your list:"); + matchingTasks.printList(); + } + } +} diff --git a/src/main/java/ListCommand.java b/src/main/java/duke/command/ListCommand.java similarity index 62% rename from src/main/java/ListCommand.java rename to src/main/java/duke/command/ListCommand.java index 90246d961b..d9d1b66189 100644 --- a/src/main/java/ListCommand.java +++ b/src/main/java/duke/command/ListCommand.java @@ -1,3 +1,9 @@ +package duke.command; + +import duke.task.TaskList; +import duke.util.Storage; +import duke.util.Ui; + public class ListCommand implements Command { @Override diff --git a/src/main/java/Deadline.java b/src/main/java/duke/task/Deadline.java similarity index 94% rename from src/main/java/Deadline.java rename to src/main/java/duke/task/Deadline.java index 508c81230c..c028b6ae23 100644 --- a/src/main/java/Deadline.java +++ b/src/main/java/duke/task/Deadline.java @@ -1,3 +1,4 @@ +package duke.task; public class Deadline extends Task { private String by; diff --git a/src/main/java/Event.java b/src/main/java/duke/task/Event.java similarity index 93% rename from src/main/java/Event.java rename to src/main/java/duke/task/Event.java index 3602381f43..7550d8c1dd 100644 --- a/src/main/java/Event.java +++ b/src/main/java/duke/task/Event.java @@ -1,3 +1,5 @@ +package duke.task; + public class Event extends Task { private String at; diff --git a/src/main/java/Task.java b/src/main/java/duke/task/Task.java similarity index 97% rename from src/main/java/Task.java rename to src/main/java/duke/task/Task.java index eace1b901a..ba4287ae33 100644 --- a/src/main/java/Task.java +++ b/src/main/java/duke/task/Task.java @@ -1,3 +1,5 @@ +package duke.task; + public class Task { private String description; private Boolean isDone; diff --git a/src/main/java/TaskList.java b/src/main/java/duke/task/TaskList.java similarity index 97% rename from src/main/java/TaskList.java rename to src/main/java/duke/task/TaskList.java index 38e2b91a16..4dd034d031 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/duke/task/TaskList.java @@ -1,3 +1,5 @@ +package duke.task; + import java.util.ArrayList; import java.util.Iterator; //import com.google.gson.Gson; @@ -28,9 +30,6 @@ public void add(Task task) { // temporary until I figure out how to abstract out task creation from adding to list public void addToList(TaskType taskType, String description, String deadline) throws IllegalArgumentException { - // debug - System.out.println("at addToList method"); - Task newTask = null; // task to be added // based on task type, create corresponding subclass object diff --git a/src/main/java/Todo.java b/src/main/java/duke/task/Todo.java similarity index 86% rename from src/main/java/Todo.java rename to src/main/java/duke/task/Todo.java index ab637b86d7..e75ac4ef13 100644 --- a/src/main/java/Todo.java +++ b/src/main/java/duke/task/Todo.java @@ -1,3 +1,5 @@ +package duke.task; + public class Todo extends Task { public Todo(String description) { super(description); diff --git a/src/main/java/Parser.java b/src/main/java/duke/util/Parser.java similarity index 97% rename from src/main/java/Parser.java rename to src/main/java/duke/util/Parser.java index 64825a7b98..69fc9e0b8b 100644 --- a/src/main/java/Parser.java +++ b/src/main/java/duke/util/Parser.java @@ -1,3 +1,6 @@ +package duke.util; + +import duke.command.*; import java.util.InputMismatchException; import java.util.Scanner; diff --git a/src/main/java/Storage.java b/src/main/java/duke/util/Storage.java similarity index 96% rename from src/main/java/Storage.java rename to src/main/java/duke/util/Storage.java index fb423d93e5..e97dcb1b80 100644 --- a/src/main/java/Storage.java +++ b/src/main/java/duke/util/Storage.java @@ -1,3 +1,7 @@ +package duke.util; + +import duke.task.Task; +import duke.task.TaskList; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileNotFoundException; diff --git a/src/main/java/Ui.java b/src/main/java/duke/util/Ui.java similarity index 98% rename from src/main/java/Ui.java rename to src/main/java/duke/util/Ui.java index 990c9602d7..8b6bc1feca 100644 --- a/src/main/java/Ui.java +++ b/src/main/java/duke/util/Ui.java @@ -1,3 +1,4 @@ +package duke.util; import java.util.Scanner; public class Ui { From 94dcf1c50b06262ff365cbcff54b9c206859781c Mon Sep 17 00:00:00 2001 From: nattanyz Date: Mon, 9 Sep 2019 10:13:21 +0800 Subject: [PATCH 20/84] add DukeTest.java, modify build.gradle to support JUnit --- build.gradle | 5 +++++ src/test/java/DukeTest.java | 10 ++++++++++ 2 files changed, 15 insertions(+) create mode 100644 src/test/java/DukeTest.java diff --git a/build.gradle b/build.gradle index 7ece6faf24..2baaa3ad8c 100644 --- a/build.gradle +++ b/build.gradle @@ -21,4 +21,9 @@ run { dependencies { implementation 'com.google.code.gson:gson:2.8.5' + testImplementation 'org.junit.jupiter:junit-jupiter:5.5.0' +} + +test { + useJUnitPlatform() } \ No newline at end of file diff --git a/src/test/java/DukeTest.java b/src/test/java/DukeTest.java new file mode 100644 index 0000000000..55c64ed52c --- /dev/null +++ b/src/test/java/DukeTest.java @@ -0,0 +1,10 @@ +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class DukeTest { + @Test + public void dummyTest() { + assertEquals(2,2); + } +} \ No newline at end of file From 13c1f9bf26904a71a20ef6dd3d1e5ca2ca4e646a Mon Sep 17 00:00:00 2001 From: nattanyz Date: Mon, 9 Sep 2019 10:17:35 +0800 Subject: [PATCH 21/84] remove unnecessary iterators and replace unnecessary references to "this.tasks" with "tasks" in TaskList.java --- build.gradle | 2 +- src/main/java/duke/task/TaskList.java | 19 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/build.gradle b/build.gradle index 2baaa3ad8c..5f0cf7018c 100644 --- a/build.gradle +++ b/build.gradle @@ -26,4 +26,4 @@ dependencies { test { useJUnitPlatform() -} \ No newline at end of file +} diff --git a/src/main/java/duke/task/TaskList.java b/src/main/java/duke/task/TaskList.java index 4dd034d031..308bf827d8 100644 --- a/src/main/java/duke/task/TaskList.java +++ b/src/main/java/duke/task/TaskList.java @@ -1,7 +1,6 @@ package duke.task; import java.util.ArrayList; -import java.util.Iterator; //import com.google.gson.Gson; public class TaskList { @@ -13,7 +12,7 @@ public TaskList(ArrayList tasks) { } public TaskList() { - this.tasks = new ArrayList(); + tasks = new ArrayList(); } public enum TaskType { @@ -24,7 +23,7 @@ public enum TaskType { // ideal implementation of addToList public void add(Task task) { - this.tasks.add(task); + tasks.add(task); } // temporary until I figure out how to abstract out task creation from adding to list @@ -52,23 +51,23 @@ public void addToList(TaskType taskType, String description, String deadline) } // add newTask to taskList - this.tasks.add(newTask); + tasks.add(newTask); System.out.println("Okay! I've added: " + description + ". Use list to see all your tasks!"); } public void printList() { int i = 1; - for (Iterator iterator = this.tasks.iterator(); iterator.hasNext(); i++) { - String s = iterator.next().toString(); + for (Task task : tasks) { + String s = task.toString(); System.out.println(i + ". " + s); } } // public String writeToFile() { // Task task; -// for (Iterator iterator = this.tasks.iterator(); iterator.hasNext(); task = iterator.next()) { -// String s = iterator.next().printToFile(); +// for (Task task : tasks) { +// String s = task.printToFile(); // return s; // } // } @@ -85,12 +84,12 @@ public void deleteTask(Task taskToDelete) { } public boolean isEmpty() { - return this.tasks.isEmpty(); + return tasks.isEmpty(); } public TaskList findTasks(String keyword) { TaskList matchingTasks = new TaskList(); - for (Task task : this.tasks) { + for (Task task : tasks) { if (task.toString().contains(keyword)) { matchingTasks.add(task); } From 72d92b24bc92274c6ac96a7925913007175133e3 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Mon, 9 Sep 2019 10:29:04 +0800 Subject: [PATCH 22/84] add newTask method to separate creating and adding of tasks, remove addToList method and replace with calls to newTask() and add() --- .../java/duke/command/AddDeadlineCommand.java | 3 ++- src/main/java/duke/command/AddEventCommand.java | 3 ++- src/main/java/duke/command/AddTodoCommand.java | 3 ++- src/main/java/duke/task/Task.java | 8 ++++++-- src/main/java/duke/task/TaskList.java | 17 ++++++----------- 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/main/java/duke/command/AddDeadlineCommand.java b/src/main/java/duke/command/AddDeadlineCommand.java index 3ff1417105..e83c5ea570 100644 --- a/src/main/java/duke/command/AddDeadlineCommand.java +++ b/src/main/java/duke/command/AddDeadlineCommand.java @@ -33,7 +33,8 @@ public Task createTask() { @Override public void execute(TaskList tasks, Ui ui, Storage storage) { try { - tasks.addToList(TaskList.TaskType.DEADLINE, getDescription(), getDeadline()); + Task newTask = tasks.newTask(TaskList.TaskType.DEADLINE, getDescription(), getDeadline()); + tasks.add(newTask); } catch (NoSuchElementException e) { // user input after task type is blank System.out.println("Oops! You did not enter a description or deadline!"); diff --git a/src/main/java/duke/command/AddEventCommand.java b/src/main/java/duke/command/AddEventCommand.java index dd86b4e727..48ec3a9fc3 100644 --- a/src/main/java/duke/command/AddEventCommand.java +++ b/src/main/java/duke/command/AddEventCommand.java @@ -33,7 +33,8 @@ public Task createTask() { @Override public void execute(TaskList tasks, Ui ui, Storage storage) { try { - tasks.addToList(TaskList.TaskType.EVENT, getDescription(), getDeadline()); + Task newTask = tasks.newTask(TaskList.TaskType.EVENT, getDescription(), getDeadline()); + tasks.add(newTask); } catch (NoSuchElementException e) { // user imput after task type is blank System.out.println("Oops! You did not enter a description or deadline!"); diff --git a/src/main/java/duke/command/AddTodoCommand.java b/src/main/java/duke/command/AddTodoCommand.java index a2ec6e213a..5854f90f40 100644 --- a/src/main/java/duke/command/AddTodoCommand.java +++ b/src/main/java/duke/command/AddTodoCommand.java @@ -30,7 +30,8 @@ public Task createTask() { @Override public void execute(TaskList tasks, Ui ui, Storage storage) { try { - tasks.addToList(TaskList.TaskType.TODO, getDescription(), getDeadline()); + Task newTask = tasks.newTask(TaskList.TaskType.TODO, getDescription(), getDeadline()); + tasks.add(newTask); } catch (NoSuchElementException e) { // user imput after task type is blank System.out.println("Oops! You did not enter a description!"); diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java index ba4287ae33..c38d775985 100644 --- a/src/main/java/duke/task/Task.java +++ b/src/main/java/duke/task/Task.java @@ -3,7 +3,7 @@ public class Task { private String description; private Boolean isDone; - protected String type; + String type; public Task(String description) { // todo: modify constructor to create new task from String @@ -18,7 +18,11 @@ public String toString() { return type + status + this.description; } - public String getStatusIcon() { + String getDescription() { + return this.description; + } + + private String getStatusIcon() { return (isDone ? "\u2713" : "\u2718"); // return tick or X symbols } diff --git a/src/main/java/duke/task/TaskList.java b/src/main/java/duke/task/TaskList.java index 308bf827d8..eafa6eb217 100644 --- a/src/main/java/duke/task/TaskList.java +++ b/src/main/java/duke/task/TaskList.java @@ -1,7 +1,6 @@ package duke.task; import java.util.ArrayList; -//import com.google.gson.Gson; public class TaskList { @@ -12,7 +11,7 @@ public TaskList(ArrayList tasks) { } public TaskList() { - tasks = new ArrayList(); + tasks = new ArrayList<>(); } public enum TaskType { @@ -24,16 +23,15 @@ public enum TaskType { // ideal implementation of addToList public void add(Task task) { tasks.add(task); + + System.out.println("Okay! I've added: " + task.getDescription() + + ". Use list to see all your tasks!"); } - // temporary until I figure out how to abstract out task creation from adding to list - public void addToList(TaskType taskType, String description, String deadline) + public Task newTask(TaskType taskType, String description, String deadline) throws IllegalArgumentException { Task newTask = null; // task to be added - // based on task type, create corresponding subclass object - // todo: how to call subclass constructor from parent class? - // want to move this to the Task class switch (taskType) { case DEADLINE: newTask = new Deadline(description, deadline); @@ -50,10 +48,7 @@ public void addToList(TaskType taskType, String description, String deadline) break; } - // add newTask to taskList - tasks.add(newTask); - System.out.println("Okay! I've added: " + description - + ". Use list to see all your tasks!"); + return newTask; } public void printList() { From de6b351012307de59bec6e60d6ef31032a6e6bb7 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Mon, 9 Sep 2019 12:20:39 +0800 Subject: [PATCH 23/84] partially implement load() and save() methods in Storage class using Gson, remove redundant saveToDisk() and readFromFile() methods from TaskList class --- build.gradle | 10 ++++++-- src/main/java/{ => duke}/Duke.java | 4 ++- src/main/java/duke/task/TaskList.java | 18 +------------- src/main/java/duke/util/Storage.java | 35 ++++++++++++++++++--------- 4 files changed, 35 insertions(+), 32 deletions(-) rename src/main/java/{ => duke}/Duke.java (96%) diff --git a/build.gradle b/build.gradle index 5f0cf7018c..f0d52509bc 100644 --- a/build.gradle +++ b/build.gradle @@ -1,9 +1,9 @@ plugins { id 'java' id 'application' +// id 'com.github.johnrengelman.shadow' version '5.1.0' } -group 'seedu.duke' version '0.1.0' repositories { @@ -11,7 +11,6 @@ repositories { } application { - // Change this to your main class. mainClassName = "Duke" } @@ -27,3 +26,10 @@ dependencies { test { useJUnitPlatform() } + +//shadowJar { +// archiveBaseName = "duke" +// archiveVersion = "0.1.3" +// archiveClassifier = null +// archiveAppendix = null +//} diff --git a/src/main/java/Duke.java b/src/main/java/duke/Duke.java similarity index 96% rename from src/main/java/Duke.java rename to src/main/java/duke/Duke.java index c212e7432f..6201c5b1a9 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/duke/Duke.java @@ -1,3 +1,5 @@ +//package duke; + import duke.command.Command; import duke.task.TaskList; import duke.util.Parser; @@ -20,7 +22,7 @@ public Duke(String filePath) { } } - public void run() { + private void run() { ui.showWelcome(); boolean isExit = false; while (!isExit) { diff --git a/src/main/java/duke/task/TaskList.java b/src/main/java/duke/task/TaskList.java index eafa6eb217..839755edfb 100644 --- a/src/main/java/duke/task/TaskList.java +++ b/src/main/java/duke/task/TaskList.java @@ -91,21 +91,5 @@ public TaskList findTasks(String keyword) { } return matchingTasks; } -// public void saveToDisk() { -//// // create gson to serialise taskList -//// Gson gson = new Gson(); -//// String taskListGson = gson.toJson(this); -//// -//// // write taskList to txt file -//// } -//// -//// public void readFromFile() { -//// // read json from file -//// // TODO -//// -//// // create type token to deal with Arraylist -//// // todo: why can't I use Type????? -//// Type taskListType = new TypeToken>(){}.getType(); -//// this.tasks = Gson.fromJson(json, taskListType); -//// } + } diff --git a/src/main/java/duke/util/Storage.java b/src/main/java/duke/util/Storage.java index e97dcb1b80..e78c17bf12 100644 --- a/src/main/java/duke/util/Storage.java +++ b/src/main/java/duke/util/Storage.java @@ -1,14 +1,18 @@ package duke.util; +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; import duke.task.Task; import duke.task.TaskList; import java.io.BufferedReader; import java.io.BufferedWriter; +import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; +import java.lang.reflect.Type; import java.util.ArrayList; public class Storage { @@ -20,19 +24,23 @@ public Storage(String filePath) { } public ArrayList load() { - ArrayList tasks = new ArrayList(); + ArrayList tasks = new ArrayList<>(); try { // create buffered reader from file BufferedReader br = new BufferedReader(new FileReader(this.filePath)); - // load tasks from file while file is not empty - for (String line = br.readLine(); line != null; line = br.readLine()) { - tasks.add(loadTask(line)); - } + // create Gson object + Gson gson = new Gson(); + + // create type token to deal with ArrayList + Type taskListType = new TypeToken>(){}.getType(); + + // import tasks from json + tasks = gson.fromJson(br, taskListType); + } catch (FileNotFoundException e) { - // temporary haxx - e.printStackTrace(); - } catch (IOException e) { + System.out.println("Existing tasks file not found! Starting duke afresh..."); + } catch (Exception e) { // temporary haxx e.printStackTrace(); } @@ -48,11 +56,14 @@ private Task loadTask(String line) { public void save(TaskList tasks) { // create json representation and save to given file try { - PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(this.filePath))); - - // for each task in tasks, create its string representation for storage + // todo: fix file not found (create file), maybe use FileOutputStream instead + File file = new File(this.filePath); + file.createNewFile(); // result (boolean) is not required + PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file))); - // write string to file + // create json representation of tasks + Gson gson = new Gson(); + gson.toJson(tasks, pw); // print done System.out.println(doneMessage + filePath); From 0d7e28e9cd28e2ce2c0335d1d7a8a37042ccf9c1 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Fri, 27 Sep 2019 15:06:21 +0800 Subject: [PATCH 24/84] resolve main class not found issue, change command classes to use ui.showError instead of System.out.println --- build.gradle | 2 +- src/main/java/duke/Duke.java | 4 ++-- src/main/java/duke/command/AddDeadlineCommand.java | 2 +- src/main/java/duke/command/AddEventCommand.java | 4 ++-- src/main/java/duke/command/AddTodoCommand.java | 4 ++-- src/main/java/duke/command/DeleteCommand.java | 11 ++++------- src/main/java/duke/command/DoneCommand.java | 11 ++++------- src/main/java/duke/command/ListCommand.java | 3 +++ src/main/java/duke/util/DukeException.java | 5 +++++ src/main/java/duke/util/Parser.java | 4 ++-- src/main/java/duke/util/Ui.java | 8 ++------ 11 files changed, 28 insertions(+), 30 deletions(-) create mode 100644 src/main/java/duke/util/DukeException.java diff --git a/build.gradle b/build.gradle index f0d52509bc..c4e33392bf 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ repositories { } application { - mainClassName = "Duke" + mainClassName = 'duke.Duke' } run { diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 6201c5b1a9..ddd2834cd9 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -1,4 +1,4 @@ -//package duke; +package duke; import duke.command.Command; import duke.task.TaskList; @@ -33,7 +33,7 @@ private void run() { c.execute(tasks, ui, storage); isExit = c.isExit(); } catch (Exception e) { - // temporary haxx + // todo: proper exception handling System.out.println(e); } finally { ui.showLine(); diff --git a/src/main/java/duke/command/AddDeadlineCommand.java b/src/main/java/duke/command/AddDeadlineCommand.java index e83c5ea570..4712b6a3bd 100644 --- a/src/main/java/duke/command/AddDeadlineCommand.java +++ b/src/main/java/duke/command/AddDeadlineCommand.java @@ -37,7 +37,7 @@ public void execute(TaskList tasks, Ui ui, Storage storage) { tasks.add(newTask); } catch (NoSuchElementException e) { // user input after task type is blank - System.out.println("Oops! You did not enter a description or deadline!"); + ui.showError("Oops! You did not enter a description or deadline!"); } } } diff --git a/src/main/java/duke/command/AddEventCommand.java b/src/main/java/duke/command/AddEventCommand.java index 48ec3a9fc3..8b3e4f236f 100644 --- a/src/main/java/duke/command/AddEventCommand.java +++ b/src/main/java/duke/command/AddEventCommand.java @@ -36,8 +36,8 @@ public void execute(TaskList tasks, Ui ui, Storage storage) { Task newTask = tasks.newTask(TaskList.TaskType.EVENT, getDescription(), getDeadline()); tasks.add(newTask); } catch (NoSuchElementException e) { - // user imput after task type is blank - System.out.println("Oops! You did not enter a description or deadline!"); + // user input after task type is blank + ui.showError("Oops! You did not enter a description or deadline!"); } } } diff --git a/src/main/java/duke/command/AddTodoCommand.java b/src/main/java/duke/command/AddTodoCommand.java index 5854f90f40..2aa187994d 100644 --- a/src/main/java/duke/command/AddTodoCommand.java +++ b/src/main/java/duke/command/AddTodoCommand.java @@ -33,8 +33,8 @@ public void execute(TaskList tasks, Ui ui, Storage storage) { Task newTask = tasks.newTask(TaskList.TaskType.TODO, getDescription(), getDeadline()); tasks.add(newTask); } catch (NoSuchElementException e) { - // user imput after task type is blank - System.out.println("Oops! You did not enter a description!"); + // user input after task type is blank + ui.showError("Oops! You did not enter a description!"); } } } diff --git a/src/main/java/duke/command/DeleteCommand.java b/src/main/java/duke/command/DeleteCommand.java index 7e1f6bac2e..27fc2ff9f7 100644 --- a/src/main/java/duke/command/DeleteCommand.java +++ b/src/main/java/duke/command/DeleteCommand.java @@ -20,15 +20,12 @@ public void execute(TaskList tasks, Ui ui, Storage storage) { try { Task task = tasks.getTask(taskId); tasks.deleteTask(task); // mark task as done - } catch (InputMismatchException e) { - // user input after "done" is not an int - System.out.println("Oops! You entered an invalid task ID!"); + } catch (InputMismatchException | IndexOutOfBoundsException e) { + // user input after "done" is not an int, or is an invalid task ID + ui.showError("Oops! You entered an invalid task ID!"); } catch (NoSuchElementException e) { // user input after "done" is blank - System.out.println("Oops! You did not enter a task ID!"); - } catch (IndexOutOfBoundsException e) { - // user input after "done" is an invalid task ID - System.out.println("Oops! You entered an invalid task ID!"); + ui.showError("Oops! You did not enter a task ID!"); } } } diff --git a/src/main/java/duke/command/DoneCommand.java b/src/main/java/duke/command/DoneCommand.java index 729e31fd10..7937cfcf2a 100644 --- a/src/main/java/duke/command/DoneCommand.java +++ b/src/main/java/duke/command/DoneCommand.java @@ -18,15 +18,12 @@ public DoneCommand(int taskId) { public void execute(TaskList tasks, Ui ui, Storage storage) { try { tasks.getTask(this.taskId).markAsDone(); // mark task as done - } catch (InputMismatchException e) { - // user input after "done" is not an int - System.out.println("Oops! You entered an invalid task ID!"); + } catch (InputMismatchException | IndexOutOfBoundsException e) { + // user input after "done" is not an int, or is an invalid task ID + ui.showError("Oops! You entered an invalid task ID!"); } catch (NoSuchElementException e) { // user input after "done" is blank - System.out.println("Oops! You did not enter a task ID!"); - } catch (IndexOutOfBoundsException e) { - // user input after "done" is an invalid task ID - System.out.println("Oops! You entered an invalid task ID!"); + ui.showError("Oops! You did not enter a task ID!"); } } } diff --git a/src/main/java/duke/command/ListCommand.java b/src/main/java/duke/command/ListCommand.java index d9d1b66189..4c33942bd9 100644 --- a/src/main/java/duke/command/ListCommand.java +++ b/src/main/java/duke/command/ListCommand.java @@ -8,6 +8,9 @@ public class ListCommand implements Command { @Override public void execute(TaskList tasks, Ui ui, Storage storage) { + if (tasks.isEmpty()) { + ui.showError("The task list is empty."); + } tasks.printList(); } } diff --git a/src/main/java/duke/util/DukeException.java b/src/main/java/duke/util/DukeException.java new file mode 100644 index 0000000000..201da3eeed --- /dev/null +++ b/src/main/java/duke/util/DukeException.java @@ -0,0 +1,5 @@ +package duke.util; + +public class DukeException extends Exception { + +} diff --git a/src/main/java/duke/util/Parser.java b/src/main/java/duke/util/Parser.java index 69fc9e0b8b..8f1c92d124 100644 --- a/src/main/java/duke/util/Parser.java +++ b/src/main/java/duke/util/Parser.java @@ -27,8 +27,8 @@ public static Command parse(String fullCommand) throws InputMismatchException { String restOfCommand = commandReader.nextLine(); return new AddEventCommand(restOfCommand); } else if (command.equals("deadline")) { - String restofCommand = commandReader.nextLine(); - return new AddDeadlineCommand(restofCommand); + String restOfCommand = commandReader.nextLine(); + return new AddDeadlineCommand(restOfCommand); } else if (command.equals("find")) { String keyword = commandReader.nextLine(); return new FindCommand(keyword); diff --git a/src/main/java/duke/util/Ui.java b/src/main/java/duke/util/Ui.java index 8b6bc1feca..d4469e45f1 100644 --- a/src/main/java/duke/util/Ui.java +++ b/src/main/java/duke/util/Ui.java @@ -10,7 +10,6 @@ public class Ui { + "| |_| | |_| | < __/\n" + "|____/ \\__,_|_|\\_\\___|\n"; private String welcomeMessage = "Hello from \n" + logo + "What can I do for you?"; - private String line = "____________________________________________________________"; private String goodbyeMessage = "Bye. Hope to see you again soon!"; public Ui() { @@ -30,18 +29,15 @@ public String readCommand() { } public void showLine() { + String line = "____________________________________________________________"; System.out.println(line); } public void showError(String message) { + // todo: use exceptions to abstract out error messages from command classes? System.out.println(message); } - // probably would want to abstract these messages out into Ui class -// public void showTasks() { -// System.out.println() -// } - public void showGoodbye() { System.out.println(goodbyeMessage); } From 82c5a39030250d1eba877aae675c7c5cffda9584 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Fri, 27 Sep 2019 15:18:59 +0800 Subject: [PATCH 25/84] build jar file, add "command not recognised" error message --- build.gradle | 14 +++++++------- src/main/java/duke/Duke.java | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/build.gradle b/build.gradle index c4e33392bf..529d16923a 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ plugins { id 'java' id 'application' -// id 'com.github.johnrengelman.shadow' version '5.1.0' + id 'com.github.johnrengelman.shadow' version '5.1.0' } version '0.1.0' @@ -27,9 +27,9 @@ test { useJUnitPlatform() } -//shadowJar { -// archiveBaseName = "duke" -// archiveVersion = "0.1.3" -// archiveClassifier = null -// archiveAppendix = null -//} +shadowJar { + archiveBaseName = "duke" + archiveVersion = "0.1" + archiveClassifier = null + archiveAppendix = null +} diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index ddd2834cd9..2e1e107012 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -5,6 +5,7 @@ import duke.util.Parser; import duke.util.Storage; import duke.util.Ui; +import java.util.InputMismatchException; public class Duke { private Storage storage; @@ -32,9 +33,8 @@ private void run() { Command c = Parser.parse(fullCommand); c.execute(tasks, ui, storage); isExit = c.isExit(); - } catch (Exception e) { - // todo: proper exception handling - System.out.println(e); + } catch (InputMismatchException e) { + ui.showError("Command not recognised!"); } finally { ui.showLine(); } From a0ae06d02c5d251d63539dfc84da7fbcd4bfb5b4 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Fri, 27 Sep 2019 15:50:58 +0800 Subject: [PATCH 26/84] attempt to implement datetime --- src/main/java/duke/util/DateTime.java | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/main/java/duke/util/DateTime.java diff --git a/src/main/java/duke/util/DateTime.java b/src/main/java/duke/util/DateTime.java new file mode 100644 index 0000000000..595b301834 --- /dev/null +++ b/src/main/java/duke/util/DateTime.java @@ -0,0 +1,23 @@ +package duke.util; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +//import duke.util.Ui; + +public class DateTime { + // todo: date format is not implemented correctly + private static DateFormat dateFormat = new SimpleDateFormat("dd/mm/YYYY HHmm"); + public static Date parseDate(String date) { + Date d = null; + try { + d = dateFormat.parse(date); + } catch (ParseException e) { + // how to use ui's methods without passing Ui to this method? + System.out.println("Oops! You did not enter the date in an appropriate format.\n" + + "Try: DD/MM/YYYY HHmm instead."); + } + return d; + } +} From 704355512722ecc1bfc12c4cc0f1722148c84aa9 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Sun, 29 Sep 2019 11:01:19 +0800 Subject: [PATCH 27/84] implement execute() in abstract class AddTaskCommand, implement createTask() for each task type, move TaskType enum to Task class, use createTask() in execute(), remove now-unused newTask() method --- .../java/duke/command/AddDeadlineCommand.java | 20 ++----------- .../java/duke/command/AddEventCommand.java | 20 ++----------- .../java/duke/command/AddTaskCommand.java | 18 ++++++++++-- .../java/duke/command/AddTodoCommand.java | 18 ++---------- src/main/java/duke/task/Task.java | 7 +++-- src/main/java/duke/task/TaskList.java | 29 ------------------- 6 files changed, 29 insertions(+), 83 deletions(-) diff --git a/src/main/java/duke/command/AddDeadlineCommand.java b/src/main/java/duke/command/AddDeadlineCommand.java index 4712b6a3bd..998de1b568 100644 --- a/src/main/java/duke/command/AddDeadlineCommand.java +++ b/src/main/java/duke/command/AddDeadlineCommand.java @@ -1,14 +1,11 @@ package duke.command; +import duke.task.Deadline; import duke.task.Task; -import duke.task.TaskList; -import duke.util.Storage; -import duke.util.Ui; -import java.util.NoSuchElementException; import java.util.Scanner; public class AddDeadlineCommand extends AddTaskCommand { - Scanner s = new Scanner(restOfCommand); + private Scanner s = new Scanner(restOfCommand); public AddDeadlineCommand(String restOfCommand) { super(restOfCommand); @@ -27,17 +24,6 @@ public String getDeadline() { @Override public Task createTask() { - return null; - } - - @Override - public void execute(TaskList tasks, Ui ui, Storage storage) { - try { - Task newTask = tasks.newTask(TaskList.TaskType.DEADLINE, getDescription(), getDeadline()); - tasks.add(newTask); - } catch (NoSuchElementException e) { - // user input after task type is blank - ui.showError("Oops! You did not enter a description or deadline!"); - } + return new Deadline(getDescription(), getDeadline()); } } diff --git a/src/main/java/duke/command/AddEventCommand.java b/src/main/java/duke/command/AddEventCommand.java index 8b3e4f236f..556575b941 100644 --- a/src/main/java/duke/command/AddEventCommand.java +++ b/src/main/java/duke/command/AddEventCommand.java @@ -1,14 +1,11 @@ package duke.command; +import duke.task.Event; import duke.task.Task; -import duke.task.TaskList; -import duke.util.Storage; -import duke.util.Ui; -import java.util.NoSuchElementException; import java.util.Scanner; public class AddEventCommand extends AddTaskCommand { - Scanner s = new Scanner(restOfCommand); + private Scanner s = new Scanner(restOfCommand); public AddEventCommand(String restOfCommand) { super(restOfCommand); @@ -27,17 +24,6 @@ public String getDeadline() { @Override public Task createTask() { - return null; - } - - @Override - public void execute(TaskList tasks, Ui ui, Storage storage) { - try { - Task newTask = tasks.newTask(TaskList.TaskType.EVENT, getDescription(), getDeadline()); - tasks.add(newTask); - } catch (NoSuchElementException e) { - // user input after task type is blank - ui.showError("Oops! You did not enter a description or deadline!"); - } + return new Event(getDescription(), getDeadline()); } } diff --git a/src/main/java/duke/command/AddTaskCommand.java b/src/main/java/duke/command/AddTaskCommand.java index 611c7088d6..7e5a185653 100644 --- a/src/main/java/duke/command/AddTaskCommand.java +++ b/src/main/java/duke/command/AddTaskCommand.java @@ -1,17 +1,31 @@ package duke.command; import duke.task.Task; +import duke.task.TaskList; +import duke.util.Storage; +import duke.util.Ui; +import java.util.NoSuchElementException; public abstract class AddTaskCommand implements Command { String restOfCommand; - public AddTaskCommand(String restOfCommand) { + AddTaskCommand(String restOfCommand) { this.restOfCommand = restOfCommand; } abstract String getDescription(); abstract String getDeadline(); - // to abstract out creating the task vs adding it to list abstract Task createTask(); + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + try { + Task newTask = createTask(); + tasks.add(newTask); + } catch (NoSuchElementException e) { + // user input after task type is blank + ui.showError("Oops! You did not enter a description!"); + } + } } diff --git a/src/main/java/duke/command/AddTodoCommand.java b/src/main/java/duke/command/AddTodoCommand.java index 2aa187994d..bba86a9191 100644 --- a/src/main/java/duke/command/AddTodoCommand.java +++ b/src/main/java/duke/command/AddTodoCommand.java @@ -1,10 +1,7 @@ package duke.command; import duke.task.Task; -import duke.task.TaskList; -import duke.util.Storage; -import duke.util.Ui; -import java.util.NoSuchElementException; +import duke.task.Todo; public class AddTodoCommand extends AddTaskCommand { @@ -24,17 +21,6 @@ public String getDeadline() { @Override public Task createTask() { - return null; - } - - @Override - public void execute(TaskList tasks, Ui ui, Storage storage) { - try { - Task newTask = tasks.newTask(TaskList.TaskType.TODO, getDescription(), getDeadline()); - tasks.add(newTask); - } catch (NoSuchElementException e) { - // user input after task type is blank - ui.showError("Oops! You did not enter a description!"); - } + return new Todo(getDescription()); } } diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java index c38d775985..8c7855b63a 100644 --- a/src/main/java/duke/task/Task.java +++ b/src/main/java/duke/task/Task.java @@ -32,6 +32,9 @@ public void markAsDone() { System.out.println(this.toString()); } -// public String printToFile() { -// } + public enum TaskType { + DEADLINE, + EVENT, + TODO + } } diff --git a/src/main/java/duke/task/TaskList.java b/src/main/java/duke/task/TaskList.java index 839755edfb..b1d084ad9e 100644 --- a/src/main/java/duke/task/TaskList.java +++ b/src/main/java/duke/task/TaskList.java @@ -14,12 +14,6 @@ public TaskList() { tasks = new ArrayList<>(); } - public enum TaskType { - DEADLINE, - EVENT, - TODO - } - // ideal implementation of addToList public void add(Task task) { tasks.add(task); @@ -28,29 +22,6 @@ public void add(Task task) { + ". Use list to see all your tasks!"); } - public Task newTask(TaskType taskType, String description, String deadline) - throws IllegalArgumentException { - Task newTask = null; // task to be added - - switch (taskType) { - case DEADLINE: - newTask = new Deadline(description, deadline); - break; - case EVENT: - newTask = new Event(description, deadline); - break; - case TODO: - newTask = new Todo(description); - break; - default: - // this should not happen; invalid task type should be caught in caller method already - System.out.println("Something went wrong!"); - break; - } - - return newTask; - } - public void printList() { int i = 1; for (Task task : tasks) { From ce6a15df5d52bd4147334b71967f9a66ff846d07 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Sun, 29 Sep 2019 11:46:27 +0800 Subject: [PATCH 28/84] create DukeException class and ExceptionType enum to handle different types of exceptions and their error messages, change ui.showError() to use exceptions --- src/main/java/duke/Duke.java | 4 +++- .../java/duke/command/AddTaskCommand.java | 4 +++- src/main/java/duke/command/DeleteCommand.java | 6 ++++-- src/main/java/duke/command/DoneCommand.java | 6 ++++-- src/main/java/duke/command/FindCommand.java | 7 ++++--- src/main/java/duke/command/ListCommand.java | 4 +++- .../java/duke/exception/DukeException.java | 15 ++++++++++++++ .../java/duke/exception/ExceptionType.java | 20 +++++++++++++++++++ src/main/java/duke/task/TaskList.java | 2 +- src/main/java/duke/util/DateTime.java | 2 ++ src/main/java/duke/util/DukeException.java | 5 ----- src/main/java/duke/util/Ui.java | 12 ++++++++--- 12 files changed, 68 insertions(+), 19 deletions(-) create mode 100644 src/main/java/duke/exception/DukeException.java create mode 100644 src/main/java/duke/exception/ExceptionType.java delete mode 100644 src/main/java/duke/util/DukeException.java diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 2e1e107012..7e517e225c 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -1,6 +1,8 @@ package duke; import duke.command.Command; +import duke.exception.DukeException; +import duke.exception.ExceptionType; import duke.task.TaskList; import duke.util.Parser; import duke.util.Storage; @@ -34,7 +36,7 @@ private void run() { c.execute(tasks, ui, storage); isExit = c.isExit(); } catch (InputMismatchException e) { - ui.showError("Command not recognised!"); + ui.showError(new DukeException(ExceptionType.INVALID_COMMAND)); } finally { ui.showLine(); } diff --git a/src/main/java/duke/command/AddTaskCommand.java b/src/main/java/duke/command/AddTaskCommand.java index 7e5a185653..b8998edbef 100644 --- a/src/main/java/duke/command/AddTaskCommand.java +++ b/src/main/java/duke/command/AddTaskCommand.java @@ -1,5 +1,7 @@ package duke.command; +import duke.exception.DukeException; +import duke.exception.ExceptionType; import duke.task.Task; import duke.task.TaskList; import duke.util.Storage; @@ -25,7 +27,7 @@ public void execute(TaskList tasks, Ui ui, Storage storage) { tasks.add(newTask); } catch (NoSuchElementException e) { // user input after task type is blank - ui.showError("Oops! You did not enter a description!"); + ui.showError(new DukeException(ExceptionType.DESCRIPTION_BLANK)); } } } diff --git a/src/main/java/duke/command/DeleteCommand.java b/src/main/java/duke/command/DeleteCommand.java index 27fc2ff9f7..297283bfa5 100644 --- a/src/main/java/duke/command/DeleteCommand.java +++ b/src/main/java/duke/command/DeleteCommand.java @@ -1,5 +1,7 @@ package duke.command; +import duke.exception.DukeException; +import duke.exception.ExceptionType; import duke.task.Task; import duke.task.TaskList; import duke.util.Storage; @@ -22,10 +24,10 @@ public void execute(TaskList tasks, Ui ui, Storage storage) { tasks.deleteTask(task); // mark task as done } catch (InputMismatchException | IndexOutOfBoundsException e) { // user input after "done" is not an int, or is an invalid task ID - ui.showError("Oops! You entered an invalid task ID!"); + ui.showError(new DukeException(ExceptionType.INVALID_ID)); } catch (NoSuchElementException e) { // user input after "done" is blank - ui.showError("Oops! You did not enter a task ID!"); + ui.showError(new DukeException(ExceptionType.ID_BLANK)); } } } diff --git a/src/main/java/duke/command/DoneCommand.java b/src/main/java/duke/command/DoneCommand.java index 7937cfcf2a..9da9333d8e 100644 --- a/src/main/java/duke/command/DoneCommand.java +++ b/src/main/java/duke/command/DoneCommand.java @@ -1,5 +1,7 @@ package duke.command; +import duke.exception.DukeException; +import duke.exception.ExceptionType; import duke.task.TaskList; import duke.util.Storage; import duke.util.Ui; @@ -20,10 +22,10 @@ public void execute(TaskList tasks, Ui ui, Storage storage) { tasks.getTask(this.taskId).markAsDone(); // mark task as done } catch (InputMismatchException | IndexOutOfBoundsException e) { // user input after "done" is not an int, or is an invalid task ID - ui.showError("Oops! You entered an invalid task ID!"); + ui.showError(new DukeException(ExceptionType.INVALID_ID)); } catch (NoSuchElementException e) { // user input after "done" is blank - ui.showError("Oops! You did not enter a task ID!"); + ui.showError(new DukeException(ExceptionType.ID_BLANK)); } } } diff --git a/src/main/java/duke/command/FindCommand.java b/src/main/java/duke/command/FindCommand.java index d5c1b8785e..6b24f945ef 100644 --- a/src/main/java/duke/command/FindCommand.java +++ b/src/main/java/duke/command/FindCommand.java @@ -1,5 +1,7 @@ package duke.command; +import duke.exception.DukeException; +import duke.exception.ExceptionType; import duke.task.TaskList; import duke.util.Storage; import duke.util.Ui; @@ -16,10 +18,9 @@ public FindCommand(String keyword) { public void execute(TaskList tasks, Ui ui, Storage storage) { TaskList matchingTasks = tasks.findTasks(this.keyword); if (matchingTasks.isEmpty()) { - System.out.println("There are no tasks matching your query :("); + ui.showError(new DukeException(ExceptionType.NO_MATCHING_TASKS)); } else { - System.out.println("Here are the matching tasks in your list:"); - matchingTasks.printList(); + ui.showTasks(matchingTasks); } } } diff --git a/src/main/java/duke/command/ListCommand.java b/src/main/java/duke/command/ListCommand.java index 4c33942bd9..bf796f6ca3 100644 --- a/src/main/java/duke/command/ListCommand.java +++ b/src/main/java/duke/command/ListCommand.java @@ -1,5 +1,7 @@ package duke.command; +import duke.exception.DukeException; +import duke.exception.ExceptionType; import duke.task.TaskList; import duke.util.Storage; import duke.util.Ui; @@ -9,7 +11,7 @@ public class ListCommand implements Command { @Override public void execute(TaskList tasks, Ui ui, Storage storage) { if (tasks.isEmpty()) { - ui.showError("The task list is empty."); + ui.showError(new DukeException(ExceptionType.TASK_LIST_EMPTY)); } tasks.printList(); } diff --git a/src/main/java/duke/exception/DukeException.java b/src/main/java/duke/exception/DukeException.java new file mode 100644 index 0000000000..dd821ec3c9 --- /dev/null +++ b/src/main/java/duke/exception/DukeException.java @@ -0,0 +1,15 @@ +package duke.exception; + +public class DukeException extends Exception { + private ExceptionType exceptionType; + + public DukeException(ExceptionType exceptionType) { + super(); + this.exceptionType = exceptionType; + } + + @Override + public String getMessage() { + return this.exceptionType.getMessage(); + } +} diff --git a/src/main/java/duke/exception/ExceptionType.java b/src/main/java/duke/exception/ExceptionType.java new file mode 100644 index 0000000000..01784a1a5b --- /dev/null +++ b/src/main/java/duke/exception/ExceptionType.java @@ -0,0 +1,20 @@ +package duke.exception; + +public enum ExceptionType { + INVALID_ID("Oops! You entered an invalid task ID!"), + ID_BLANK("Oops! You did not enter a task ID!"), + NO_MATCHING_TASKS("There are no tasks matching your query :("), + TASK_LIST_EMPTY("The task list is empty."), + DESCRIPTION_BLANK("Oops! You did not enter a description!"), + INVALID_COMMAND("Command not recognised!"); + + private final String message; + + ExceptionType(String message) { + this.message = message; + } + + public String getMessage() { + return this.message; + } +} diff --git a/src/main/java/duke/task/TaskList.java b/src/main/java/duke/task/TaskList.java index b1d084ad9e..f6bdd5c1af 100644 --- a/src/main/java/duke/task/TaskList.java +++ b/src/main/java/duke/task/TaskList.java @@ -14,7 +14,6 @@ public TaskList() { tasks = new ArrayList<>(); } - // ideal implementation of addToList public void add(Task task) { tasks.add(task); @@ -27,6 +26,7 @@ public void printList() { for (Task task : tasks) { String s = task.toString(); System.out.println(i + ". " + s); + i++; } } diff --git a/src/main/java/duke/util/DateTime.java b/src/main/java/duke/util/DateTime.java index 595b301834..732155d041 100644 --- a/src/main/java/duke/util/DateTime.java +++ b/src/main/java/duke/util/DateTime.java @@ -9,6 +9,7 @@ public class DateTime { // todo: date format is not implemented correctly private static DateFormat dateFormat = new SimpleDateFormat("dd/mm/YYYY HHmm"); + public static Date parseDate(String date) { Date d = null; try { @@ -20,4 +21,5 @@ public static Date parseDate(String date) { } return d; } + } diff --git a/src/main/java/duke/util/DukeException.java b/src/main/java/duke/util/DukeException.java deleted file mode 100644 index 201da3eeed..0000000000 --- a/src/main/java/duke/util/DukeException.java +++ /dev/null @@ -1,5 +0,0 @@ -package duke.util; - -public class DukeException extends Exception { - -} diff --git a/src/main/java/duke/util/Ui.java b/src/main/java/duke/util/Ui.java index d4469e45f1..19d6c5d922 100644 --- a/src/main/java/duke/util/Ui.java +++ b/src/main/java/duke/util/Ui.java @@ -1,4 +1,6 @@ package duke.util; +import duke.exception.DukeException; +import duke.task.TaskList; import java.util.Scanner; public class Ui { @@ -33,12 +35,16 @@ public void showLine() { System.out.println(line); } - public void showError(String message) { - // todo: use exceptions to abstract out error messages from command classes? - System.out.println(message); + public void showError(DukeException exception) { + System.out.println(exception.getMessage()); } public void showGoodbye() { System.out.println(goodbyeMessage); } + + public void showTasks(TaskList matchingTasks) { + System.out.println("Here are the matching tasks in your list:"); + matchingTasks.printList(); + } } From 901c014453b44dede20880bc46e58f32bfaa9612 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Sun, 29 Sep 2019 12:02:17 +0800 Subject: [PATCH 29/84] identify need for error handling when user enters "todo" without anything after --- src/main/java/duke/command/AddTaskCommand.java | 12 ++++++++++++ src/main/java/duke/util/Parser.java | 7 ++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/main/java/duke/command/AddTaskCommand.java b/src/main/java/duke/command/AddTaskCommand.java index b8998edbef..ce5894e790 100644 --- a/src/main/java/duke/command/AddTaskCommand.java +++ b/src/main/java/duke/command/AddTaskCommand.java @@ -13,6 +13,18 @@ public abstract class AddTaskCommand implements Command { AddTaskCommand(String restOfCommand) { this.restOfCommand = restOfCommand; +// this.s = new Scanner(command); +// String taskTypeString = s.next(); +// +// if (taskTypeString.equals("todo")) { +// return new AddTodoCommand(s.nextLine()); +// } else if (taskTypeString.equals("event")) { +// this.taskType = TaskType.EVENT; +// } else if (taskTypeString.equals("deadline")) { +// this.taskType = TaskType.DEADLINE; +// } else { +// throw new DukeException(ExceptionType.INVALID_COMMAND); +// } } abstract String getDescription(); diff --git a/src/main/java/duke/util/Parser.java b/src/main/java/duke/util/Parser.java index 8f1c92d124..e01f4243a0 100644 --- a/src/main/java/duke/util/Parser.java +++ b/src/main/java/duke/util/Parser.java @@ -20,7 +20,11 @@ public static Command parse(String fullCommand) throws InputMismatchException { } else if (command.equals("delete")) { int taskId = commandReader.nextInt(); return new DeleteCommand(taskId); + } else if (command.equals("find")) { + String keyword = commandReader.nextLine(); + return new FindCommand(keyword); } else if (command.equals("todo")) { + // todo: error handling for empty restOfCommand :( String restOfCommand = commandReader.nextLine(); return new AddTodoCommand(restOfCommand); } else if (command.equals("event")) { @@ -29,9 +33,6 @@ public static Command parse(String fullCommand) throws InputMismatchException { } else if (command.equals("deadline")) { String restOfCommand = commandReader.nextLine(); return new AddDeadlineCommand(restOfCommand); - } else if (command.equals("find")) { - String keyword = commandReader.nextLine(); - return new FindCommand(keyword); } else { throw new InputMismatchException(); } From 51e41e58a8ef0f022312d5cb83933b8561e995dd Mon Sep 17 00:00:00 2001 From: nattanyz Date: Sun, 29 Sep 2019 13:49:29 +0800 Subject: [PATCH 30/84] implement proper exception handling, abstract commonalities of AddTodoCommand, AddEventCommand and AddDeadlineCommand to AddTaskCommand class --- src/main/java/duke/Duke.java | 6 +- .../java/duke/command/AddDeadlineCommand.java | 22 ++---- .../java/duke/command/AddEventCommand.java | 22 ++---- .../java/duke/command/AddTaskCommand.java | 74 +++++++++++++------ .../java/duke/command/AddTodoCommand.java | 18 ++--- src/main/java/duke/command/Command.java | 3 +- src/main/java/duke/command/DeleteCommand.java | 22 ++++-- src/main/java/duke/command/DoneCommand.java | 20 +++-- src/main/java/duke/command/FindCommand.java | 32 +++++--- .../java/duke/exception/ExceptionType.java | 6 +- src/main/java/duke/task/Deadline.java | 8 +- src/main/java/duke/task/Event.java | 6 +- src/main/java/duke/task/Task.java | 4 +- src/main/java/duke/util/Parser.java | 20 ++--- 14 files changed, 151 insertions(+), 112 deletions(-) diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 7e517e225c..d9a9aa68f3 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -2,12 +2,10 @@ import duke.command.Command; import duke.exception.DukeException; -import duke.exception.ExceptionType; import duke.task.TaskList; import duke.util.Parser; import duke.util.Storage; import duke.util.Ui; -import java.util.InputMismatchException; public class Duke { private Storage storage; @@ -35,8 +33,8 @@ private void run() { Command c = Parser.parse(fullCommand); c.execute(tasks, ui, storage); isExit = c.isExit(); - } catch (InputMismatchException e) { - ui.showError(new DukeException(ExceptionType.INVALID_COMMAND)); + } catch (DukeException e) { + ui.showError(e); } finally { ui.showLine(); } diff --git a/src/main/java/duke/command/AddDeadlineCommand.java b/src/main/java/duke/command/AddDeadlineCommand.java index 998de1b568..c2a0c2bd7c 100644 --- a/src/main/java/duke/command/AddDeadlineCommand.java +++ b/src/main/java/duke/command/AddDeadlineCommand.java @@ -1,25 +1,17 @@ package duke.command; +import duke.exception.DukeException; import duke.task.Deadline; import duke.task.Task; -import java.util.Scanner; public class AddDeadlineCommand extends AddTaskCommand { - private Scanner s = new Scanner(restOfCommand); - - public AddDeadlineCommand(String restOfCommand) { - super(restOfCommand); + public AddDeadlineCommand(String command) throws DukeException { + // todo: use enum and then lambda to pass in delimiter + super(command); s.useDelimiter("/by"); - } - - @Override - public String getDescription() { - return this.s.next().strip(); - } - - @Override - public String getDeadline() { - return this.s.next().strip(); + setDescription(); + setDeadlineString(); + setDeadline(); } @Override diff --git a/src/main/java/duke/command/AddEventCommand.java b/src/main/java/duke/command/AddEventCommand.java index 556575b941..c4710ca12a 100644 --- a/src/main/java/duke/command/AddEventCommand.java +++ b/src/main/java/duke/command/AddEventCommand.java @@ -1,25 +1,17 @@ package duke.command; +import duke.exception.DukeException; import duke.task.Event; import duke.task.Task; -import java.util.Scanner; public class AddEventCommand extends AddTaskCommand { - private Scanner s = new Scanner(restOfCommand); - - public AddEventCommand(String restOfCommand) { - super(restOfCommand); + public AddEventCommand(String command) throws DukeException { + // todo: use enum and then lambda to pass in delimiter + super(command); s.useDelimiter("/at"); - } - - @Override - public String getDescription() { - return this.s.next().strip(); - } - - @Override - public String getDeadline() { - return this.s.next().strip(); + setDescription(); + setDeadlineString(); + setDeadline(); } @Override diff --git a/src/main/java/duke/command/AddTaskCommand.java b/src/main/java/duke/command/AddTaskCommand.java index ce5894e790..e9ca6c1321 100644 --- a/src/main/java/duke/command/AddTaskCommand.java +++ b/src/main/java/duke/command/AddTaskCommand.java @@ -6,40 +6,66 @@ import duke.task.TaskList; import duke.util.Storage; import duke.util.Ui; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; import java.util.NoSuchElementException; +import java.util.Scanner; public abstract class AddTaskCommand implements Command { - String restOfCommand; - - AddTaskCommand(String restOfCommand) { - this.restOfCommand = restOfCommand; -// this.s = new Scanner(command); -// String taskTypeString = s.next(); -// -// if (taskTypeString.equals("todo")) { -// return new AddTodoCommand(s.nextLine()); -// } else if (taskTypeString.equals("event")) { -// this.taskType = TaskType.EVENT; -// } else if (taskTypeString.equals("deadline")) { -// this.taskType = TaskType.DEADLINE; -// } else { -// throw new DukeException(ExceptionType.INVALID_COMMAND); -// } + Scanner s; + private String description; + private Date deadline; + private String deadlineString; + // todo: move dateFormatter to somewhere else that makes more sense + private SimpleDateFormat dateFormatter = new SimpleDateFormat("dd/MM/yyyy HHmm"); + + AddTaskCommand(String fullCommand) { + super(); + this.s = new Scanner(fullCommand); + s.next(); // ignore command } - abstract String getDescription(); - abstract String getDeadline(); + String getDescription() { + return this.description; + } - abstract Task createTask(); + Date getDeadline() { + return this.deadline; + } - @Override - public void execute(TaskList tasks, Ui ui, Storage storage) { + void setDescription() throws DukeException { try { - Task newTask = createTask(); - tasks.add(newTask); + this.description = this.s.next().strip(); } catch (NoSuchElementException e) { // user input after task type is blank - ui.showError(new DukeException(ExceptionType.DESCRIPTION_BLANK)); + throw new DukeException(ExceptionType.DESCRIPTION_BLANK); + } + } + + void setDeadlineString() throws DukeException { + try { + this.deadlineString = this.s.next().strip(); + } catch (NoSuchElementException e) { + // no deadline entered + throw new DukeException(ExceptionType.DEADLINE_BLANK); + } + } + + void setDeadline() throws DukeException { + try { + this.deadline = this.dateFormatter.parse(this.deadlineString); + } catch (ParseException e) { + // deadline entered in wrong format + throw new DukeException(ExceptionType.INVALID_DATE); } + }; + + abstract Task createTask(); + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + Task newTask = createTask(); + tasks.add(newTask); } } diff --git a/src/main/java/duke/command/AddTodoCommand.java b/src/main/java/duke/command/AddTodoCommand.java index bba86a9191..7684b3283e 100644 --- a/src/main/java/duke/command/AddTodoCommand.java +++ b/src/main/java/duke/command/AddTodoCommand.java @@ -1,22 +1,20 @@ package duke.command; +import duke.exception.DukeException; import duke.task.Task; import duke.task.Todo; +import java.util.Date; public class AddTodoCommand extends AddTaskCommand { - - public AddTodoCommand(String restOfCommand) { - super(restOfCommand); - } - - @Override - public String getDescription() { - return this.restOfCommand.strip(); + public AddTodoCommand(String fullCommand) throws DukeException { + super(fullCommand); + s.useDelimiter("\n"); // no special delimiter required + setDescription(); } @Override - public String getDeadline() { - return "no deadline"; + Date getDeadline() { + return null; } @Override diff --git a/src/main/java/duke/command/Command.java b/src/main/java/duke/command/Command.java index 552e5089dc..761204128b 100644 --- a/src/main/java/duke/command/Command.java +++ b/src/main/java/duke/command/Command.java @@ -1,11 +1,12 @@ package duke.command; +import duke.exception.DukeException; import duke.task.TaskList; import duke.util.Storage; import duke.util.Ui; public interface Command { - void execute(TaskList tasks, Ui ui, Storage storage); + void execute(TaskList tasks, Ui ui, Storage storage) throws DukeException; // implementation varies for each subclass of Command default boolean isExit() { diff --git a/src/main/java/duke/command/DeleteCommand.java b/src/main/java/duke/command/DeleteCommand.java index 297283bfa5..6ce5c8f1e4 100644 --- a/src/main/java/duke/command/DeleteCommand.java +++ b/src/main/java/duke/command/DeleteCommand.java @@ -8,26 +8,32 @@ import duke.util.Ui; import java.util.InputMismatchException; import java.util.NoSuchElementException; +import java.util.Scanner; public class DeleteCommand implements Command { - private int taskId; - - public DeleteCommand(int taskId) { + private Scanner s; + + public DeleteCommand(String fullCommand) { super(); - this.taskId = taskId; + this.s = new Scanner(fullCommand); } @Override - public void execute(TaskList tasks, Ui ui, Storage storage) { + public void execute(TaskList tasks, Ui ui, Storage storage) throws DukeException { try { + // first, try to get taskId + s.next(); // command (delete), to be ignored + int taskId = s.nextInt(); + + // if ok, delete task Task task = tasks.getTask(taskId); - tasks.deleteTask(task); // mark task as done + tasks.deleteTask(task); } catch (InputMismatchException | IndexOutOfBoundsException e) { // user input after "done" is not an int, or is an invalid task ID - ui.showError(new DukeException(ExceptionType.INVALID_ID)); + throw new DukeException(ExceptionType.INVALID_ID); } catch (NoSuchElementException e) { // user input after "done" is blank - ui.showError(new DukeException(ExceptionType.ID_BLANK)); + throw new DukeException(ExceptionType.ID_BLANK); } } } diff --git a/src/main/java/duke/command/DoneCommand.java b/src/main/java/duke/command/DoneCommand.java index 9da9333d8e..ba843077ac 100644 --- a/src/main/java/duke/command/DoneCommand.java +++ b/src/main/java/duke/command/DoneCommand.java @@ -7,25 +7,31 @@ import duke.util.Ui; import java.util.InputMismatchException; import java.util.NoSuchElementException; +import java.util.Scanner; public class DoneCommand implements Command { - private int taskId; + private Scanner s; - public DoneCommand(int taskId) { + public DoneCommand(String fullCommand) { super(); - this.taskId = taskId; + this.s = new Scanner(fullCommand); } @Override - public void execute(TaskList tasks, Ui ui, Storage storage) { + public void execute(TaskList tasks, Ui ui, Storage storage) throws DukeException { try { - tasks.getTask(this.taskId).markAsDone(); // mark task as done + // first, try to get taskId + s.next(); // command (done), to be ignored + int taskId = s.nextInt(); + + // if ok, mark task as done + tasks.getTask(taskId).markAsDone(); } catch (InputMismatchException | IndexOutOfBoundsException e) { // user input after "done" is not an int, or is an invalid task ID - ui.showError(new DukeException(ExceptionType.INVALID_ID)); + throw new DukeException(ExceptionType.INVALID_ID); } catch (NoSuchElementException e) { // user input after "done" is blank - ui.showError(new DukeException(ExceptionType.ID_BLANK)); + throw new DukeException(ExceptionType.ID_BLANK); } } } diff --git a/src/main/java/duke/command/FindCommand.java b/src/main/java/duke/command/FindCommand.java index 6b24f945ef..cea762131a 100644 --- a/src/main/java/duke/command/FindCommand.java +++ b/src/main/java/duke/command/FindCommand.java @@ -5,22 +5,36 @@ import duke.task.TaskList; import duke.util.Storage; import duke.util.Ui; +import java.util.InputMismatchException; +import java.util.Scanner; public class FindCommand implements Command { - private String keyword; + private Scanner s; - public FindCommand(String keyword) { + public FindCommand(String fullCommand) { super(); - this.keyword = keyword; + this.s = new Scanner(fullCommand); } @Override - public void execute(TaskList tasks, Ui ui, Storage storage) { - TaskList matchingTasks = tasks.findTasks(this.keyword); - if (matchingTasks.isEmpty()) { - ui.showError(new DukeException(ExceptionType.NO_MATCHING_TASKS)); - } else { - ui.showTasks(matchingTasks); + public void execute(TaskList tasks, Ui ui, Storage storage) throws DukeException { + try { + // first, try to get keyword + s.next(); // command (find), to be ignored + String keyword = s.nextLine(); + + // if ok, find and return matching tasks + TaskList matchingTasks = tasks.findTasks(keyword); + if (matchingTasks.isEmpty()) { + throw new DukeException(ExceptionType.NO_MATCHING_TASKS); + } else { + ui.showTasks(matchingTasks); + } + } catch (InputMismatchException e) { + // user input after "find" is empty + throw new DukeException(ExceptionType.KEYWORD_BLANK); } + + } } diff --git a/src/main/java/duke/exception/ExceptionType.java b/src/main/java/duke/exception/ExceptionType.java index 01784a1a5b..deba1a12e2 100644 --- a/src/main/java/duke/exception/ExceptionType.java +++ b/src/main/java/duke/exception/ExceptionType.java @@ -6,7 +6,11 @@ public enum ExceptionType { NO_MATCHING_TASKS("There are no tasks matching your query :("), TASK_LIST_EMPTY("The task list is empty."), DESCRIPTION_BLANK("Oops! You did not enter a description!"), - INVALID_COMMAND("Command not recognised!"); + DEADLINE_BLANK("Oops! You did not enter a deadline!"), + INVALID_COMMAND("Command not recognised!"), + INVALID_DATE("Oops! You did not enter the date in an appropriate format.\n" + + "Try: DD/MM/YYYY HHmm instead."), + KEYWORD_BLANK("Oops! You did not enter a keyword!"); private final String message; diff --git a/src/main/java/duke/task/Deadline.java b/src/main/java/duke/task/Deadline.java index c028b6ae23..3ab63239b9 100644 --- a/src/main/java/duke/task/Deadline.java +++ b/src/main/java/duke/task/Deadline.java @@ -1,12 +1,14 @@ package duke.task; + +import java.util.Date; + public class Deadline extends Task { - private String by; + private Date by; - public Deadline(String description, String by) { + public Deadline(String description, Date by) { super(description); this.by = by; this.type = "D"; - } @Override diff --git a/src/main/java/duke/task/Event.java b/src/main/java/duke/task/Event.java index 7550d8c1dd..efc7eed20d 100644 --- a/src/main/java/duke/task/Event.java +++ b/src/main/java/duke/task/Event.java @@ -1,9 +1,11 @@ package duke.task; +import java.util.Date; + public class Event extends Task { - private String at; + private Date at; - public Event(String description, String at) { + public Event(String description, Date at) { super(description); this.at = at; this.type = "E"; diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java index 8c7855b63a..bc66f51437 100644 --- a/src/main/java/duke/task/Task.java +++ b/src/main/java/duke/task/Task.java @@ -23,7 +23,7 @@ String getDescription() { } private String getStatusIcon() { - return (isDone ? "\u2713" : "\u2718"); // return tick or X symbols + return (isDone ? "Y" : "N"); // return Y or N } public void markAsDone() { @@ -37,4 +37,6 @@ public enum TaskType { EVENT, TODO } + + // todo: use TaskType enum to get type in toString() instead } diff --git a/src/main/java/duke/util/Parser.java b/src/main/java/duke/util/Parser.java index e01f4243a0..9c7a58f218 100644 --- a/src/main/java/duke/util/Parser.java +++ b/src/main/java/duke/util/Parser.java @@ -1,12 +1,13 @@ package duke.util; import duke.command.*; -import java.util.InputMismatchException; +import duke.exception.DukeException; +import duke.exception.ExceptionType; import java.util.Scanner; public class Parser { - public static Command parse(String fullCommand) throws InputMismatchException { + public static Command parse(String fullCommand) throws DukeException { Scanner commandReader = new Scanner(fullCommand); String command = commandReader.next(); @@ -15,18 +16,13 @@ public static Command parse(String fullCommand) throws InputMismatchException { } else if (command.equals("list")) { return new ListCommand(); } else if (command.equals("done")) { - int taskId = commandReader.nextInt(); // extract the task ID entered by user - return new DoneCommand(taskId); + return new DoneCommand(fullCommand); } else if (command.equals("delete")) { - int taskId = commandReader.nextInt(); - return new DeleteCommand(taskId); + return new DeleteCommand(fullCommand); } else if (command.equals("find")) { - String keyword = commandReader.nextLine(); - return new FindCommand(keyword); + return new FindCommand(fullCommand); } else if (command.equals("todo")) { - // todo: error handling for empty restOfCommand :( - String restOfCommand = commandReader.nextLine(); - return new AddTodoCommand(restOfCommand); + return new AddTodoCommand(fullCommand); } else if (command.equals("event")) { String restOfCommand = commandReader.nextLine(); return new AddEventCommand(restOfCommand); @@ -34,7 +30,7 @@ public static Command parse(String fullCommand) throws InputMismatchException { String restOfCommand = commandReader.nextLine(); return new AddDeadlineCommand(restOfCommand); } else { - throw new InputMismatchException(); + throw new DukeException(ExceptionType.INVALID_COMMAND); } } } From 7cffc25939c1caaa0c94b6a7a70e8b160a3c19ca Mon Sep 17 00:00:00 2001 From: nattanyz Date: Sun, 29 Sep 2019 18:42:21 +0800 Subject: [PATCH 31/84] FINALLY, FINALLY implemented Level-7 --- src/main/java/duke/Duke.java | 9 +- src/main/java/duke/command/ExitCommand.java | 1 - .../java/duke/exception/ExceptionType.java | 15 ++- src/main/java/duke/task/Task.java | 6 +- src/main/java/duke/task/TaskList.java | 19 +-- src/main/java/duke/util/Storage.java | 109 ++++++++++-------- 6 files changed, 94 insertions(+), 65 deletions(-) diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index d9a9aa68f3..8153fd8c79 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -15,11 +15,15 @@ public class Duke { public Duke(String filePath) { ui = new Ui(); storage = new Storage(filePath); + tasks = new TaskList(); + try { - tasks = new TaskList(storage.load()); + TaskList tasksFromFile = storage.load(); + tasks = tasksFromFile; } catch (Exception e) { + // temporary haxx + e.printStackTrace(); ui.showLoadingError(); - tasks = new TaskList(); } } @@ -39,6 +43,7 @@ private void run() { ui.showLine(); } } + ui.showGoodbye(); } public static void main(String[] args) { diff --git a/src/main/java/duke/command/ExitCommand.java b/src/main/java/duke/command/ExitCommand.java index dcdc1f7f72..ee76540657 100644 --- a/src/main/java/duke/command/ExitCommand.java +++ b/src/main/java/duke/command/ExitCommand.java @@ -9,7 +9,6 @@ public class ExitCommand implements Command { @Override public void execute(TaskList tasks, Ui ui, Storage storage) { storage.save(tasks); - ui.showGoodbye(); } @Override diff --git a/src/main/java/duke/exception/ExceptionType.java b/src/main/java/duke/exception/ExceptionType.java index deba1a12e2..cbca53c6f2 100644 --- a/src/main/java/duke/exception/ExceptionType.java +++ b/src/main/java/duke/exception/ExceptionType.java @@ -1,16 +1,19 @@ package duke.exception; public enum ExceptionType { + // invalid INVALID_ID("Oops! You entered an invalid task ID!"), - ID_BLANK("Oops! You did not enter a task ID!"), - NO_MATCHING_TASKS("There are no tasks matching your query :("), - TASK_LIST_EMPTY("The task list is empty."), - DESCRIPTION_BLANK("Oops! You did not enter a description!"), - DEADLINE_BLANK("Oops! You did not enter a deadline!"), INVALID_COMMAND("Command not recognised!"), INVALID_DATE("Oops! You did not enter the date in an appropriate format.\n" + "Try: DD/MM/YYYY HHmm instead."), - KEYWORD_BLANK("Oops! You did not enter a keyword!"); + // blank + ID_BLANK("Oops! You did not enter a task ID!"), + DESCRIPTION_BLANK("Oops! You did not enter a description!"), + DEADLINE_BLANK("Oops! You did not enter a deadline!"), + KEYWORD_BLANK("Oops! You did not enter a keyword!"), + // nothing to return + NO_MATCHING_TASKS("There are no tasks matching your query :("), + TASK_LIST_EMPTY("The task list is empty."),; private final String message; diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java index bc66f51437..ee0e978876 100644 --- a/src/main/java/duke/task/Task.java +++ b/src/main/java/duke/task/Task.java @@ -1,12 +1,14 @@ package duke.task; -public class Task { +import java.io.Serializable; + +public abstract class Task implements Serializable { private String description; private Boolean isDone; String type; public Task(String description) { - // todo: modify constructor to create new task from String + // todo: add new constructor to create new task from String this.description = description; this.isDone = false; } diff --git a/src/main/java/duke/task/TaskList.java b/src/main/java/duke/task/TaskList.java index f6bdd5c1af..d97a8323a0 100644 --- a/src/main/java/duke/task/TaskList.java +++ b/src/main/java/duke/task/TaskList.java @@ -1,8 +1,9 @@ package duke.task; +import java.io.Serializable; import java.util.ArrayList; -public class TaskList { +public class TaskList implements Serializable { private ArrayList tasks; @@ -21,6 +22,10 @@ public void add(Task task) { + ". Use list to see all your tasks!"); } +// public void addAll(ArrayList tasks) { +// this.tasks.addAll(tasks); +// } + public void printList() { int i = 1; for (Task task : tasks) { @@ -30,18 +35,14 @@ public void printList() { } } -// public String writeToFile() { -// Task task; -// for (Task task : tasks) { -// String s = task.printToFile(); -// return s; -// } -// } - public Task getTask(int taskIndex) throws IndexOutOfBoundsException { return tasks.get(taskIndex - 1); } + public ArrayList getTasks() { + return this.tasks; + } + public void deleteTask(Task taskToDelete) { String taskDescription = taskToDelete.toString(); tasks.remove(taskToDelete); diff --git a/src/main/java/duke/util/Storage.java b/src/main/java/duke/util/Storage.java index e78c17bf12..1a6eed263f 100644 --- a/src/main/java/duke/util/Storage.java +++ b/src/main/java/duke/util/Storage.java @@ -1,73 +1,92 @@ package duke.util; -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; -import duke.task.Task; import duke.task.TaskList; -import java.io.BufferedReader; -import java.io.BufferedWriter; import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.lang.reflect.Type; -import java.util.ArrayList; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; public class Storage { private String filePath; - private String doneMessage = "Success! Your tasks have been saved to: "; // should be in Ui class? + private String tasksImportedMessage = "Success! Your tasks have been imported from: "; + private String tasksSavedMessage = "Success! Your tasks have been saved to: "; // should be in Ui class? + private String tasksNotSavedMessage = "Your task list is empty! Adios :)"; + private String fileNotFoundMessage = "Existing tasks file not found! Starting duke afresh..."; public Storage(String filePath) { this.filePath = filePath; } - public ArrayList load() { - ArrayList tasks = new ArrayList<>(); - try { - // create buffered reader from file - BufferedReader br = new BufferedReader(new FileReader(this.filePath)); + private boolean hasDirectory() { + // check if parent directory exists. if not, create it + File file = new File(this.filePath); + if (!file.getParentFile().exists()) { + file.getParentFile().mkdirs(); + return false; + } else { + return true; + } + } + private boolean hasFile() { + File file = new File(this.filePath); + + // check if file exists + if (!file.exists()) { + System.out.println(fileNotFoundMessage); + return false; + } + + return true; + } + + public TaskList load() { + TaskList tasks = new TaskList(); + // if directory does not exist, or file does not exist, no need to load from file + if (!hasDirectory() || !hasFile()) { + return tasks; + } + + // for each line in file + // create corresponding task + // add task to list - // create Gson object - Gson gson = new Gson(); + try { + FileInputStream fis = new FileInputStream(this.filePath); + ObjectInputStream ois = new ObjectInputStream(fis); - // create type token to deal with ArrayList - Type taskListType = new TypeToken>(){}.getType(); + tasks = (TaskList) ois.readObject(); - // import tasks from json - tasks = gson.fromJson(br, taskListType); + ois.close(); + fis.close(); - } catch (FileNotFoundException e) { - System.out.println("Existing tasks file not found! Starting duke afresh..."); + System.out.println(tasksImportedMessage); } catch (Exception e) { // temporary haxx e.printStackTrace(); } - return tasks; - } - private Task loadTask(String line) { - // use Task class's constructor from String - Task task = new Task(line); - return task; + return tasks; } public void save(TaskList tasks) { - // create json representation and save to given file + // first, check if task list is empty. if so, do not save + if (tasks.isEmpty()) { + System.out.println(tasksNotSavedMessage); + return; + } + try { - // todo: fix file not found (create file), maybe use FileOutputStream instead - File file = new File(this.filePath); - file.createNewFile(); // result (boolean) is not required - PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file))); - - // create json representation of tasks - Gson gson = new Gson(); - gson.toJson(tasks, pw); - - // print done - System.out.println(doneMessage + filePath); - } catch (IOException e) { + FileOutputStream fos = new FileOutputStream(this.filePath); + ObjectOutputStream oos = new ObjectOutputStream(fos); + + oos.writeObject(tasks); + + oos.close(); + fos.close(); + + System.out.println(tasksSavedMessage + this.filePath); + } catch (Exception e) { // temporary haxx e.printStackTrace(); } From 3413d6b07e054c255d05ddf142a26969f888e8a4 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Sun, 29 Sep 2019 19:03:58 +0800 Subject: [PATCH 32/84] move exception-related classes to util.exception, add UiMessage enum to store ui messages, correct Parser to use fullCommand for events and deadlines --- src/main/java/duke/Duke.java | 8 +++---- .../java/duke/command/AddDeadlineCommand.java | 2 +- .../java/duke/command/AddEventCommand.java | 2 +- .../java/duke/command/AddTaskCommand.java | 4 ++-- .../java/duke/command/AddTodoCommand.java | 2 +- src/main/java/duke/command/Command.java | 2 +- src/main/java/duke/command/DeleteCommand.java | 4 ++-- src/main/java/duke/command/DoneCommand.java | 4 ++-- src/main/java/duke/command/FindCommand.java | 4 ++-- src/main/java/duke/command/ListCommand.java | 4 ++-- src/main/java/duke/util/Parser.java | 10 ++++---- src/main/java/duke/util/Storage.java | 17 ++++++------- src/main/java/duke/util/Ui.java | 19 ++++----------- src/main/java/duke/util/UiMessage.java | 24 +++++++++++++++++++ .../{ => util}/exception/DukeException.java | 2 +- .../{ => util}/exception/ExceptionType.java | 2 +- 16 files changed, 62 insertions(+), 48 deletions(-) create mode 100644 src/main/java/duke/util/UiMessage.java rename src/main/java/duke/{ => util}/exception/DukeException.java (91%) rename src/main/java/duke/{ => util}/exception/ExceptionType.java (96%) diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 8153fd8c79..12cfb1d51b 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -1,7 +1,8 @@ package duke; +import duke.util.UiMessage; import duke.command.Command; -import duke.exception.DukeException; +import duke.util.exception.DukeException; import duke.task.TaskList; import duke.util.Parser; import duke.util.Storage; @@ -23,12 +24,11 @@ public Duke(String filePath) { } catch (Exception e) { // temporary haxx e.printStackTrace(); - ui.showLoadingError(); } } private void run() { - ui.showWelcome(); + ui.showMessage(UiMessage.WELCOME); boolean isExit = false; while (!isExit) { try { @@ -43,7 +43,7 @@ private void run() { ui.showLine(); } } - ui.showGoodbye(); + ui.showMessage(UiMessage.GOODBYE); } public static void main(String[] args) { diff --git a/src/main/java/duke/command/AddDeadlineCommand.java b/src/main/java/duke/command/AddDeadlineCommand.java index c2a0c2bd7c..31e41f7e3f 100644 --- a/src/main/java/duke/command/AddDeadlineCommand.java +++ b/src/main/java/duke/command/AddDeadlineCommand.java @@ -1,6 +1,6 @@ package duke.command; -import duke.exception.DukeException; +import duke.util.exception.DukeException; import duke.task.Deadline; import duke.task.Task; diff --git a/src/main/java/duke/command/AddEventCommand.java b/src/main/java/duke/command/AddEventCommand.java index c4710ca12a..f5cd4e6b60 100644 --- a/src/main/java/duke/command/AddEventCommand.java +++ b/src/main/java/duke/command/AddEventCommand.java @@ -1,6 +1,6 @@ package duke.command; -import duke.exception.DukeException; +import duke.util.exception.DukeException; import duke.task.Event; import duke.task.Task; diff --git a/src/main/java/duke/command/AddTaskCommand.java b/src/main/java/duke/command/AddTaskCommand.java index e9ca6c1321..0553bc34a8 100644 --- a/src/main/java/duke/command/AddTaskCommand.java +++ b/src/main/java/duke/command/AddTaskCommand.java @@ -1,7 +1,7 @@ package duke.command; -import duke.exception.DukeException; -import duke.exception.ExceptionType; +import duke.util.exception.DukeException; +import duke.util.exception.ExceptionType; import duke.task.Task; import duke.task.TaskList; import duke.util.Storage; diff --git a/src/main/java/duke/command/AddTodoCommand.java b/src/main/java/duke/command/AddTodoCommand.java index 7684b3283e..b27c1a8721 100644 --- a/src/main/java/duke/command/AddTodoCommand.java +++ b/src/main/java/duke/command/AddTodoCommand.java @@ -1,6 +1,6 @@ package duke.command; -import duke.exception.DukeException; +import duke.util.exception.DukeException; import duke.task.Task; import duke.task.Todo; import java.util.Date; diff --git a/src/main/java/duke/command/Command.java b/src/main/java/duke/command/Command.java index 761204128b..549b03ae61 100644 --- a/src/main/java/duke/command/Command.java +++ b/src/main/java/duke/command/Command.java @@ -1,6 +1,6 @@ package duke.command; -import duke.exception.DukeException; +import duke.util.exception.DukeException; import duke.task.TaskList; import duke.util.Storage; import duke.util.Ui; diff --git a/src/main/java/duke/command/DeleteCommand.java b/src/main/java/duke/command/DeleteCommand.java index 6ce5c8f1e4..62072f0604 100644 --- a/src/main/java/duke/command/DeleteCommand.java +++ b/src/main/java/duke/command/DeleteCommand.java @@ -1,7 +1,7 @@ package duke.command; -import duke.exception.DukeException; -import duke.exception.ExceptionType; +import duke.util.exception.DukeException; +import duke.util.exception.ExceptionType; import duke.task.Task; import duke.task.TaskList; import duke.util.Storage; diff --git a/src/main/java/duke/command/DoneCommand.java b/src/main/java/duke/command/DoneCommand.java index ba843077ac..cfb742147c 100644 --- a/src/main/java/duke/command/DoneCommand.java +++ b/src/main/java/duke/command/DoneCommand.java @@ -1,7 +1,7 @@ package duke.command; -import duke.exception.DukeException; -import duke.exception.ExceptionType; +import duke.util.exception.DukeException; +import duke.util.exception.ExceptionType; import duke.task.TaskList; import duke.util.Storage; import duke.util.Ui; diff --git a/src/main/java/duke/command/FindCommand.java b/src/main/java/duke/command/FindCommand.java index cea762131a..9a5d2322dc 100644 --- a/src/main/java/duke/command/FindCommand.java +++ b/src/main/java/duke/command/FindCommand.java @@ -1,7 +1,7 @@ package duke.command; -import duke.exception.DukeException; -import duke.exception.ExceptionType; +import duke.util.exception.DukeException; +import duke.util.exception.ExceptionType; import duke.task.TaskList; import duke.util.Storage; import duke.util.Ui; diff --git a/src/main/java/duke/command/ListCommand.java b/src/main/java/duke/command/ListCommand.java index bf796f6ca3..60d013f0d3 100644 --- a/src/main/java/duke/command/ListCommand.java +++ b/src/main/java/duke/command/ListCommand.java @@ -1,7 +1,7 @@ package duke.command; -import duke.exception.DukeException; -import duke.exception.ExceptionType; +import duke.util.exception.DukeException; +import duke.util.exception.ExceptionType; import duke.task.TaskList; import duke.util.Storage; import duke.util.Ui; diff --git a/src/main/java/duke/util/Parser.java b/src/main/java/duke/util/Parser.java index 9c7a58f218..e68b708da8 100644 --- a/src/main/java/duke/util/Parser.java +++ b/src/main/java/duke/util/Parser.java @@ -1,8 +1,8 @@ package duke.util; import duke.command.*; -import duke.exception.DukeException; -import duke.exception.ExceptionType; +import duke.util.exception.DukeException; +import duke.util.exception.ExceptionType; import java.util.Scanner; public class Parser { @@ -24,11 +24,9 @@ public static Command parse(String fullCommand) throws DukeException { } else if (command.equals("todo")) { return new AddTodoCommand(fullCommand); } else if (command.equals("event")) { - String restOfCommand = commandReader.nextLine(); - return new AddEventCommand(restOfCommand); + return new AddEventCommand(fullCommand); } else if (command.equals("deadline")) { - String restOfCommand = commandReader.nextLine(); - return new AddDeadlineCommand(restOfCommand); + return new AddDeadlineCommand(fullCommand); } else { throw new DukeException(ExceptionType.INVALID_COMMAND); } diff --git a/src/main/java/duke/util/Storage.java b/src/main/java/duke/util/Storage.java index 1a6eed263f..fae09e0bde 100644 --- a/src/main/java/duke/util/Storage.java +++ b/src/main/java/duke/util/Storage.java @@ -12,7 +12,7 @@ public class Storage { private String tasksImportedMessage = "Success! Your tasks have been imported from: "; private String tasksSavedMessage = "Success! Your tasks have been saved to: "; // should be in Ui class? private String tasksNotSavedMessage = "Your task list is empty! Adios :)"; - private String fileNotFoundMessage = "Existing tasks file not found! Starting duke afresh..."; + private String tasksNotFoundMessage = "Existing tasks file not found! Starting duke afresh..."; public Storage(String filePath) { this.filePath = filePath; @@ -33,7 +33,8 @@ private boolean hasFile() { // check if file exists if (!file.exists()) { - System.out.println(fileNotFoundMessage); + // todo: replace with showMessage(UiMessage.TASKS_NOT_FOUND) + System.out.println(tasksNotFoundMessage); return false; } @@ -47,12 +48,8 @@ public TaskList load() { return tasks; } - // for each line in file - // create corresponding task - // add task to list - try { - FileInputStream fis = new FileInputStream(this.filePath); + FileInputStream fis = new FileInputStream(filePath); ObjectInputStream ois = new ObjectInputStream(fis); tasks = (TaskList) ois.readObject(); @@ -60,7 +57,8 @@ public TaskList load() { ois.close(); fis.close(); - System.out.println(tasksImportedMessage); + // todo: replace with showMessage(UiMessage.TASKS_IMPORTED) + System.out.println(tasksImportedMessage + filePath); } catch (Exception e) { // temporary haxx e.printStackTrace(); @@ -72,6 +70,7 @@ public TaskList load() { public void save(TaskList tasks) { // first, check if task list is empty. if so, do not save if (tasks.isEmpty()) { + // todo: replace with showMessage(UiMessage.TASKS_NOT_SAVED) System.out.println(tasksNotSavedMessage); return; } @@ -85,6 +84,8 @@ public void save(TaskList tasks) { oos.close(); fos.close(); + // todo: replace with showMessage(UiMessage.TASKS_SAVED) + // how to pass filePath to Ui? System.out.println(tasksSavedMessage + this.filePath); } catch (Exception e) { // temporary haxx diff --git a/src/main/java/duke/util/Ui.java b/src/main/java/duke/util/Ui.java index 19d6c5d922..11a31c7b81 100644 --- a/src/main/java/duke/util/Ui.java +++ b/src/main/java/duke/util/Ui.java @@ -1,11 +1,10 @@ package duke.util; -import duke.exception.DukeException; +import duke.util.exception.DukeException; import duke.task.TaskList; import java.util.Scanner; public class Ui { private Scanner in; - private String loadingErrorMessage = "Oh no! Could not load tasks from file :("; private String logo = " ____ _ \n" + "| _ \\ _ _| | _____ \n" + "| | | | | | | |/ / _ \\\n" @@ -18,14 +17,6 @@ public Ui() { this.in = new Scanner(System.in); } - public void showLoadingError() { - System.out.println(loadingErrorMessage); - } - - public void showWelcome() { - System.out.println(welcomeMessage); - } - public String readCommand() { return in.nextLine(); } @@ -35,12 +26,12 @@ public void showLine() { System.out.println(line); } - public void showError(DukeException exception) { - System.out.println(exception.getMessage()); + public void showMessage(UiMessage uiMessage) { + System.out.println(uiMessage.getMessage()); } - public void showGoodbye() { - System.out.println(goodbyeMessage); + public void showError(DukeException exception) { + System.out.println(exception.getMessage()); } public void showTasks(TaskList matchingTasks) { diff --git a/src/main/java/duke/util/UiMessage.java b/src/main/java/duke/util/UiMessage.java new file mode 100644 index 0000000000..4b9bbae72c --- /dev/null +++ b/src/main/java/duke/util/UiMessage.java @@ -0,0 +1,24 @@ +package duke.util; + +public enum UiMessage { + // greetings + WELCOME("Hello! What can I do for you?"), + GOODBYE("Bye. Hope to see you again soon!"), + // storage + TASKS_IMPORTED("Success! Your tasks have been imported from: "), + TASKS_SAVED("Success! Your tasks have been saved to: "), + TASKS_NOT_SAVED("Your task list is empty! Adios :)"), + TASKS_NOT_FOUND("Existing tasks file not found! Starting duke afresh..."), + // miscellaneous + LINE("____________________________________________________________"); + + private final String message; + + UiMessage(String message) { + this.message = message; + } + + public String getMessage() { + return this.message; + } +} diff --git a/src/main/java/duke/exception/DukeException.java b/src/main/java/duke/util/exception/DukeException.java similarity index 91% rename from src/main/java/duke/exception/DukeException.java rename to src/main/java/duke/util/exception/DukeException.java index dd821ec3c9..1e0cabc950 100644 --- a/src/main/java/duke/exception/DukeException.java +++ b/src/main/java/duke/util/exception/DukeException.java @@ -1,4 +1,4 @@ -package duke.exception; +package duke.util.exception; public class DukeException extends Exception { private ExceptionType exceptionType; diff --git a/src/main/java/duke/exception/ExceptionType.java b/src/main/java/duke/util/exception/ExceptionType.java similarity index 96% rename from src/main/java/duke/exception/ExceptionType.java rename to src/main/java/duke/util/exception/ExceptionType.java index cbca53c6f2..3ff7d5ffb0 100644 --- a/src/main/java/duke/exception/ExceptionType.java +++ b/src/main/java/duke/util/exception/ExceptionType.java @@ -1,4 +1,4 @@ -package duke.exception; +package duke.util.exception; public enum ExceptionType { // invalid From 3988b1dbaeba025543982d2c703ea6cfcbedec8f Mon Sep 17 00:00:00 2001 From: nattanyz Date: Sun, 29 Sep 2019 19:05:32 +0800 Subject: [PATCH 33/84] update gitignore to ignore data files --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 99712178bf..c2f5aa01a2 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,6 @@ src/main/resources/docs/ .DS_Store *.iml bin/ + +# Data files +/data/ From 66a1ab53e4a335f330ccfe4c312a0128dfe9b650 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Sun, 29 Sep 2019 19:55:17 +0800 Subject: [PATCH 34/84] remove Storage param from execute() method, remove Gson from build.gradle, remove unused attributes in Ui class, add some Javadoc --- build.gradle | 1 - src/main/java/duke/Duke.java | 6 +- .../java/duke/command/AddTaskCommand.java | 7 +- src/main/java/duke/command/Command.java | 17 ++++- src/main/java/duke/command/DeleteCommand.java | 3 +- src/main/java/duke/command/DoneCommand.java | 3 +- src/main/java/duke/command/ExitCommand.java | 12 ++- src/main/java/duke/command/FindCommand.java | 12 ++- src/main/java/duke/command/ListCommand.java | 3 +- src/main/java/duke/task/TaskList.java | 76 ++++++++++++++----- src/main/java/duke/util/Ui.java | 25 ++++-- 11 files changed, 122 insertions(+), 43 deletions(-) diff --git a/build.gradle b/build.gradle index 529d16923a..9d0f784119 100644 --- a/build.gradle +++ b/build.gradle @@ -19,7 +19,6 @@ run { } dependencies { - implementation 'com.google.code.gson:gson:2.8.5' testImplementation 'org.junit.jupiter:junit-jupiter:5.5.0' } diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 12cfb1d51b..25c1ac00a0 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -18,6 +18,8 @@ public Duke(String filePath) { storage = new Storage(filePath); tasks = new TaskList(); + ui.showMessage(UiMessage.WELCOME); + try { TaskList tasksFromFile = storage.load(); tasks = tasksFromFile; @@ -28,14 +30,13 @@ public Duke(String filePath) { } private void run() { - ui.showMessage(UiMessage.WELCOME); boolean isExit = false; while (!isExit) { try { String fullCommand = ui.readCommand(); ui.showLine(); // show the divider line ("_______") Command c = Parser.parse(fullCommand); - c.execute(tasks, ui, storage); + c.execute(tasks, ui); isExit = c.isExit(); } catch (DukeException e) { ui.showError(e); @@ -43,6 +44,7 @@ private void run() { ui.showLine(); } } + storage.save(tasks); ui.showMessage(UiMessage.GOODBYE); } diff --git a/src/main/java/duke/command/AddTaskCommand.java b/src/main/java/duke/command/AddTaskCommand.java index 0553bc34a8..806df68ecd 100644 --- a/src/main/java/duke/command/AddTaskCommand.java +++ b/src/main/java/duke/command/AddTaskCommand.java @@ -4,7 +4,6 @@ import duke.util.exception.ExceptionType; import duke.task.Task; import duke.task.TaskList; -import duke.util.Storage; import duke.util.Ui; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -64,8 +63,12 @@ void setDeadline() throws DukeException { abstract Task createTask(); @Override - public void execute(TaskList tasks, Ui ui, Storage storage) { + public void execute(TaskList tasks, Ui ui) { Task newTask = createTask(); tasks.add(newTask); + + // todo: use UiMessage + System.out.println("Okay! I've added: " + getDescription() + + ". Use list to see all your tasks!"); } } diff --git a/src/main/java/duke/command/Command.java b/src/main/java/duke/command/Command.java index 549b03ae61..00705113ab 100644 --- a/src/main/java/duke/command/Command.java +++ b/src/main/java/duke/command/Command.java @@ -2,13 +2,26 @@ import duke.util.exception.DukeException; import duke.task.TaskList; -import duke.util.Storage; import duke.util.Ui; +/** + * Interface for commands, containing execute() method and isExit() boolean. + */ public interface Command { - void execute(TaskList tasks, Ui ui, Storage storage) throws DukeException; + + /** + * Performs command, by interacting with tasks and UI. + * @param tasks List of tasks. + * @param ui UI to display to the user. + * @throws DukeException Application-specific exception thrown during execution. + */ + void execute(TaskList tasks, Ui ui) throws DukeException; // implementation varies for each subclass of Command + /** + * Returns boolean indicating if command entered was "exit", false by default. + * @return boolean indicating if command entered was "exit". + */ default boolean isExit() { return false; } diff --git a/src/main/java/duke/command/DeleteCommand.java b/src/main/java/duke/command/DeleteCommand.java index 62072f0604..e0bd402738 100644 --- a/src/main/java/duke/command/DeleteCommand.java +++ b/src/main/java/duke/command/DeleteCommand.java @@ -4,7 +4,6 @@ import duke.util.exception.ExceptionType; import duke.task.Task; import duke.task.TaskList; -import duke.util.Storage; import duke.util.Ui; import java.util.InputMismatchException; import java.util.NoSuchElementException; @@ -19,7 +18,7 @@ public DeleteCommand(String fullCommand) { } @Override - public void execute(TaskList tasks, Ui ui, Storage storage) throws DukeException { + public void execute(TaskList tasks, Ui ui) throws DukeException { try { // first, try to get taskId s.next(); // command (delete), to be ignored diff --git a/src/main/java/duke/command/DoneCommand.java b/src/main/java/duke/command/DoneCommand.java index cfb742147c..fb7cc4fa9d 100644 --- a/src/main/java/duke/command/DoneCommand.java +++ b/src/main/java/duke/command/DoneCommand.java @@ -3,7 +3,6 @@ import duke.util.exception.DukeException; import duke.util.exception.ExceptionType; import duke.task.TaskList; -import duke.util.Storage; import duke.util.Ui; import java.util.InputMismatchException; import java.util.NoSuchElementException; @@ -18,7 +17,7 @@ public DoneCommand(String fullCommand) { } @Override - public void execute(TaskList tasks, Ui ui, Storage storage) throws DukeException { + public void execute(TaskList tasks, Ui ui) throws DukeException { try { // first, try to get taskId s.next(); // command (done), to be ignored diff --git a/src/main/java/duke/command/ExitCommand.java b/src/main/java/duke/command/ExitCommand.java index ee76540657..704bac42c4 100644 --- a/src/main/java/duke/command/ExitCommand.java +++ b/src/main/java/duke/command/ExitCommand.java @@ -1,16 +1,22 @@ package duke.command; import duke.task.TaskList; -import duke.util.Storage; import duke.util.Ui; +/** + * Exits the application. + */ public class ExitCommand implements Command { @Override - public void execute(TaskList tasks, Ui ui, Storage storage) { - storage.save(tasks); + public void execute(TaskList tasks, Ui ui) { + // do nothing } + /** + * Returns boolean indicating if command entered was "exit", true in this case. + * @return boolean indicating if command entered was "exit". + */ @Override public boolean isExit() { return true; diff --git a/src/main/java/duke/command/FindCommand.java b/src/main/java/duke/command/FindCommand.java index 9a5d2322dc..1a0a50328f 100644 --- a/src/main/java/duke/command/FindCommand.java +++ b/src/main/java/duke/command/FindCommand.java @@ -3,7 +3,6 @@ import duke.util.exception.DukeException; import duke.util.exception.ExceptionType; import duke.task.TaskList; -import duke.util.Storage; import duke.util.Ui; import java.util.InputMismatchException; import java.util.Scanner; @@ -11,13 +10,21 @@ public class FindCommand implements Command { private Scanner s; + /** + * @param fullCommand Command that was entered by the user. + */ public FindCommand(String fullCommand) { super(); this.s = new Scanner(fullCommand); } + /** + * @param tasks List of tasks. + * @param ui UI to display to the user. + * @throws DukeException Application-specific exception thrown during execution. + */ @Override - public void execute(TaskList tasks, Ui ui, Storage storage) throws DukeException { + public void execute(TaskList tasks, Ui ui) throws DukeException { try { // first, try to get keyword s.next(); // command (find), to be ignored @@ -25,6 +32,7 @@ public void execute(TaskList tasks, Ui ui, Storage storage) throws DukeException // if ok, find and return matching tasks TaskList matchingTasks = tasks.findTasks(keyword); + // todo: find tasks does not return taskId of original tasks if (matchingTasks.isEmpty()) { throw new DukeException(ExceptionType.NO_MATCHING_TASKS); } else { diff --git a/src/main/java/duke/command/ListCommand.java b/src/main/java/duke/command/ListCommand.java index 60d013f0d3..e19bd9c7fc 100644 --- a/src/main/java/duke/command/ListCommand.java +++ b/src/main/java/duke/command/ListCommand.java @@ -3,13 +3,12 @@ import duke.util.exception.DukeException; import duke.util.exception.ExceptionType; import duke.task.TaskList; -import duke.util.Storage; import duke.util.Ui; public class ListCommand implements Command { @Override - public void execute(TaskList tasks, Ui ui, Storage storage) { + public void execute(TaskList tasks, Ui ui) { if (tasks.isEmpty()) { ui.showError(new DukeException(ExceptionType.TASK_LIST_EMPTY)); } diff --git a/src/main/java/duke/task/TaskList.java b/src/main/java/duke/task/TaskList.java index d97a8323a0..6eae42d6fb 100644 --- a/src/main/java/duke/task/TaskList.java +++ b/src/main/java/duke/task/TaskList.java @@ -3,57 +3,99 @@ import java.io.Serializable; import java.util.ArrayList; +/** + * List of tasks in the application. + */ public class TaskList implements Serializable { + /** ArrayList containing tasks in the TaskList. */ private ArrayList tasks; + /** + * Constructs a new TaskList containing the tasks in the list provided. + * @param tasks ArrayList containing the tasks to be included in the new TaskList. + */ public TaskList(ArrayList tasks) { this.tasks = tasks; } + /** + * Constructs a new, empty TaskList. + */ public TaskList() { tasks = new ArrayList<>(); } - public void add(Task task) { - tasks.add(task); + /** + * Returns ArrayList containing the tasks in the TaskList. + * @return ArrayList containing the tasks in the TaskList. + */ + public ArrayList getTasks() { + return this.tasks; + } - System.out.println("Okay! I've added: " + task.getDescription() - + ". Use list to see all your tasks!"); + /** + * Returns true if the TaskList does not contain any tasks. + * @return True if the TaskList does not contain any tasks. + */ + public boolean isEmpty() { + return tasks.isEmpty(); } -// public void addAll(ArrayList tasks) { -// this.tasks.addAll(tasks); -// } + /** + * Adds a new task to the list. + * @param task New task to be added to the list. + */ + public void add(Task task) { + tasks.add(task); + } + /** + * Prints the list of tasks to the UI. + */ public void printList() { - int i = 1; for (Task task : tasks) { + int i = getId(task); String s = task.toString(); System.out.println(i + ". " + s); - i++; } } - public Task getTask(int taskIndex) throws IndexOutOfBoundsException { - return tasks.get(taskIndex - 1); + /** + * Returns the ID of the given task, in the main TaskList. + * Helper function for printList() and deleteTask() methods. + * @param task Task whose ID is required. + * @return ID of the given task. + */ + private int getId(Task task) { + // todo: change to return ID in the main TaskList, rather than a sublist + return tasks.indexOf(task) + 1; } - public ArrayList getTasks() { - return this.tasks; + /** + * Returns the task with the given ID in the main TaskList. + * @param taskId ID of the task. + * @return Task with the given ID. + * @throws IndexOutOfBoundsException Exception thrown when the given ID is not present in + * the TaskList. + */ + public Task getTask(int taskId) throws IndexOutOfBoundsException { + return tasks.get(taskId - 1); } + /** + * Deletes the given task from the TaskList. + * @param taskToDelete Task to be deleted from the TaskList. + */ public void deleteTask(Task taskToDelete) { + // todo: change to use taskID instead of task String taskDescription = taskToDelete.toString(); tasks.remove(taskToDelete); System.out.println("Noted. I've removed this task: " + taskDescription); System.out.println("Now you have " + tasks.size() + " items in this list."); } - public boolean isEmpty() { - return tasks.isEmpty(); - } - + // todo: javadoc public TaskList findTasks(String keyword) { TaskList matchingTasks = new TaskList(); for (Task task : tasks) { diff --git a/src/main/java/duke/util/Ui.java b/src/main/java/duke/util/Ui.java index 11a31c7b81..b861fd852e 100644 --- a/src/main/java/duke/util/Ui.java +++ b/src/main/java/duke/util/Ui.java @@ -1,35 +1,44 @@ package duke.util; -import duke.util.exception.DukeException; + import duke.task.TaskList; +import duke.util.exception.DukeException; import java.util.Scanner; public class Ui { private Scanner in; - private String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - private String welcomeMessage = "Hello from \n" + logo + "What can I do for you?"; - private String goodbyeMessage = "Bye. Hope to see you again soon!"; public Ui() { this.in = new Scanner(System.in); } + /** + * Returns the command entered by the user. + * @return Command entered by the user. + */ public String readCommand() { return in.nextLine(); } + /** + * Displays a divider line in the UI. + */ public void showLine() { String line = "____________________________________________________________"; System.out.println(line); } + /** + * Displays the required message in the UI, given the type of message required. + * @param uiMessage Enum indicating type of message required to be displayed. + */ public void showMessage(UiMessage uiMessage) { System.out.println(uiMessage.getMessage()); } + /** + * Displays the required error message in the UI, given the type of exception thrown. + * @param exception Exception thrown by the application. + */ public void showError(DukeException exception) { System.out.println(exception.getMessage()); } From f3fbba23b163a3b5eaa254aeb7234d44b3b6514d Mon Sep 17 00:00:00 2001 From: nattanyz Date: Sun, 29 Sep 2019 22:28:07 +0800 Subject: [PATCH 35/84] add TaskType enum to use in Task and related classes, remove redundant getDescription() method in Task class, add taskList param to getId() method, change deleteTask() method to use taskId as param --- src/main/java/duke/Duke.java | 1 + src/main/java/duke/command/DeleteCommand.java | 8 ++-- src/main/java/duke/task/Deadline.java | 2 +- src/main/java/duke/task/Event.java | 2 +- src/main/java/duke/task/Task.java | 20 ++-------- src/main/java/duke/task/TaskList.java | 26 ++++++++----- src/main/java/duke/task/TaskType.java | 37 +++++++++++++++++++ src/main/java/duke/task/Todo.java | 2 +- 8 files changed, 63 insertions(+), 35 deletions(-) create mode 100644 src/main/java/duke/task/TaskType.java diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 25c1ac00a0..f5f3da7a13 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -35,6 +35,7 @@ private void run() { try { String fullCommand = ui.readCommand(); ui.showLine(); // show the divider line ("_______") + // todo: remove redundant showLine() for bye command Command c = Parser.parse(fullCommand); c.execute(tasks, ui); isExit = c.isExit(); diff --git a/src/main/java/duke/command/DeleteCommand.java b/src/main/java/duke/command/DeleteCommand.java index e0bd402738..d07d8478e3 100644 --- a/src/main/java/duke/command/DeleteCommand.java +++ b/src/main/java/duke/command/DeleteCommand.java @@ -1,10 +1,9 @@ package duke.command; -import duke.util.exception.DukeException; -import duke.util.exception.ExceptionType; -import duke.task.Task; import duke.task.TaskList; import duke.util.Ui; +import duke.util.exception.DukeException; +import duke.util.exception.ExceptionType; import java.util.InputMismatchException; import java.util.NoSuchElementException; import java.util.Scanner; @@ -25,8 +24,7 @@ public void execute(TaskList tasks, Ui ui) throws DukeException { int taskId = s.nextInt(); // if ok, delete task - Task task = tasks.getTask(taskId); - tasks.deleteTask(task); + tasks.deleteTask(taskId); } catch (InputMismatchException | IndexOutOfBoundsException e) { // user input after "done" is not an int, or is an invalid task ID throw new DukeException(ExceptionType.INVALID_ID); diff --git a/src/main/java/duke/task/Deadline.java b/src/main/java/duke/task/Deadline.java index 3ab63239b9..eb7a22c62d 100644 --- a/src/main/java/duke/task/Deadline.java +++ b/src/main/java/duke/task/Deadline.java @@ -8,7 +8,7 @@ public class Deadline extends Task { public Deadline(String description, Date by) { super(description); this.by = by; - this.type = "D"; + this.type = TaskType.DEADLINE; } @Override diff --git a/src/main/java/duke/task/Event.java b/src/main/java/duke/task/Event.java index efc7eed20d..f35a8c2375 100644 --- a/src/main/java/duke/task/Event.java +++ b/src/main/java/duke/task/Event.java @@ -8,7 +8,7 @@ public class Event extends Task { public Event(String description, Date at) { super(description); this.at = at; - this.type = "E"; + this.type = TaskType.EVENT; } @Override diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java index ee0e978876..6cd1599e43 100644 --- a/src/main/java/duke/task/Task.java +++ b/src/main/java/duke/task/Task.java @@ -4,26 +4,20 @@ public abstract class Task implements Serializable { private String description; - private Boolean isDone; - String type; + private Boolean isDone = false; + TaskType type; public Task(String description) { - // todo: add new constructor to create new task from String this.description = description; - this.isDone = false; } @Override public String toString() { - String type = "[" + this.type + "] "; + String type = "[" + this.type.getTaskTypeInitial() + "] "; String status = "[" + this.getStatusIcon() + "] "; return type + status + this.description; } - String getDescription() { - return this.description; - } - private String getStatusIcon() { return (isDone ? "Y" : "N"); // return Y or N } @@ -33,12 +27,4 @@ public void markAsDone() { System.out.println("Nice! I've marked this task as done:"); System.out.println(this.toString()); } - - public enum TaskType { - DEADLINE, - EVENT, - TODO - } - - // todo: use TaskType enum to get type in toString() instead } diff --git a/src/main/java/duke/task/TaskList.java b/src/main/java/duke/task/TaskList.java index 6eae42d6fb..5a91bab1ce 100644 --- a/src/main/java/duke/task/TaskList.java +++ b/src/main/java/duke/task/TaskList.java @@ -53,23 +53,23 @@ public void add(Task task) { /** * Prints the list of tasks to the UI. */ + // todo: move to Ui class public void printList() { for (Task task : tasks) { - int i = getId(task); + int i = getId(task, this); String s = task.toString(); System.out.println(i + ". " + s); } } /** - * Returns the ID of the given task, in the main TaskList. - * Helper function for printList() and deleteTask() methods. + * Returns the ID of the given task, in the given TaskList. + * Helper function for printList() method. * @param task Task whose ID is required. * @return ID of the given task. */ - private int getId(Task task) { - // todo: change to return ID in the main TaskList, rather than a sublist - return tasks.indexOf(task) + 1; + private int getId(Task task, TaskList taskList) { + return taskList.tasks.indexOf(task) + 1; } /** @@ -85,18 +85,24 @@ public Task getTask(int taskId) throws IndexOutOfBoundsException { /** * Deletes the given task from the TaskList. - * @param taskToDelete Task to be deleted from the TaskList. + * @param taskId ID of task to be deleted from the TaskList. */ - public void deleteTask(Task taskToDelete) { - // todo: change to use taskID instead of task + public void deleteTask(int taskId) { + Task taskToDelete = getTask(taskId); String taskDescription = taskToDelete.toString(); tasks.remove(taskToDelete); System.out.println("Noted. I've removed this task: " + taskDescription); System.out.println("Now you have " + tasks.size() + " items in this list."); } - // todo: javadoc + /** + * Returns a TaskList containing tasks that match the given keyword. + * @param keyword Keyword to be used to find tasks. + * @return TaskList containing tasks that match the given keyword. + */ public TaskList findTasks(String keyword) { + // todo: is it possible to implement without creating temporary TaskList object? + // so that the numbering of the tasks based on the original list can be preserved TaskList matchingTasks = new TaskList(); for (Task task : tasks) { if (task.toString().contains(keyword)) { diff --git a/src/main/java/duke/task/TaskType.java b/src/main/java/duke/task/TaskType.java new file mode 100644 index 0000000000..06350372bb --- /dev/null +++ b/src/main/java/duke/task/TaskType.java @@ -0,0 +1,37 @@ +package duke.task; + +public enum TaskType { + DEADLINE("by", "D"), + EVENT("at", "E"), + TODO("\n", "T"), + INVALID(null, null); + + private final String delimiter; + private final String initial; + + TaskType(String delimiter, String initial) { + this.delimiter = delimiter; + this.initial = initial; + } + + public String getDelimiter() { + return this.delimiter; + } + + public TaskType getTaskType(String taskTypeString) { + switch (taskTypeString) { + case "todo": + return TaskType.TODO; + case "event": + return TaskType.EVENT; + case "deadline": + return TaskType.DEADLINE; + default: + return TaskType.INVALID; + } + } + + public String getTaskTypeInitial() { + return this.initial; + } +} diff --git a/src/main/java/duke/task/Todo.java b/src/main/java/duke/task/Todo.java index e75ac4ef13..2ca94fed7b 100644 --- a/src/main/java/duke/task/Todo.java +++ b/src/main/java/duke/task/Todo.java @@ -3,6 +3,6 @@ public class Todo extends Task { public Todo(String description) { super(description); - this.type = "T"; + this.type = TaskType.TODO; } } From 003af61182fe2b29a9817cb0bedc9fc81c5d660a Mon Sep 17 00:00:00 2001 From: nattanyz Date: Sun, 29 Sep 2019 22:59:42 +0800 Subject: [PATCH 36/84] add and edit JavaDoc for all Command classes and Enums --- .../java/duke/command/AddDeadlineCommand.java | 3 ++ .../java/duke/command/AddEventCommand.java | 3 ++ .../java/duke/command/AddTaskCommand.java | 35 +++++++++++++++++++ .../java/duke/command/AddTodoCommand.java | 3 ++ src/main/java/duke/command/Command.java | 5 +-- src/main/java/duke/command/DeleteCommand.java | 10 ++++++ src/main/java/duke/command/DoneCommand.java | 13 +++++++ src/main/java/duke/command/ExitCommand.java | 5 +++ src/main/java/duke/command/FindCommand.java | 6 ++-- src/main/java/duke/command/ListCommand.java | 10 ++++-- src/main/java/duke/task/Deadline.java | 14 ++++++++ src/main/java/duke/task/Event.java | 14 ++++++++ src/main/java/duke/task/Task.java | 20 +++++++++++ src/main/java/duke/task/TaskList.java | 10 +++--- src/main/java/duke/task/TaskType.java | 19 ++++++++++ src/main/java/duke/util/UiMessage.java | 7 ++++ .../duke/util/exception/ExceptionType.java | 7 ++++ 17 files changed, 172 insertions(+), 12 deletions(-) diff --git a/src/main/java/duke/command/AddDeadlineCommand.java b/src/main/java/duke/command/AddDeadlineCommand.java index 31e41f7e3f..37397e87a8 100644 --- a/src/main/java/duke/command/AddDeadlineCommand.java +++ b/src/main/java/duke/command/AddDeadlineCommand.java @@ -4,6 +4,9 @@ import duke.task.Deadline; import duke.task.Task; +/** + * Represents a command to create and add a Deadline task. + */ public class AddDeadlineCommand extends AddTaskCommand { public AddDeadlineCommand(String command) throws DukeException { // todo: use enum and then lambda to pass in delimiter diff --git a/src/main/java/duke/command/AddEventCommand.java b/src/main/java/duke/command/AddEventCommand.java index f5cd4e6b60..4dc2a5154b 100644 --- a/src/main/java/duke/command/AddEventCommand.java +++ b/src/main/java/duke/command/AddEventCommand.java @@ -4,6 +4,9 @@ import duke.task.Event; import duke.task.Task; +/** + * Represents a command to create and add an Event task. + */ public class AddEventCommand extends AddTaskCommand { public AddEventCommand(String command) throws DukeException { // todo: use enum and then lambda to pass in delimiter diff --git a/src/main/java/duke/command/AddTaskCommand.java b/src/main/java/duke/command/AddTaskCommand.java index 806df68ecd..d4fde96ae0 100644 --- a/src/main/java/duke/command/AddTaskCommand.java +++ b/src/main/java/duke/command/AddTaskCommand.java @@ -11,6 +11,9 @@ import java.util.NoSuchElementException; import java.util.Scanner; +/** + * Represents a command to add a new task to the list of tasks. + */ public abstract class AddTaskCommand implements Command { Scanner s; private String description; @@ -25,14 +28,28 @@ public abstract class AddTaskCommand implements Command { s.next(); // ignore command } + /** + * Returns the description of the task to be added. + * @return Description of the task to be added. + */ String getDescription() { return this.description; } + /** + * Returns the deadline of the task to be added. + * For Deadline tasks, this refers to the expected date of completion. + * For Event tasks, this refers to the expected date of occurrence. + * @return Deadline of the task to be added. + */ Date getDeadline() { return this.deadline; } + /** + * Retrieves the description of the task to be added, based on command issued by user. + * @throws DukeException Application-specific exception thrown during execution. + */ void setDescription() throws DukeException { try { this.description = this.s.next().strip(); @@ -42,6 +59,11 @@ void setDescription() throws DukeException { } } + /** + * Retrieves the string representing the deadline of the task to be added, + * based on command issued by user. + * @throws DukeException Application-specific exception thrown during execution. + */ void setDeadlineString() throws DukeException { try { this.deadlineString = this.s.next().strip(); @@ -51,6 +73,10 @@ void setDeadlineString() throws DukeException { } } + /** + * Retrieves the deadline of the task to be added, based on command issued by user. + * @throws DukeException Application-specific exception thrown during execution. + */ void setDeadline() throws DukeException { try { this.deadline = this.dateFormatter.parse(this.deadlineString); @@ -60,8 +86,17 @@ void setDeadline() throws DukeException { } }; + /** + * Creates the task to be added, based on command issued by the user. + * @return Task to be added. + */ abstract Task createTask(); + /** + * Creates a new Task based on command issued by the user, and adds it to the list of tasks. + * @param tasks List of tasks. + * @param ui UI to display to the user. + */ @Override public void execute(TaskList tasks, Ui ui) { Task newTask = createTask(); diff --git a/src/main/java/duke/command/AddTodoCommand.java b/src/main/java/duke/command/AddTodoCommand.java index b27c1a8721..6914234daf 100644 --- a/src/main/java/duke/command/AddTodoCommand.java +++ b/src/main/java/duke/command/AddTodoCommand.java @@ -5,6 +5,9 @@ import duke.task.Todo; import java.util.Date; +/** + * Represents a command to create and add a Todo task. + */ public class AddTodoCommand extends AddTaskCommand { public AddTodoCommand(String fullCommand) throws DukeException { super(fullCommand); diff --git a/src/main/java/duke/command/Command.java b/src/main/java/duke/command/Command.java index 00705113ab..dc4525cf4a 100644 --- a/src/main/java/duke/command/Command.java +++ b/src/main/java/duke/command/Command.java @@ -5,12 +5,13 @@ import duke.util.Ui; /** - * Interface for commands, containing execute() method and isExit() boolean. + * Represents commands requested by user and related operations, + * such as executing the command. */ public interface Command { /** - * Performs command, by interacting with tasks and UI. + * Executes the command, by interacting with tasks and UI. * @param tasks List of tasks. * @param ui UI to display to the user. * @throws DukeException Application-specific exception thrown during execution. diff --git a/src/main/java/duke/command/DeleteCommand.java b/src/main/java/duke/command/DeleteCommand.java index d07d8478e3..158e6b42de 100644 --- a/src/main/java/duke/command/DeleteCommand.java +++ b/src/main/java/duke/command/DeleteCommand.java @@ -11,11 +11,21 @@ public class DeleteCommand implements Command { private Scanner s; + /** + * Constructs a new DeleteCommand, given the full command issued by the user. + * @param fullCommand Full command issued by the user. + */ public DeleteCommand(String fullCommand) { super(); this.s = new Scanner(fullCommand); } + /** + * Deletes a task, based on command issued by the user. + * @param tasks List of tasks. + * @param ui UI to display to the user. + * @throws DukeException Application-specific exception thrown during execution. + */ @Override public void execute(TaskList tasks, Ui ui) throws DukeException { try { diff --git a/src/main/java/duke/command/DoneCommand.java b/src/main/java/duke/command/DoneCommand.java index fb7cc4fa9d..35b058719c 100644 --- a/src/main/java/duke/command/DoneCommand.java +++ b/src/main/java/duke/command/DoneCommand.java @@ -8,14 +8,27 @@ import java.util.NoSuchElementException; import java.util.Scanner; +/** + * Represents a request from the user to mark a given task as done. + */ public class DoneCommand implements Command { private Scanner s; + /** + * Constructs a new DoneCommand, given the full command issued by the user. + * @param fullCommand Full command issued by the user. + */ public DoneCommand(String fullCommand) { super(); this.s = new Scanner(fullCommand); } + /** + * Marks the task in the command issued by the user as done. + * @param tasks List of tasks. + * @param ui UI to display to the user. + * @throws DukeException Application-specific exception thrown during execution. + */ @Override public void execute(TaskList tasks, Ui ui) throws DukeException { try { diff --git a/src/main/java/duke/command/ExitCommand.java b/src/main/java/duke/command/ExitCommand.java index 704bac42c4..f3db221f5e 100644 --- a/src/main/java/duke/command/ExitCommand.java +++ b/src/main/java/duke/command/ExitCommand.java @@ -8,6 +8,11 @@ */ public class ExitCommand implements Command { + /** + * Exits the application. + * @param tasks List of tasks. + * @param ui UI to display to the user. + */ @Override public void execute(TaskList tasks, Ui ui) { // do nothing diff --git a/src/main/java/duke/command/FindCommand.java b/src/main/java/duke/command/FindCommand.java index 1a0a50328f..d23a505762 100644 --- a/src/main/java/duke/command/FindCommand.java +++ b/src/main/java/duke/command/FindCommand.java @@ -11,7 +11,8 @@ public class FindCommand implements Command { private Scanner s; /** - * @param fullCommand Command that was entered by the user. + * Constructs a new FindCommand, given the full command issued by the user. + * @param fullCommand Full command issued by the user. */ public FindCommand(String fullCommand) { super(); @@ -19,6 +20,7 @@ public FindCommand(String fullCommand) { } /** + * Finds a list of tasks matching the keyword issued by the user. * @param tasks List of tasks. * @param ui UI to display to the user. * @throws DukeException Application-specific exception thrown during execution. @@ -42,7 +44,5 @@ public void execute(TaskList tasks, Ui ui) throws DukeException { // user input after "find" is empty throw new DukeException(ExceptionType.KEYWORD_BLANK); } - - } } diff --git a/src/main/java/duke/command/ListCommand.java b/src/main/java/duke/command/ListCommand.java index e19bd9c7fc..eeb292d940 100644 --- a/src/main/java/duke/command/ListCommand.java +++ b/src/main/java/duke/command/ListCommand.java @@ -7,10 +7,16 @@ public class ListCommand implements Command { + /** + * Lists all tasks currently in the list. + * @param tasks List of tasks. + * @param ui UI to display to the user. + * @throws DukeException Application-specific exception thrown during execution. + */ @Override - public void execute(TaskList tasks, Ui ui) { + public void execute(TaskList tasks, Ui ui) throws DukeException { if (tasks.isEmpty()) { - ui.showError(new DukeException(ExceptionType.TASK_LIST_EMPTY)); + throw new DukeException(ExceptionType.TASK_LIST_EMPTY); } tasks.printList(); } diff --git a/src/main/java/duke/task/Deadline.java b/src/main/java/duke/task/Deadline.java index eb7a22c62d..76a362c250 100644 --- a/src/main/java/duke/task/Deadline.java +++ b/src/main/java/duke/task/Deadline.java @@ -2,15 +2,29 @@ import java.util.Date; +/** + * Represents a Deadline, a type of Task that has an expected date of completion. + */ public class Deadline extends Task { private Date by; + /** + * Constructs a new Deadline, with the specified description and date of completion. + * @param description Description of the Deadline. + * @param by Expected date of completion of the Deadline. + */ public Deadline(String description, Date by) { super(description); this.by = by; this.type = TaskType.DEADLINE; } + /** + * Returns the String representation of a Deadline for display purposes. + * Adds the deadline of the Deadline to the String representation + * provided by the Task class. + * @return String representation of a Deadline for display purposes. + */ @Override public String toString() { return super.toString() + " (by: " + by + ")"; diff --git a/src/main/java/duke/task/Event.java b/src/main/java/duke/task/Event.java index f35a8c2375..ad8f5b5f3d 100644 --- a/src/main/java/duke/task/Event.java +++ b/src/main/java/duke/task/Event.java @@ -2,15 +2,29 @@ import java.util.Date; +/** + * Represents an Event, a type of Task that has an expected date of occurrence. + */ public class Event extends Task { private Date at; + /** + * Constructs a new Event, with the specified description and date of occurrence. + * @param description Description of the Event. + * @param at Expected date of occurrence of the Event. + */ public Event(String description, Date at) { super(description); this.at = at; this.type = TaskType.EVENT; } + /** + * Returns the String representation of an Event for display purposes. + * Adds the date of occurrence of the Event to the String representation + * provided by the Task class. + * @return String representation of a Event for display purposes. + */ @Override public String toString() { return super.toString() + " (at: " + at + ")"; diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java index 6cd1599e43..6902bb8090 100644 --- a/src/main/java/duke/task/Task.java +++ b/src/main/java/duke/task/Task.java @@ -2,15 +2,27 @@ import java.io.Serializable; +/** + * Represents a task, the building block of a TaskList object. + */ public abstract class Task implements Serializable { private String description; private Boolean isDone = false; TaskType type; + /** + * Constructs a Task, with the specified description. + * @param description Description of the Task. + */ public Task(String description) { this.description = description; } + /** + * Returns the String representation of a Task for display purposes. + * @return String representation of a Task for display purposes. + */ + // todo: move to Ui class @Override public String toString() { String type = "[" + this.type.getTaskTypeInitial() + "] "; @@ -18,12 +30,20 @@ public String toString() { return type + status + this.description; } + /** + * Returns the status icon corresponding to the status of the task (done or not done). + * @return Status icon corresponding to the status of the task (done or not done). + */ private String getStatusIcon() { return (isDone ? "Y" : "N"); // return Y or N } + /** + * Marks the task as done. + */ public void markAsDone() { this.isDone = true; + // todo: replace with proper UI implementation System.out.println("Nice! I've marked this task as done:"); System.out.println(this.toString()); } diff --git a/src/main/java/duke/task/TaskList.java b/src/main/java/duke/task/TaskList.java index 5a91bab1ce..6125f1c708 100644 --- a/src/main/java/duke/task/TaskList.java +++ b/src/main/java/duke/task/TaskList.java @@ -4,7 +4,7 @@ import java.util.ArrayList; /** - * List of tasks in the application. + * Represents the list of tasks in the application. */ public class TaskList implements Serializable { @@ -56,7 +56,7 @@ public void add(Task task) { // todo: move to Ui class public void printList() { for (Task task : tasks) { - int i = getId(task, this); + int i = getId(task); String s = task.toString(); System.out.println(i + ". " + s); } @@ -68,12 +68,12 @@ public void printList() { * @param task Task whose ID is required. * @return ID of the given task. */ - private int getId(Task task, TaskList taskList) { - return taskList.tasks.indexOf(task) + 1; + private int getId(Task task) { + return this.tasks.indexOf(task) + 1; } /** - * Returns the task with the given ID in the main TaskList. + * Returns the task with the given ID in this TaskList. * @param taskId ID of the task. * @return Task with the given ID. * @throws IndexOutOfBoundsException Exception thrown when the given ID is not present in diff --git a/src/main/java/duke/task/TaskType.java b/src/main/java/duke/task/TaskType.java index 06350372bb..533ba36d18 100644 --- a/src/main/java/duke/task/TaskType.java +++ b/src/main/java/duke/task/TaskType.java @@ -1,5 +1,9 @@ package duke.task; +/** + * Represents the possible types of Tasks. + * Possible values: TODO, DEADLINE, EVENT. + */ public enum TaskType { DEADLINE("by", "D"), EVENT("at", "E"), @@ -14,10 +18,20 @@ public enum TaskType { this.initial = initial; } + /** + * Returns the delimiter used to separate the description of a Task from its additional details. + * Possible usage: in an alternative implementation of AddTaskCommand. + * @return Delimiter used to separate the description of a Task from its additional details. + */ public String getDelimiter() { return this.delimiter; } + /** + * Returns the TaskType of the task, given a String describing its type. + * @param taskTypeString String describing the type of the Task. + * @return TaskType of the task. + */ public TaskType getTaskType(String taskTypeString) { switch (taskTypeString) { case "todo": @@ -31,6 +45,11 @@ public TaskType getTaskType(String taskTypeString) { } } + /** + * Returns the initial representing the TaskType. + * Possible usage: for icons representing the TaskType in UI. + * @return Initial representing the TaskType. + */ public String getTaskTypeInitial() { return this.initial; } diff --git a/src/main/java/duke/util/UiMessage.java b/src/main/java/duke/util/UiMessage.java index 4b9bbae72c..9ac1f005a6 100644 --- a/src/main/java/duke/util/UiMessage.java +++ b/src/main/java/duke/util/UiMessage.java @@ -1,5 +1,8 @@ package duke.util; +/** + * Represents different types of events that need to be displayed to the user within the UI. + */ public enum UiMessage { // greetings WELCOME("Hello! What can I do for you?"), @@ -18,6 +21,10 @@ public enum UiMessage { this.message = message; } + /** + * Returns a message relating to the event, to be displayed in the UI. + * @return Message relating to the event, to be displayed in the UI. + */ public String getMessage() { return this.message; } diff --git a/src/main/java/duke/util/exception/ExceptionType.java b/src/main/java/duke/util/exception/ExceptionType.java index 3ff7d5ffb0..2ffb60240b 100644 --- a/src/main/java/duke/util/exception/ExceptionType.java +++ b/src/main/java/duke/util/exception/ExceptionType.java @@ -1,5 +1,8 @@ package duke.util.exception; +/** + * Represents different types of Exceptions unique to the application. + */ public enum ExceptionType { // invalid INVALID_ID("Oops! You entered an invalid task ID!"), @@ -21,6 +24,10 @@ public enum ExceptionType { this.message = message; } + /** + * Returns a message describing the Exception, to be displayed in the UI. + * @return Message describing the Exception, to be displayed in the UI. + */ public String getMessage() { return this.message; } From dd6a24172534bf24f1e540c7e435ceba42e0a95d Mon Sep 17 00:00:00 2001 From: nattanyz Date: Sun, 29 Sep 2019 23:15:34 +0800 Subject: [PATCH 37/84] begin to implement Snooze command --- .../java/duke/command/AddTaskCommand.java | 1 + src/main/java/duke/command/SnoozeCommand.java | 42 +++++++++++++++++++ src/main/java/duke/task/Deadline.java | 5 +++ src/main/java/duke/task/Event.java | 5 +++ src/main/java/duke/task/Task.java | 5 +++ src/main/java/duke/task/Todo.java | 9 ++++ src/main/java/duke/util/Parser.java | 2 + 7 files changed, 69 insertions(+) create mode 100644 src/main/java/duke/command/SnoozeCommand.java diff --git a/src/main/java/duke/command/AddTaskCommand.java b/src/main/java/duke/command/AddTaskCommand.java index d4fde96ae0..70a6d79ead 100644 --- a/src/main/java/duke/command/AddTaskCommand.java +++ b/src/main/java/duke/command/AddTaskCommand.java @@ -19,6 +19,7 @@ public abstract class AddTaskCommand implements Command { private String description; private Date deadline; private String deadlineString; + // todo: move dateFormatter to somewhere else that makes more sense private SimpleDateFormat dateFormatter = new SimpleDateFormat("dd/MM/yyyy HHmm"); diff --git a/src/main/java/duke/command/SnoozeCommand.java b/src/main/java/duke/command/SnoozeCommand.java new file mode 100644 index 0000000000..36168bd97a --- /dev/null +++ b/src/main/java/duke/command/SnoozeCommand.java @@ -0,0 +1,42 @@ +package duke.command; + +import duke.task.TaskList; +import duke.util.Ui; +import duke.util.exception.DukeException; +import duke.util.exception.ExceptionType; +import java.util.InputMismatchException; +import java.util.NoSuchElementException; +import java.util.Scanner; + +/** + * Represents a command to postpone ("snooze") a task. + */ +public class SnoozeCommand implements Command { + private Scanner s; + + /** + * Constructs a new SnoozeCommand, given the full command issued by the user. + * @param fullCommand Full command issued by the user. + */ + public SnoozeCommand(String fullCommand) { + super(); + this.s = new Scanner(fullCommand); + } + @Override + public void execute(TaskList tasks, Ui ui) throws DukeException { + try { + // first, try to get taskId + s.next(); // command (done), to be ignored + int taskId = s.nextInt(); + + // if ok, snooze task + tasks.getTask(taskId).snooze(); + } catch (InputMismatchException | IndexOutOfBoundsException e) { + // user input after "done" is not an int, or is an invalid task ID + throw new DukeException(ExceptionType.INVALID_ID); + } catch (NoSuchElementException e) { + // user input after "done" is blank + throw new DukeException(ExceptionType.ID_BLANK); + } + } +} diff --git a/src/main/java/duke/task/Deadline.java b/src/main/java/duke/task/Deadline.java index 76a362c250..95b8b0ee01 100644 --- a/src/main/java/duke/task/Deadline.java +++ b/src/main/java/duke/task/Deadline.java @@ -29,4 +29,9 @@ public Deadline(String description, Date by) { public String toString() { return super.toString() + " (by: " + by + ")"; } + + @Override + public void snooze() { + // todo + } } diff --git a/src/main/java/duke/task/Event.java b/src/main/java/duke/task/Event.java index ad8f5b5f3d..ba4fcf508f 100644 --- a/src/main/java/duke/task/Event.java +++ b/src/main/java/duke/task/Event.java @@ -29,4 +29,9 @@ public Event(String description, Date at) { public String toString() { return super.toString() + " (at: " + at + ")"; } + + @Override + public void snooze() { + // todo + } } diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java index 6902bb8090..b96efbad36 100644 --- a/src/main/java/duke/task/Task.java +++ b/src/main/java/duke/task/Task.java @@ -47,4 +47,9 @@ public void markAsDone() { System.out.println("Nice! I've marked this task as done:"); System.out.println(this.toString()); } + + /** + * Postpones the deadline of the given task by 1 day if no other argument is specified. + */ + public abstract void snooze(); } diff --git a/src/main/java/duke/task/Todo.java b/src/main/java/duke/task/Todo.java index 2ca94fed7b..65b5757fd6 100644 --- a/src/main/java/duke/task/Todo.java +++ b/src/main/java/duke/task/Todo.java @@ -5,4 +5,13 @@ public Todo(String description) { super(description); this.type = TaskType.TODO; } + + /** + * Snoozes ("postpones") the given task. + * Not applicable to tasks of TODO type. + */ + @Override + public void snooze() { + // do nothing + } } diff --git a/src/main/java/duke/util/Parser.java b/src/main/java/duke/util/Parser.java index e68b708da8..f6a6f694af 100644 --- a/src/main/java/duke/util/Parser.java +++ b/src/main/java/duke/util/Parser.java @@ -27,6 +27,8 @@ public static Command parse(String fullCommand) throws DukeException { return new AddEventCommand(fullCommand); } else if (command.equals("deadline")) { return new AddDeadlineCommand(fullCommand); + } else if (command.equals("snooze")) { + return new SnoozeCommand(fullCommand); } else { throw new DukeException(ExceptionType.INVALID_COMMAND); } From b308c14226a38d45e1dd28b825b8ebb792c3c92e Mon Sep 17 00:00:00 2001 From: nattanyz Date: Sun, 29 Sep 2019 23:49:37 +0800 Subject: [PATCH 38/84] add ModifyTaskCommand class to simplify implementations of Done, Snooze, Tag and Delete commands. implement C-Tagging --- src/main/java/duke/command/Command.java | 2 +- src/main/java/duke/command/DeleteCommand.java | 31 +++------------ src/main/java/duke/command/DoneCommand.java | 33 +++------------- .../java/duke/command/ModifyTaskCommand.java | 38 ++++++++++++++++++ src/main/java/duke/command/SnoozeCommand.java | 38 ++++++------------ src/main/java/duke/command/TagCommand.java | 39 +++++++++++++++++++ src/main/java/duke/task/Task.java | 33 +++++++++++++++- src/main/java/duke/task/TaskList.java | 5 +-- src/main/java/duke/util/Parser.java | 2 + .../duke/util/exception/ExceptionType.java | 1 + 10 files changed, 138 insertions(+), 84 deletions(-) create mode 100644 src/main/java/duke/command/ModifyTaskCommand.java create mode 100644 src/main/java/duke/command/TagCommand.java diff --git a/src/main/java/duke/command/Command.java b/src/main/java/duke/command/Command.java index dc4525cf4a..e00cfa4499 100644 --- a/src/main/java/duke/command/Command.java +++ b/src/main/java/duke/command/Command.java @@ -1,8 +1,8 @@ package duke.command; -import duke.util.exception.DukeException; import duke.task.TaskList; import duke.util.Ui; +import duke.util.exception.DukeException; /** * Represents commands requested by user and related operations, diff --git a/src/main/java/duke/command/DeleteCommand.java b/src/main/java/duke/command/DeleteCommand.java index 158e6b42de..15aeff2b7f 100644 --- a/src/main/java/duke/command/DeleteCommand.java +++ b/src/main/java/duke/command/DeleteCommand.java @@ -1,23 +1,14 @@ package duke.command; +import duke.task.Task; import duke.task.TaskList; import duke.util.Ui; import duke.util.exception.DukeException; -import duke.util.exception.ExceptionType; -import java.util.InputMismatchException; -import java.util.NoSuchElementException; -import java.util.Scanner; -public class DeleteCommand implements Command { - private Scanner s; +public class DeleteCommand extends ModifyTaskCommand { - /** - * Constructs a new DeleteCommand, given the full command issued by the user. - * @param fullCommand Full command issued by the user. - */ public DeleteCommand(String fullCommand) { - super(); - this.s = new Scanner(fullCommand); + super(fullCommand); } /** @@ -28,19 +19,7 @@ public DeleteCommand(String fullCommand) { */ @Override public void execute(TaskList tasks, Ui ui) throws DukeException { - try { - // first, try to get taskId - s.next(); // command (delete), to be ignored - int taskId = s.nextInt(); - - // if ok, delete task - tasks.deleteTask(taskId); - } catch (InputMismatchException | IndexOutOfBoundsException e) { - // user input after "done" is not an int, or is an invalid task ID - throw new DukeException(ExceptionType.INVALID_ID); - } catch (NoSuchElementException e) { - // user input after "done" is blank - throw new DukeException(ExceptionType.ID_BLANK); - } + Task task = getTaskById(tasks); + tasks.deleteTask(task); } } diff --git a/src/main/java/duke/command/DoneCommand.java b/src/main/java/duke/command/DoneCommand.java index 35b058719c..0b25de2c6c 100644 --- a/src/main/java/duke/command/DoneCommand.java +++ b/src/main/java/duke/command/DoneCommand.java @@ -1,26 +1,17 @@ package duke.command; -import duke.util.exception.DukeException; -import duke.util.exception.ExceptionType; +import duke.task.Task; import duke.task.TaskList; import duke.util.Ui; -import java.util.InputMismatchException; -import java.util.NoSuchElementException; -import java.util.Scanner; +import duke.util.exception.DukeException; /** * Represents a request from the user to mark a given task as done. */ -public class DoneCommand implements Command { - private Scanner s; +public class DoneCommand extends ModifyTaskCommand { - /** - * Constructs a new DoneCommand, given the full command issued by the user. - * @param fullCommand Full command issued by the user. - */ public DoneCommand(String fullCommand) { - super(); - this.s = new Scanner(fullCommand); + super(fullCommand); } /** @@ -31,19 +22,7 @@ public DoneCommand(String fullCommand) { */ @Override public void execute(TaskList tasks, Ui ui) throws DukeException { - try { - // first, try to get taskId - s.next(); // command (done), to be ignored - int taskId = s.nextInt(); - - // if ok, mark task as done - tasks.getTask(taskId).markAsDone(); - } catch (InputMismatchException | IndexOutOfBoundsException e) { - // user input after "done" is not an int, or is an invalid task ID - throw new DukeException(ExceptionType.INVALID_ID); - } catch (NoSuchElementException e) { - // user input after "done" is blank - throw new DukeException(ExceptionType.ID_BLANK); - } + Task task = getTaskById(tasks); + task.markAsDone(); } } diff --git a/src/main/java/duke/command/ModifyTaskCommand.java b/src/main/java/duke/command/ModifyTaskCommand.java new file mode 100644 index 0000000000..3236b836ea --- /dev/null +++ b/src/main/java/duke/command/ModifyTaskCommand.java @@ -0,0 +1,38 @@ +package duke.command; + +import duke.task.Task; +import duke.task.TaskList; +import duke.util.exception.DukeException; +import duke.util.exception.ExceptionType; +import java.util.InputMismatchException; +import java.util.NoSuchElementException; +import java.util.Scanner; + +public abstract class ModifyTaskCommand implements Command{ + Scanner s; + + public ModifyTaskCommand(String fullCommand) { + super(); + s = new Scanner(fullCommand); + } + + public Task getTaskById(TaskList tasks) throws DukeException{ + int taskId; + Task task; + + try { + // first, try to get taskId + s.next(); // command, to be ignored + taskId = s.nextInt(); + task = tasks.getTask(taskId); + + return task; + } catch (InputMismatchException | IndexOutOfBoundsException e) { + // user input after "tag" is not an int, or is an invalid task ID + throw new DukeException(ExceptionType.INVALID_ID); + } catch (NoSuchElementException e) { + // user input after "tag" is blank + throw new DukeException(ExceptionType.ID_BLANK); + } + } +} diff --git a/src/main/java/duke/command/SnoozeCommand.java b/src/main/java/duke/command/SnoozeCommand.java index 36168bd97a..47639cfcd2 100644 --- a/src/main/java/duke/command/SnoozeCommand.java +++ b/src/main/java/duke/command/SnoozeCommand.java @@ -1,42 +1,28 @@ package duke.command; +import duke.task.Task; import duke.task.TaskList; import duke.util.Ui; import duke.util.exception.DukeException; -import duke.util.exception.ExceptionType; -import java.util.InputMismatchException; -import java.util.NoSuchElementException; -import java.util.Scanner; /** * Represents a command to postpone ("snooze") a task. */ -public class SnoozeCommand implements Command { - private Scanner s; +public class SnoozeCommand extends ModifyTaskCommand { - /** - * Constructs a new SnoozeCommand, given the full command issued by the user. - * @param fullCommand Full command issued by the user. - */ public SnoozeCommand(String fullCommand) { - super(); - this.s = new Scanner(fullCommand); + super(fullCommand); } + + /** + * Snoozes the task in the command issued by the user. + * @param tasks List of tasks. + * @param ui UI to display to the user. + * @throws DukeException Application-specific exception thrown during execution. + */ @Override public void execute(TaskList tasks, Ui ui) throws DukeException { - try { - // first, try to get taskId - s.next(); // command (done), to be ignored - int taskId = s.nextInt(); - - // if ok, snooze task - tasks.getTask(taskId).snooze(); - } catch (InputMismatchException | IndexOutOfBoundsException e) { - // user input after "done" is not an int, or is an invalid task ID - throw new DukeException(ExceptionType.INVALID_ID); - } catch (NoSuchElementException e) { - // user input after "done" is blank - throw new DukeException(ExceptionType.ID_BLANK); - } + Task task = getTaskById(tasks); + task.snooze(); } } diff --git a/src/main/java/duke/command/TagCommand.java b/src/main/java/duke/command/TagCommand.java new file mode 100644 index 0000000000..b82fcaed74 --- /dev/null +++ b/src/main/java/duke/command/TagCommand.java @@ -0,0 +1,39 @@ +package duke.command; + +import duke.task.Task; +import duke.task.TaskList; +import duke.util.Ui; +import duke.util.exception.DukeException; +import duke.util.exception.ExceptionType; +import java.util.NoSuchElementException; + +/** + * Represents a command to add a tag to a task. + */ +public class TagCommand extends ModifyTaskCommand { + public TagCommand(String fullCommand) { + super(fullCommand); + } + + /** + * Adds a tag to the task, based on command issued by the user. + * @param tasks List of tasks. + * @param ui UI to display to the user. + * @throws DukeException Application-specific exception thrown during execution. + */ + @Override + public void execute(TaskList tasks, Ui ui) throws DukeException { + Task task = getTaskById(tasks); + + // then, try to get tag + try { + String tag = s.next().strip(); + + // if ok, add tag to task + task.addTag(tag); + } catch (NoSuchElementException e) { + // user input after taskId is blank + throw new DukeException(ExceptionType.TAG_BLANK); + } + } +} diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java index b96efbad36..351933389c 100644 --- a/src/main/java/duke/task/Task.java +++ b/src/main/java/duke/task/Task.java @@ -9,6 +9,7 @@ public abstract class Task implements Serializable { private String description; private Boolean isDone = false; TaskType type; + private String tag; /** * Constructs a Task, with the specified description. @@ -27,7 +28,12 @@ public Task(String description) { public String toString() { String type = "[" + this.type.getTaskTypeInitial() + "] "; String status = "[" + this.getStatusIcon() + "] "; - return type + status + this.description; + String toString = type + status + this.description; + + if (this.hasTag()) { + toString = toString + " (tag: " + this.getTag() + ")"; + } + return toString; } /** @@ -52,4 +58,29 @@ public void markAsDone() { * Postpones the deadline of the given task by 1 day if no other argument is specified. */ public abstract void snooze(); + + /** + * Adds a tag to the given task. + * Currently supports only one tag per task. + * To override existing tag, use tag command. + * @param tag Tag to be added to the given task. + */ + public void addTag(String tag) { + this.tag = tag; + // todo: replace with proper UI implementation + System.out.println("Nice! I've added a tag to this task:"); + System.out.println(this.toString()); + } + + private String getTag() { + return this.tag; + } + + private boolean hasTag() { + if (this.getTag() == null) { + return false; + } else { + return true; + } + } } diff --git a/src/main/java/duke/task/TaskList.java b/src/main/java/duke/task/TaskList.java index 6125f1c708..6293c0f1f5 100644 --- a/src/main/java/duke/task/TaskList.java +++ b/src/main/java/duke/task/TaskList.java @@ -85,10 +85,9 @@ public Task getTask(int taskId) throws IndexOutOfBoundsException { /** * Deletes the given task from the TaskList. - * @param taskId ID of task to be deleted from the TaskList. + * @param taskToDelete Task to be deleted from the TaskList. */ - public void deleteTask(int taskId) { - Task taskToDelete = getTask(taskId); + public void deleteTask(Task taskToDelete) { String taskDescription = taskToDelete.toString(); tasks.remove(taskToDelete); System.out.println("Noted. I've removed this task: " + taskDescription); diff --git a/src/main/java/duke/util/Parser.java b/src/main/java/duke/util/Parser.java index f6a6f694af..6cb9cfda0a 100644 --- a/src/main/java/duke/util/Parser.java +++ b/src/main/java/duke/util/Parser.java @@ -29,6 +29,8 @@ public static Command parse(String fullCommand) throws DukeException { return new AddDeadlineCommand(fullCommand); } else if (command.equals("snooze")) { return new SnoozeCommand(fullCommand); + } else if (command.equals("tag")) { + return new TagCommand(fullCommand); } else { throw new DukeException(ExceptionType.INVALID_COMMAND); } diff --git a/src/main/java/duke/util/exception/ExceptionType.java b/src/main/java/duke/util/exception/ExceptionType.java index 2ffb60240b..164df194a9 100644 --- a/src/main/java/duke/util/exception/ExceptionType.java +++ b/src/main/java/duke/util/exception/ExceptionType.java @@ -14,6 +14,7 @@ public enum ExceptionType { DESCRIPTION_BLANK("Oops! You did not enter a description!"), DEADLINE_BLANK("Oops! You did not enter a deadline!"), KEYWORD_BLANK("Oops! You did not enter a keyword!"), + TAG_BLANK("Oops! You did not enter a tag!"), // nothing to return NO_MATCHING_TASKS("There are no tasks matching your query :("), TASK_LIST_EMPTY("The task list is empty."),; From 98d13957ac3b124bd8a77c3223dd5dc4d284090a Mon Sep 17 00:00:00 2001 From: nattanyz Date: Mon, 30 Sep 2019 00:04:35 +0800 Subject: [PATCH 39/84] implement C-Priority --- .../java/duke/command/PriorityCommand.java | 43 +++++++++++++++++++ src/main/java/duke/task/Task.java | 28 ++++++++++++ src/main/java/duke/task/TaskPriority.java | 25 +++++++++++ src/main/java/duke/task/TaskType.java | 2 +- src/main/java/duke/util/Parser.java | 2 + 5 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 src/main/java/duke/command/PriorityCommand.java create mode 100644 src/main/java/duke/task/TaskPriority.java diff --git a/src/main/java/duke/command/PriorityCommand.java b/src/main/java/duke/command/PriorityCommand.java new file mode 100644 index 0000000000..a6f991485b --- /dev/null +++ b/src/main/java/duke/command/PriorityCommand.java @@ -0,0 +1,43 @@ +package duke.command; + +import static duke.task.TaskPriority.getTaskPriority; + +import duke.task.Task; +import duke.task.TaskList; +import duke.task.TaskPriority; +import duke.util.Ui; +import duke.util.exception.DukeException; +import duke.util.exception.ExceptionType; +import java.util.NoSuchElementException; + +/** + * Represents a command to add a priority to a task. + */ +public class PriorityCommand extends ModifyTaskCommand { + public PriorityCommand(String fullCommand) { + super(fullCommand); + } + + /** + * Adds a priority to the task, based on command issued by the user. + * @param tasks List of tasks. + * @param ui UI to display to the user. + * @throws DukeException Application-specific exception thrown during execution. + */ + @Override + public void execute(TaskList tasks, Ui ui) throws DukeException { + Task task = getTaskById(tasks); + + // then, try to get priority + try { + String priorityString = s.next().strip(); + TaskPriority priority = getTaskPriority(priorityString); + + // if ok, add priority to task + task.addPriority(priority); + } catch (NoSuchElementException e) { + // user input after taskId is blank + throw new DukeException(ExceptionType.TAG_BLANK); + } + } +} diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java index 351933389c..0a14457002 100644 --- a/src/main/java/duke/task/Task.java +++ b/src/main/java/duke/task/Task.java @@ -10,6 +10,7 @@ public abstract class Task implements Serializable { private Boolean isDone = false; TaskType type; private String tag; + private TaskPriority priority; /** * Constructs a Task, with the specified description. @@ -33,6 +34,10 @@ public String toString() { if (this.hasTag()) { toString = toString + " (tag: " + this.getTag() + ")"; } + + if (this.hasPriority()) { + toString = toString + " (priority: " + this.getPriority() + ")"; + } return toString; } @@ -83,4 +88,27 @@ private boolean hasTag() { return true; } } + + /** + * Adds a priority to the given task. + * @param priority Priority to be added to the given task. + */ + public void addPriority(TaskPriority priority) { + this.priority = priority; + // todo: replace with proper UI implementation + System.out.println("Nice! I've added a priority to this task:"); + System.out.println(this.toString()); + } + + private TaskPriority getPriority() { + return this.priority; + } + + private boolean hasPriority() { + if (this.getPriority() == null) { + return false; + } else { + return true; + } + } } diff --git a/src/main/java/duke/task/TaskPriority.java b/src/main/java/duke/task/TaskPriority.java new file mode 100644 index 0000000000..30da0b1c21 --- /dev/null +++ b/src/main/java/duke/task/TaskPriority.java @@ -0,0 +1,25 @@ +package duke.task; + +public enum TaskPriority { + LOW, + MEDIUM, + HIGH; + + /** + * Returns the TaskPriority, given a String describing its priority. + * @param taskPriorityString String describing the priority. + * @return TaskPriority, based on String provided. + */ + public static TaskPriority getTaskPriority(String taskPriorityString) { + switch (taskPriorityString) { + case "low": + return TaskPriority.LOW; + case "medium": + return TaskPriority.MEDIUM; + case "high": + return TaskPriority.HIGH; + default: + return null; + } + } +} diff --git a/src/main/java/duke/task/TaskType.java b/src/main/java/duke/task/TaskType.java index 533ba36d18..2849a35054 100644 --- a/src/main/java/duke/task/TaskType.java +++ b/src/main/java/duke/task/TaskType.java @@ -32,7 +32,7 @@ public String getDelimiter() { * @param taskTypeString String describing the type of the Task. * @return TaskType of the task. */ - public TaskType getTaskType(String taskTypeString) { + public static TaskType getTaskType(String taskTypeString) { switch (taskTypeString) { case "todo": return TaskType.TODO; diff --git a/src/main/java/duke/util/Parser.java b/src/main/java/duke/util/Parser.java index 6cb9cfda0a..de5f3b26b8 100644 --- a/src/main/java/duke/util/Parser.java +++ b/src/main/java/duke/util/Parser.java @@ -31,6 +31,8 @@ public static Command parse(String fullCommand) throws DukeException { return new SnoozeCommand(fullCommand); } else if (command.equals("tag")) { return new TagCommand(fullCommand); + } else if (command.equals("priority")) { + return new PriorityCommand(fullCommand); } else { throw new DukeException(ExceptionType.INVALID_COMMAND); } From 303476774ad026890445ef8065797d6625ffab67 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Mon, 30 Sep 2019 00:10:09 +0800 Subject: [PATCH 40/84] refactor: rename Deadline, Todo and Event to DeadlineTask, TodoTask and EventTask to better reflect inheritance --- src/main/java/duke/command/AddDeadlineCommand.java | 8 ++++---- src/main/java/duke/command/AddEventCommand.java | 4 ++-- src/main/java/duke/command/AddTodoCommand.java | 8 ++++---- .../java/duke/task/{Deadline.java => DeadlineTask.java} | 4 ++-- src/main/java/duke/task/{Event.java => EventTask.java} | 4 ++-- src/main/java/duke/task/{Todo.java => TodoTask.java} | 4 ++-- 6 files changed, 16 insertions(+), 16 deletions(-) rename src/main/java/duke/task/{Deadline.java => DeadlineTask.java} (90%) rename src/main/java/duke/task/{Event.java => EventTask.java} (90%) rename src/main/java/duke/task/{Todo.java => TodoTask.java} (77%) diff --git a/src/main/java/duke/command/AddDeadlineCommand.java b/src/main/java/duke/command/AddDeadlineCommand.java index 37397e87a8..36476a6267 100644 --- a/src/main/java/duke/command/AddDeadlineCommand.java +++ b/src/main/java/duke/command/AddDeadlineCommand.java @@ -1,11 +1,11 @@ package duke.command; -import duke.util.exception.DukeException; -import duke.task.Deadline; +import duke.task.DeadlineTask; import duke.task.Task; +import duke.util.exception.DukeException; /** - * Represents a command to create and add a Deadline task. + * Represents a command to create and add a DeadlineTask. */ public class AddDeadlineCommand extends AddTaskCommand { public AddDeadlineCommand(String command) throws DukeException { @@ -19,6 +19,6 @@ public AddDeadlineCommand(String command) throws DukeException { @Override public Task createTask() { - return new Deadline(getDescription(), getDeadline()); + return new DeadlineTask(getDescription(), getDeadline()); } } diff --git a/src/main/java/duke/command/AddEventCommand.java b/src/main/java/duke/command/AddEventCommand.java index 4dc2a5154b..52dfd3c722 100644 --- a/src/main/java/duke/command/AddEventCommand.java +++ b/src/main/java/duke/command/AddEventCommand.java @@ -1,7 +1,7 @@ package duke.command; import duke.util.exception.DukeException; -import duke.task.Event; +import duke.task.EventTask; import duke.task.Task; /** @@ -19,6 +19,6 @@ public AddEventCommand(String command) throws DukeException { @Override public Task createTask() { - return new Event(getDescription(), getDeadline()); + return new EventTask(getDescription(), getDeadline()); } } diff --git a/src/main/java/duke/command/AddTodoCommand.java b/src/main/java/duke/command/AddTodoCommand.java index 6914234daf..f6f5ad018a 100644 --- a/src/main/java/duke/command/AddTodoCommand.java +++ b/src/main/java/duke/command/AddTodoCommand.java @@ -1,12 +1,12 @@ package duke.command; -import duke.util.exception.DukeException; import duke.task.Task; -import duke.task.Todo; +import duke.task.TodoTask; +import duke.util.exception.DukeException; import java.util.Date; /** - * Represents a command to create and add a Todo task. + * Represents a command to create and add a TodoTask. */ public class AddTodoCommand extends AddTaskCommand { public AddTodoCommand(String fullCommand) throws DukeException { @@ -22,6 +22,6 @@ Date getDeadline() { @Override public Task createTask() { - return new Todo(getDescription()); + return new TodoTask(getDescription()); } } diff --git a/src/main/java/duke/task/Deadline.java b/src/main/java/duke/task/DeadlineTask.java similarity index 90% rename from src/main/java/duke/task/Deadline.java rename to src/main/java/duke/task/DeadlineTask.java index 95b8b0ee01..b0c428d03d 100644 --- a/src/main/java/duke/task/Deadline.java +++ b/src/main/java/duke/task/DeadlineTask.java @@ -5,7 +5,7 @@ /** * Represents a Deadline, a type of Task that has an expected date of completion. */ -public class Deadline extends Task { +public class DeadlineTask extends Task { private Date by; /** @@ -13,7 +13,7 @@ public class Deadline extends Task { * @param description Description of the Deadline. * @param by Expected date of completion of the Deadline. */ - public Deadline(String description, Date by) { + public DeadlineTask(String description, Date by) { super(description); this.by = by; this.type = TaskType.DEADLINE; diff --git a/src/main/java/duke/task/Event.java b/src/main/java/duke/task/EventTask.java similarity index 90% rename from src/main/java/duke/task/Event.java rename to src/main/java/duke/task/EventTask.java index ba4fcf508f..90e7b7fb3e 100644 --- a/src/main/java/duke/task/Event.java +++ b/src/main/java/duke/task/EventTask.java @@ -5,7 +5,7 @@ /** * Represents an Event, a type of Task that has an expected date of occurrence. */ -public class Event extends Task { +public class EventTask extends Task { private Date at; /** @@ -13,7 +13,7 @@ public class Event extends Task { * @param description Description of the Event. * @param at Expected date of occurrence of the Event. */ - public Event(String description, Date at) { + public EventTask(String description, Date at) { super(description); this.at = at; this.type = TaskType.EVENT; diff --git a/src/main/java/duke/task/Todo.java b/src/main/java/duke/task/TodoTask.java similarity index 77% rename from src/main/java/duke/task/Todo.java rename to src/main/java/duke/task/TodoTask.java index 65b5757fd6..c95131007c 100644 --- a/src/main/java/duke/task/Todo.java +++ b/src/main/java/duke/task/TodoTask.java @@ -1,7 +1,7 @@ package duke.task; -public class Todo extends Task { - public Todo(String description) { +public class TodoTask extends Task { + public TodoTask(String description) { super(description); this.type = TaskType.TODO; } From 94dd6d4408adc502b2c68674b83ef344ff8750dd Mon Sep 17 00:00:00 2001 From: nattanyz Date: Mon, 30 Sep 2019 00:26:09 +0800 Subject: [PATCH 41/84] move parseDate() to DateTime class, change implementations of DeadlineTask and EventTask to use String as param and parse date within constructor --- .../java/duke/command/AddDeadlineCommand.java | 6 +-- .../java/duke/command/AddEventCommand.java | 6 +-- .../java/duke/command/AddTaskCommand.java | 41 +++++-------------- src/main/java/duke/task/DeadlineTask.java | 10 +++-- src/main/java/duke/task/EventTask.java | 10 +++-- src/main/java/duke/task/Task.java | 6 +-- src/main/java/duke/task/TaskType.java | 1 - src/main/java/duke/task/TodoTask.java | 2 +- src/main/java/duke/util/DateTime.java | 18 ++++---- src/main/java/duke/util/UiMessage.java | 6 ++- 10 files changed, 42 insertions(+), 64 deletions(-) diff --git a/src/main/java/duke/command/AddDeadlineCommand.java b/src/main/java/duke/command/AddDeadlineCommand.java index 36476a6267..fb32e07f9d 100644 --- a/src/main/java/duke/command/AddDeadlineCommand.java +++ b/src/main/java/duke/command/AddDeadlineCommand.java @@ -9,16 +9,14 @@ */ public class AddDeadlineCommand extends AddTaskCommand { public AddDeadlineCommand(String command) throws DukeException { - // todo: use enum and then lambda to pass in delimiter super(command); s.useDelimiter("/by"); setDescription(); setDeadlineString(); - setDeadline(); } @Override - public Task createTask() { - return new DeadlineTask(getDescription(), getDeadline()); + public Task createTask() throws DukeException { + return new DeadlineTask(getDescription(), getDeadlineString()); } } diff --git a/src/main/java/duke/command/AddEventCommand.java b/src/main/java/duke/command/AddEventCommand.java index 52dfd3c722..c7077edbc2 100644 --- a/src/main/java/duke/command/AddEventCommand.java +++ b/src/main/java/duke/command/AddEventCommand.java @@ -9,16 +9,14 @@ */ public class AddEventCommand extends AddTaskCommand { public AddEventCommand(String command) throws DukeException { - // todo: use enum and then lambda to pass in delimiter super(command); s.useDelimiter("/at"); setDescription(); setDeadlineString(); - setDeadline(); } @Override - public Task createTask() { - return new EventTask(getDescription(), getDeadline()); + public Task createTask() throws DukeException { + return new EventTask(getDescription(), getDeadlineString()); } } diff --git a/src/main/java/duke/command/AddTaskCommand.java b/src/main/java/duke/command/AddTaskCommand.java index 70a6d79ead..4ec72d3837 100644 --- a/src/main/java/duke/command/AddTaskCommand.java +++ b/src/main/java/duke/command/AddTaskCommand.java @@ -1,13 +1,11 @@ package duke.command; -import duke.util.exception.DukeException; -import duke.util.exception.ExceptionType; import duke.task.Task; import duke.task.TaskList; import duke.util.Ui; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; +import duke.util.UiMessage; +import duke.util.exception.DukeException; +import duke.util.exception.ExceptionType; import java.util.NoSuchElementException; import java.util.Scanner; @@ -17,12 +15,8 @@ public abstract class AddTaskCommand implements Command { Scanner s; private String description; - private Date deadline; private String deadlineString; - // todo: move dateFormatter to somewhere else that makes more sense - private SimpleDateFormat dateFormatter = new SimpleDateFormat("dd/MM/yyyy HHmm"); - AddTaskCommand(String fullCommand) { super(); this.s = new Scanner(fullCommand); @@ -38,13 +32,13 @@ String getDescription() { } /** - * Returns the deadline of the task to be added. + * Returns the string representing the deadline of the task to be added. * For Deadline tasks, this refers to the expected date of completion. * For Event tasks, this refers to the expected date of occurrence. * @return Deadline of the task to be added. */ - Date getDeadline() { - return this.deadline; + String getDeadlineString() { + return this.deadlineString; } /** @@ -74,37 +68,24 @@ void setDeadlineString() throws DukeException { } } - /** - * Retrieves the deadline of the task to be added, based on command issued by user. - * @throws DukeException Application-specific exception thrown during execution. - */ - void setDeadline() throws DukeException { - try { - this.deadline = this.dateFormatter.parse(this.deadlineString); - } catch (ParseException e) { - // deadline entered in wrong format - throw new DukeException(ExceptionType.INVALID_DATE); - } - }; - /** * Creates the task to be added, based on command issued by the user. * @return Task to be added. */ - abstract Task createTask(); + abstract Task createTask() throws DukeException; /** * Creates a new Task based on command issued by the user, and adds it to the list of tasks. * @param tasks List of tasks. * @param ui UI to display to the user. + * @throws DukeException Application-specific exception thrown during execution. */ @Override - public void execute(TaskList tasks, Ui ui) { + public void execute(TaskList tasks, Ui ui) throws DukeException { Task newTask = createTask(); tasks.add(newTask); - // todo: use UiMessage - System.out.println("Okay! I've added: " + getDescription() - + ". Use list to see all your tasks!"); + ui.showMessage(UiMessage.TASK_ADDED); + ui.showMessage(UiMessage.HINT_LIST); } } diff --git a/src/main/java/duke/task/DeadlineTask.java b/src/main/java/duke/task/DeadlineTask.java index b0c428d03d..252bb649fa 100644 --- a/src/main/java/duke/task/DeadlineTask.java +++ b/src/main/java/duke/task/DeadlineTask.java @@ -1,5 +1,8 @@ package duke.task; +import static duke.util.DateTime.parseDate; + +import duke.util.exception.DukeException; import java.util.Date; /** @@ -11,12 +14,13 @@ public class DeadlineTask extends Task { /** * Constructs a new Deadline, with the specified description and date of completion. * @param description Description of the Deadline. - * @param by Expected date of completion of the Deadline. + * @param byString String representing expected date of completion of the Deadline. */ - public DeadlineTask(String description, Date by) { + public DeadlineTask(String description, String byString) throws DukeException { super(description); - this.by = by; this.type = TaskType.DEADLINE; + + this.by = parseDate(byString); } /** diff --git a/src/main/java/duke/task/EventTask.java b/src/main/java/duke/task/EventTask.java index 90e7b7fb3e..45777d3ca0 100644 --- a/src/main/java/duke/task/EventTask.java +++ b/src/main/java/duke/task/EventTask.java @@ -1,5 +1,8 @@ package duke.task; +import static duke.util.DateTime.parseDate; + +import duke.util.exception.DukeException; import java.util.Date; /** @@ -11,12 +14,13 @@ public class EventTask extends Task { /** * Constructs a new Event, with the specified description and date of occurrence. * @param description Description of the Event. - * @param at Expected date of occurrence of the Event. + * @param atString String representing expected date of occurrence of the Event. */ - public EventTask(String description, Date at) { + public EventTask(String description, String atString) throws DukeException { super(description); - this.at = at; this.type = TaskType.EVENT; + + this.at = parseDate(atString); } /** diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java index 0a14457002..4287ea3fc9 100644 --- a/src/main/java/duke/task/Task.java +++ b/src/main/java/duke/task/Task.java @@ -105,10 +105,6 @@ private TaskPriority getPriority() { } private boolean hasPriority() { - if (this.getPriority() == null) { - return false; - } else { - return true; - } + return this.getPriority() != null; } } diff --git a/src/main/java/duke/task/TaskType.java b/src/main/java/duke/task/TaskType.java index 2849a35054..9d1c09609a 100644 --- a/src/main/java/duke/task/TaskType.java +++ b/src/main/java/duke/task/TaskType.java @@ -2,7 +2,6 @@ /** * Represents the possible types of Tasks. - * Possible values: TODO, DEADLINE, EVENT. */ public enum TaskType { DEADLINE("by", "D"), diff --git a/src/main/java/duke/task/TodoTask.java b/src/main/java/duke/task/TodoTask.java index c95131007c..8a02209f1d 100644 --- a/src/main/java/duke/task/TodoTask.java +++ b/src/main/java/duke/task/TodoTask.java @@ -8,7 +8,7 @@ public TodoTask(String description) { /** * Snoozes ("postpones") the given task. - * Not applicable to tasks of TODO type. + * Not applicable to TodoTasks. */ @Override public void snooze() { diff --git a/src/main/java/duke/util/DateTime.java b/src/main/java/duke/util/DateTime.java index 732155d041..5626a5b396 100644 --- a/src/main/java/duke/util/DateTime.java +++ b/src/main/java/duke/util/DateTime.java @@ -1,25 +1,21 @@ package duke.util; -import java.text.DateFormat; +import duke.util.exception.DukeException; +import duke.util.exception.ExceptionType; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; //import duke.util.Ui; public class DateTime { - // todo: date format is not implemented correctly - private static DateFormat dateFormat = new SimpleDateFormat("dd/mm/YYYY HHmm"); + private static SimpleDateFormat dateFormatter = new SimpleDateFormat("dd/MM/yyyy HHmm"); - public static Date parseDate(String date) { - Date d = null; + public static Date parseDate(String date) throws DukeException { try { - d = dateFormat.parse(date); + return dateFormatter.parse(date); } catch (ParseException e) { - // how to use ui's methods without passing Ui to this method? - System.out.println("Oops! You did not enter the date in an appropriate format.\n" + - "Try: DD/MM/YYYY HHmm instead."); + // deadline entered in wrong format + throw new DukeException(ExceptionType.INVALID_DATE); } - return d; } - } diff --git a/src/main/java/duke/util/UiMessage.java b/src/main/java/duke/util/UiMessage.java index 9ac1f005a6..ebd0599715 100644 --- a/src/main/java/duke/util/UiMessage.java +++ b/src/main/java/duke/util/UiMessage.java @@ -12,8 +12,10 @@ public enum UiMessage { TASKS_SAVED("Success! Your tasks have been saved to: "), TASKS_NOT_SAVED("Your task list is empty! Adios :)"), TASKS_NOT_FOUND("Existing tasks file not found! Starting duke afresh..."), - // miscellaneous - LINE("____________________________________________________________"); + // commands + TASK_ADDED("Okay! I've added the task."), + // helpers + HINT_LIST(". Use list to see all your tasks!"); private final String message; From b744f1d3a506e0cff9b362f779ce17ebc18aa6f5 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Mon, 30 Sep 2019 00:39:50 +0800 Subject: [PATCH 42/84] implement snoozeDate() and snooze() methods --- src/main/java/duke/command/AddDeadlineCommand.java | 1 + src/main/java/duke/command/AddEventCommand.java | 1 + src/main/java/duke/command/AddTodoCommand.java | 6 ------ src/main/java/duke/command/FindCommand.java | 1 - src/main/java/duke/command/SnoozeCommand.java | 2 ++ src/main/java/duke/task/DeadlineTask.java | 3 ++- src/main/java/duke/task/EventTask.java | 3 ++- src/main/java/duke/util/DateTime.java | 9 +++++++++ src/main/java/duke/util/UiMessage.java | 3 ++- 9 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/main/java/duke/command/AddDeadlineCommand.java b/src/main/java/duke/command/AddDeadlineCommand.java index fb32e07f9d..8c5854e578 100644 --- a/src/main/java/duke/command/AddDeadlineCommand.java +++ b/src/main/java/duke/command/AddDeadlineCommand.java @@ -17,6 +17,7 @@ public AddDeadlineCommand(String command) throws DukeException { @Override public Task createTask() throws DukeException { + // todo: add assertion here return new DeadlineTask(getDescription(), getDeadlineString()); } } diff --git a/src/main/java/duke/command/AddEventCommand.java b/src/main/java/duke/command/AddEventCommand.java index c7077edbc2..c7322a4f52 100644 --- a/src/main/java/duke/command/AddEventCommand.java +++ b/src/main/java/duke/command/AddEventCommand.java @@ -17,6 +17,7 @@ public AddEventCommand(String command) throws DukeException { @Override public Task createTask() throws DukeException { + // todo: add assertion here return new EventTask(getDescription(), getDeadlineString()); } } diff --git a/src/main/java/duke/command/AddTodoCommand.java b/src/main/java/duke/command/AddTodoCommand.java index f6f5ad018a..bfe715b992 100644 --- a/src/main/java/duke/command/AddTodoCommand.java +++ b/src/main/java/duke/command/AddTodoCommand.java @@ -3,7 +3,6 @@ import duke.task.Task; import duke.task.TodoTask; import duke.util.exception.DukeException; -import java.util.Date; /** * Represents a command to create and add a TodoTask. @@ -15,11 +14,6 @@ public AddTodoCommand(String fullCommand) throws DukeException { setDescription(); } - @Override - Date getDeadline() { - return null; - } - @Override public Task createTask() { return new TodoTask(getDescription()); diff --git a/src/main/java/duke/command/FindCommand.java b/src/main/java/duke/command/FindCommand.java index d23a505762..693a372e42 100644 --- a/src/main/java/duke/command/FindCommand.java +++ b/src/main/java/duke/command/FindCommand.java @@ -34,7 +34,6 @@ public void execute(TaskList tasks, Ui ui) throws DukeException { // if ok, find and return matching tasks TaskList matchingTasks = tasks.findTasks(keyword); - // todo: find tasks does not return taskId of original tasks if (matchingTasks.isEmpty()) { throw new DukeException(ExceptionType.NO_MATCHING_TASKS); } else { diff --git a/src/main/java/duke/command/SnoozeCommand.java b/src/main/java/duke/command/SnoozeCommand.java index 47639cfcd2..d7276a631e 100644 --- a/src/main/java/duke/command/SnoozeCommand.java +++ b/src/main/java/duke/command/SnoozeCommand.java @@ -3,6 +3,7 @@ import duke.task.Task; import duke.task.TaskList; import duke.util.Ui; +import duke.util.UiMessage; import duke.util.exception.DukeException; /** @@ -24,5 +25,6 @@ public SnoozeCommand(String fullCommand) { public void execute(TaskList tasks, Ui ui) throws DukeException { Task task = getTaskById(tasks); task.snooze(); + ui.showMessage(UiMessage.TASK_SNOOZED); } } diff --git a/src/main/java/duke/task/DeadlineTask.java b/src/main/java/duke/task/DeadlineTask.java index 252bb649fa..896690573e 100644 --- a/src/main/java/duke/task/DeadlineTask.java +++ b/src/main/java/duke/task/DeadlineTask.java @@ -1,6 +1,7 @@ package duke.task; import static duke.util.DateTime.parseDate; +import static duke.util.DateTime.snoozeDate; import duke.util.exception.DukeException; import java.util.Date; @@ -36,6 +37,6 @@ public String toString() { @Override public void snooze() { - // todo + this.by = snoozeDate(this.by); } } diff --git a/src/main/java/duke/task/EventTask.java b/src/main/java/duke/task/EventTask.java index 45777d3ca0..d2c4582760 100644 --- a/src/main/java/duke/task/EventTask.java +++ b/src/main/java/duke/task/EventTask.java @@ -1,6 +1,7 @@ package duke.task; import static duke.util.DateTime.parseDate; +import static duke.util.DateTime.snoozeDate; import duke.util.exception.DukeException; import java.util.Date; @@ -36,6 +37,6 @@ public String toString() { @Override public void snooze() { - // todo + this.at = snoozeDate(this.at); } } diff --git a/src/main/java/duke/util/DateTime.java b/src/main/java/duke/util/DateTime.java index 5626a5b396..fabc71fbc9 100644 --- a/src/main/java/duke/util/DateTime.java +++ b/src/main/java/duke/util/DateTime.java @@ -4,6 +4,7 @@ import duke.util.exception.ExceptionType; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.Calendar; import java.util.Date; //import duke.util.Ui; @@ -18,4 +19,12 @@ public static Date parseDate(String date) throws DukeException { throw new DukeException(ExceptionType.INVALID_DATE); } } + + public static Date snoozeDate(Date date) { + Calendar c = Calendar.getInstance(); + c.setTime(date); + c.add(Calendar.DATE, 1); + date = c.getTime(); + return date; + } } diff --git a/src/main/java/duke/util/UiMessage.java b/src/main/java/duke/util/UiMessage.java index ebd0599715..b126de3208 100644 --- a/src/main/java/duke/util/UiMessage.java +++ b/src/main/java/duke/util/UiMessage.java @@ -14,8 +14,9 @@ public enum UiMessage { TASKS_NOT_FOUND("Existing tasks file not found! Starting duke afresh..."), // commands TASK_ADDED("Okay! I've added the task."), + TASK_SNOOZED("Okay! The task has been snoozed by 1 day."), // helpers - HINT_LIST(". Use list to see all your tasks!"); + HINT_LIST("Use list to see all your tasks!"); private final String message; From 8b3d7c6889ac20794284cf3e80e65f4d65f30534 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Mon, 30 Sep 2019 00:53:30 +0800 Subject: [PATCH 43/84] new jar file for v0.2 --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9d0f784119..781097faab 100644 --- a/build.gradle +++ b/build.gradle @@ -28,7 +28,7 @@ test { shadowJar { archiveBaseName = "duke" - archiveVersion = "0.1" + archiveVersion = "0.2" archiveClassifier = null archiveAppendix = null } From a89e4913a90a5b4adaa5bb0e716e1bd8b71df379 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Mon, 30 Sep 2019 01:03:10 +0800 Subject: [PATCH 44/84] configure build.gradle for JavaFX and install SceneBuilder --- build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build.gradle b/build.gradle index 9d0f784119..65bb586968 100644 --- a/build.gradle +++ b/build.gradle @@ -2,6 +2,7 @@ plugins { id 'java' id 'application' id 'com.github.johnrengelman.shadow' version '5.1.0' + id "org.openjfx.javafxplugin" version "0.0.8" } version '0.1.0' @@ -10,6 +11,11 @@ repositories { mavenCentral() } +javafx { + version = "11.0.2" + modules = [ 'javafx.controls', 'javafx.fxml' ] +} + application { mainClassName = 'duke.Duke' } From 8d0aa6769a14878ea5918c1f3c2cff9624fae742 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Mon, 30 Sep 2019 09:40:31 +0800 Subject: [PATCH 45/84] follow GUI setup tutorial, original application is not broken (yay!) --- build.gradle | 23 +++++++++- src/main/java/duke/DialogBox.java | 61 +++++++++++++++++++++++++ src/main/java/duke/Duke.java | 21 ++++++++- src/main/java/duke/Launcher.java | 12 +++++ src/main/java/duke/Main.java | 30 ++++++++++++ src/main/java/duke/MainWindow.java | 52 +++++++++++++++++++++ src/main/java/duke/util/Ui.java | 4 ++ src/main/resources/view/DialogBox.fxml | 16 +++++++ src/main/resources/view/MainWindow.fxml | 14 ++++++ 9 files changed, 229 insertions(+), 4 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/view/DialogBox.fxml create mode 100644 src/main/resources/view/MainWindow.fxml diff --git a/build.gradle b/build.gradle index 65bb586968..7a0f8ddd5f 100644 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ plugins { id 'java' id 'application' id 'com.github.johnrengelman.shadow' version '5.1.0' - id "org.openjfx.javafxplugin" version "0.0.8" + id 'org.openjfx.javafxplugin' version '0.0.8' } version '0.1.0' @@ -12,7 +12,7 @@ repositories { } javafx { - version = "11.0.2" + version = "12.0.2" modules = [ 'javafx.controls', 'javafx.fxml' ] } @@ -25,6 +25,25 @@ run { } dependencies { + String javaFxVersion = '12' + 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' + implementation group: 'org.openjfx', name: 'javafx-media', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-media', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-media', version: javaFxVersion, classifier: 'linux' + implementation group: 'org.openjfx', name: 'javafx-web', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-web', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-web', version: javaFxVersion, classifier: 'linux' testImplementation 'org.junit.jupiter:junit-jupiter:5.5.0' } diff --git a/src/main/java/duke/DialogBox.java b/src/main/java/duke/DialogBox.java new file mode 100644 index 0000000000..1286339296 --- /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; + } +} diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index f5f3da7a13..c4383a4bde 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -12,8 +12,9 @@ public class Duke { private Storage storage; private TaskList tasks; private Ui ui; + private String filePath = "data/tasks.txt"; - public Duke(String filePath) { + public Duke() { ui = new Ui(); storage = new Storage(filePath); tasks = new TaskList(); @@ -50,7 +51,23 @@ private void run() { } public static void main(String[] args) { - Duke duke = new Duke("data/tasks.txt"); + Duke duke = new Duke(); duke.run(); } + + public String getResponse(String input) { + try { + Command c = Parser.parse(input); + c.execute(tasks, ui); + if (c.isExit()) { + System.exit(0); + } + } catch (DukeException e) { + ui.showError(e); + } + + // dummy implementation + return "Duke heard: " + input; + //return ui.getResponse(); + } } 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..928a48b313 --- /dev/null +++ b/src/main/java/duke/Main.java @@ -0,0 +1,30 @@ +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(); + } + } +} \ No newline at end of file diff --git a/src/main/java/duke/MainWindow.java b/src/main/java/duke/MainWindow.java new file mode 100644 index 0000000000..02085af830 --- /dev/null +++ b/src/main/java/duke/MainWindow.java @@ -0,0 +1,52 @@ +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/DaUser.png")); + private Image dukeImage = new Image(this.getClass().getResourceAsStream("/images/DaDuke.png")); + + @FXML + public void initialize() { + scrollPane.vvalueProperty().bind(dialogContainer.heightProperty()); + } + + public void setDuke(Duke d) { + duke = d; + } + + /** + * Creates two dialog boxes, one echoing user input and the other containing Duke's reply and then appends them to + * the dialog container. Clears the user input after processing. + */ + @FXML + private void handleUserInput() { + String input = userInput.getText(); + String response = duke.getResponse(input); + dialogContainer.getChildren().addAll( + DialogBox.getUserDialog(input, userImage), + DialogBox.getDukeDialog(response, dukeImage) + ); + userInput.clear(); + } +} \ No newline at end of file diff --git a/src/main/java/duke/util/Ui.java b/src/main/java/duke/util/Ui.java index b861fd852e..7868394aca 100644 --- a/src/main/java/duke/util/Ui.java +++ b/src/main/java/duke/util/Ui.java @@ -47,4 +47,8 @@ public void showTasks(TaskList matchingTasks) { System.out.println("Here are the matching tasks in your list:"); matchingTasks.printList(); } + +// public String getResponse() { +// // todo +// } } diff --git a/src/main/resources/view/DialogBox.fxml b/src/main/resources/view/DialogBox.fxml new file mode 100644 index 0000000000..c9521bd5af --- /dev/null +++ b/src/main/resources/view/DialogBox.fxml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + \ 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..9f2d7b1cf0 --- /dev/null +++ b/src/main/resources/view/MainWindow.fxml @@ -0,0 +1,14 @@ + + + + + + + + + + + From c6e12d8bdc76e649ee3df754626ec47c4b8d408c Mon Sep 17 00:00:00 2001 From: nattanyz Date: Mon, 30 Sep 2019 09:54:12 +0800 Subject: [PATCH 46/84] manage to compile and run, opens GUI window --- src/main/java/duke/MainWindow.java | 4 +- src/main/resources/images/kawaii_robot.svg | 201 ++++++++++++++++ .../resources/images/kawaii_robot_power.svg | 220 ++++++++++++++++++ src/main/resources/view/MainWindow.fxml | 17 +- 4 files changed, 434 insertions(+), 8 deletions(-) create mode 100644 src/main/resources/images/kawaii_robot.svg create mode 100644 src/main/resources/images/kawaii_robot_power.svg diff --git a/src/main/java/duke/MainWindow.java b/src/main/java/duke/MainWindow.java index 02085af830..a4f6522d07 100644 --- a/src/main/java/duke/MainWindow.java +++ b/src/main/java/duke/MainWindow.java @@ -23,8 +23,8 @@ public class MainWindow extends AnchorPane { private Duke duke; - private Image userImage = new Image(this.getClass().getResourceAsStream("/images/DaUser.png")); - private Image dukeImage = new Image(this.getClass().getResourceAsStream("/images/DaDuke.png")); + private Image userImage = new Image(this.getClass().getResourceAsStream("/images/kawaii_robot.svg")); + private Image dukeImage = new Image(this.getClass().getResourceAsStream("/images/kawaii_robot_power.svg")); @FXML public void initialize() { diff --git a/src/main/resources/images/kawaii_robot.svg b/src/main/resources/images/kawaii_robot.svg new file mode 100644 index 0000000000..ec5d750c4e --- /dev/null +++ b/src/main/resources/images/kawaii_robot.svg @@ -0,0 +1,201 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/images/kawaii_robot_power.svg b/src/main/resources/images/kawaii_robot_power.svg new file mode 100644 index 0000000000..fb277ffa06 --- /dev/null +++ b/src/main/resources/images/kawaii_robot_power.svg @@ -0,0 +1,220 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml index 9f2d7b1cf0..9497d0e360 100644 --- a/src/main/resources/view/MainWindow.fxml +++ b/src/main/resources/view/MainWindow.fxml @@ -6,9 +6,14 @@ - - - + + + + + + + - + - \ No newline at end of file + From 6bfa580a259241b27b44a442aea522f56c2e7468 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Mon, 30 Sep 2019 11:40:34 +0800 Subject: [PATCH 49/84] rectify MainWindow fit --- src/main/resources/view/MainWindow.fxml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml index f6f66d84a5..edcbf33fe7 100644 --- a/src/main/resources/view/MainWindow.fxml +++ b/src/main/resources/view/MainWindow.fxml @@ -11,9 +11,9 @@ - + - + @@ -30,8 +30,11 @@ + + + - + From 6c84fec50b49fef140957c034d8223c0fff047ee Mon Sep 17 00:00:00 2001 From: nattanyz Date: Mon, 30 Sep 2019 11:56:09 +0800 Subject: [PATCH 50/84] refactor: move GUI-related classes to duke.gui, add title and application icon --- src/main/java/duke/Main.java | 7 ++++++- src/main/java/duke/{ => gui}/DialogBox.java | 8 ++------ src/main/java/duke/{ => gui}/MainWindow.java | 3 ++- src/main/resources/images/coffee.png | Bin 0 -> 709 bytes src/main/resources/view/MainWindow.fxml | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) rename src/main/java/duke/{ => gui}/DialogBox.java (90%) rename src/main/java/duke/{ => gui}/MainWindow.java (97%) create mode 100644 src/main/resources/images/coffee.png diff --git a/src/main/java/duke/Main.java b/src/main/java/duke/Main.java index 928a48b313..83116a3712 100644 --- a/src/main/java/duke/Main.java +++ b/src/main/java/duke/Main.java @@ -1,9 +1,11 @@ package duke; -import java.io.IOException; +import duke.gui.MainWindow; +import java.io.IOException; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; +import javafx.scene.image.Image; import javafx.scene.layout.AnchorPane; import javafx.stage.Stage; @@ -12,6 +14,7 @@ */ public class Main extends Application { + private Image dukeIcon = new Image(getClass().getResourceAsStream("/images/coffee.png")); private Duke duke = new Duke(); @Override @@ -21,6 +24,8 @@ public void start(Stage stage) { AnchorPane ap = fxmlLoader.load(); Scene scene = new Scene(ap); stage.setScene(scene); + stage.setTitle("Duke"); + stage.getIcons().add(dukeIcon); fxmlLoader.getController().setDuke(duke); stage.show(); } catch (IOException e) { diff --git a/src/main/java/duke/DialogBox.java b/src/main/java/duke/gui/DialogBox.java similarity index 90% rename from src/main/java/duke/DialogBox.java rename to src/main/java/duke/gui/DialogBox.java index 069b7f7f08..3b794679d8 100644 --- a/src/main/java/duke/DialogBox.java +++ b/src/main/java/duke/gui/DialogBox.java @@ -1,4 +1,4 @@ -package duke; +package duke.gui; import java.io.IOException; import java.util.Collections; @@ -9,7 +9,6 @@ import javafx.geometry.Pos; import javafx.scene.Node; import javafx.scene.control.Label; -import javafx.scene.image.ImageView; import javafx.scene.layout.HBox; /** @@ -20,8 +19,6 @@ public class DialogBox extends HBox { @FXML private Label dialog; - @FXML - private ImageView displayPicture; private DialogBox(String text) { try { @@ -34,7 +31,6 @@ private DialogBox(String text) { } dialog.setText(text); - //displayPicture.setImage(img); } /** @@ -53,7 +49,7 @@ public static DialogBox getUserDialog(String text) { public static DialogBox getDukeDialog(String text) { var db = new DialogBox(text); -// db.flip(); + db.flip(); return db; } } diff --git a/src/main/java/duke/MainWindow.java b/src/main/java/duke/gui/MainWindow.java similarity index 97% rename from src/main/java/duke/MainWindow.java rename to src/main/java/duke/gui/MainWindow.java index 7f128b5a76..da992adf32 100644 --- a/src/main/java/duke/MainWindow.java +++ b/src/main/java/duke/gui/MainWindow.java @@ -1,5 +1,6 @@ -package duke; +package duke.gui; +import duke.Duke; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.ScrollPane; diff --git a/src/main/resources/images/coffee.png b/src/main/resources/images/coffee.png new file mode 100644 index 0000000000000000000000000000000000000000..14f2a825b2171b6f127336aa76a864bdb879c3f5 GIT binary patch literal 709 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE0wix1Z>k4UEa{HEjtmSN`?>!lvVtU&J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10f+@+{-GzZ+Rj;xUkjGiz z5n0T@z;^_M8K-LVNdpDhOFVsD*&lPtF`Kb}d1HN#fq`+dr;B5V$ML;aY%@dxMUH;F zpO!4BqVeP6kBh7#f`YD&N3~jSL`ZJgv^mHnV8bP?2u-C34G$^qjhnZaEaO|5 zZ#D~@Tf%&-<-!K}I|7IH^uBEP?X)9emAR9}ozn&v7MeHAG!xa<;xu6QoBqmHOIvFt z-w(|e?+1GXru95i$m2}Bsln#Um3VMl$$@>qqR>@?~ zp-rX_TGz+UW4>B{&u_IvIP=4u`Ri6aH~DD4I>@Z()U}lJi)MMA{kEE0>GK)udwe_Q z@^aYES#Z2+*R|-!X@RBJZ`BFe9Gr07N#eCSqlr&L>|dq`_F4NGxh1c;zA530ia&9) zNAgT%mM4et+CS~TB9ia+g{@(f-+bo2?Uuji&#hCBlE0n4{o#Ih<2S*VX1nk5|DN*G z`fcgDFL4*1hQ9f}OVWK$h=#~&hJ6|$X|gX_Vot|AX!biGCvWtoHTmtc`0k>rySZCf zcLHNfwZt`|BqgyV)hf9t6-Y4{85mmX8d&NY8-y4bTbY_z8JKGu7+4t?L`t>lp=ij> zPsvQH#H~TY-F6aCgCxj?;QX|b^2DN4hVt@qz0ADq;^f4FRK5J7^x5xhq=1STJYD@< J);T3K0RSS35k>$2 literal 0 HcmV?d00001 diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml index edcbf33fe7..e58651f1d7 100644 --- a/src/main/resources/view/MainWindow.fxml +++ b/src/main/resources/view/MainWindow.fxml @@ -9,7 +9,7 @@ - + From d9b9f4dae698f496eb88e7a5130ac2d5daa4f938 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Mon, 30 Sep 2019 12:17:33 +0800 Subject: [PATCH 51/84] fix scrolling and resizing behaviour of MainWindow, add some JavaDoc --- src/main/java/duke/Main.java | 14 +++++++++++++- src/main/java/duke/gui/MainWindow.java | 18 +++++++++++++----- src/main/resources/view/DialogBox.fxml | 3 +-- src/main/resources/view/MainWindow.fxml | 7 +++++-- 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/main/java/duke/Main.java b/src/main/java/duke/Main.java index 83116a3712..9fadabe68d 100644 --- a/src/main/java/duke/Main.java +++ b/src/main/java/duke/Main.java @@ -14,19 +14,31 @@ */ public class Main extends Application { + /** Image to be used as application icon for Duke.*/ private Image dukeIcon = new Image(getClass().getResourceAsStream("/images/coffee.png")); + + /** Underlying instance of Duke created when application runs.*/ private Duke duke = new Duke(); @Override public void start(Stage stage) { try { + // create new scene using MainWindow fxml FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("/view/MainWindow.fxml")); AnchorPane ap = fxmlLoader.load(); Scene scene = new Scene(ap); + + // set the scene to display on the stage stage.setScene(scene); + + // set underlying instance of Duke + fxmlLoader.getController().setDuke(duke); + + // set title and icon for the window stage.setTitle("Duke"); stage.getIcons().add(dukeIcon); - fxmlLoader.getController().setDuke(duke); + + // display the window stage.show(); } catch (IOException e) { e.printStackTrace(); diff --git a/src/main/java/duke/gui/MainWindow.java b/src/main/java/duke/gui/MainWindow.java index da992adf32..ad780e92ed 100644 --- a/src/main/java/duke/gui/MainWindow.java +++ b/src/main/java/duke/gui/MainWindow.java @@ -1,5 +1,8 @@ package duke.gui; +import static duke.gui.DialogBox.getDukeDialog; +import static duke.gui.DialogBox.getUserDialog; + import duke.Duke; import javafx.fxml.FXML; import javafx.scene.control.Button; @@ -41,12 +44,17 @@ public void setDuke(Duke d) { */ @FXML private void handleUserInput() { + // get and display user input String input = userInput.getText(); - String response = duke.getResponse(input); - dialogContainer.getChildren().addAll( - DialogBox.getUserDialog(input), - DialogBox.getDukeDialog(response) - ); + DialogBox inputDialog = getUserDialog(input); + dialogContainer.getChildren().add(inputDialog); + + // clear user input field userInput.clear(); + + // get and display output from Duke + String response = duke.getResponse(input); + DialogBox outputDialog = getDukeDialog(response); + dialogContainer.getChildren().add(outputDialog); } } \ No newline at end of file diff --git a/src/main/resources/view/DialogBox.fxml b/src/main/resources/view/DialogBox.fxml index 89478f4e96..e984468766 100644 --- a/src/main/resources/view/DialogBox.fxml +++ b/src/main/resources/view/DialogBox.fxml @@ -5,8 +5,7 @@ - + - + - + + + + From eaaf797642126c3e57be3033b07a1fd7567f12f0 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Mon, 30 Sep 2019 12:28:44 +0800 Subject: [PATCH 52/84] refactor: organise methods in Duke class --- src/main/java/duke/Duke.java | 40 ++++++++++++++------- src/main/java/duke/command/ExitCommand.java | 3 +- src/main/java/duke/gui/MainWindow.java | 4 +++ src/main/java/duke/util/Ui.java | 2 ++ 4 files changed, 36 insertions(+), 13 deletions(-) diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index 4d7594041d..b317145301 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -14,29 +14,28 @@ public class Duke { private Ui ui; private String filePath = "data/tasks.txt"; + /** + * Creates a new instance of Duke, with the default filePath. + */ public Duke() { ui = new Ui(); storage = new Storage(filePath); tasks = new TaskList(); - - ui.showMessage(UiMessage.WELCOME); - - try { - TaskList tasksFromFile = storage.load(); - tasks = tasksFromFile; - } catch (Exception e) { - // temporary haxx - e.printStackTrace(); - } } + /** + * Runs Duke from the CLI. All output is displayed in the CLI. + * Not used when Duke is run from the GUI. + */ private void run() { + ui.showMessage(UiMessage.WELCOME); + initializeStorage(); + boolean isExit = false; while (!isExit) { try { String fullCommand = ui.readCommand(); ui.showLine(); // show the divider line ("_______") - // todo: remove redundant showLine() for bye command Command c = Parser.parse(fullCommand); c.execute(tasks, ui); isExit = c.isExit(); @@ -47,9 +46,13 @@ private void run() { } } storage.save(tasks); - ui.showMessage(UiMessage.GOODBYE); } + /** + * Creates and runs a new instance of Duke. + * Invoked when Duke is run from the CLI. + * @param args Arguments supplied by the user. + */ public static void main(String[] args) { Duke duke = new Duke(); duke.run(); @@ -67,4 +70,17 @@ public String getResponse(String input) { return "Duke heard: " + input; //return ui.getResponse(); } + + /** + * Attempts to import an existing task list. + */ + private void initializeStorage() { + try { + TaskList tasksFromFile = storage.load(); + tasks = tasksFromFile; + } catch (Exception e) { + // temporary haxx + e.printStackTrace(); + } + } } diff --git a/src/main/java/duke/command/ExitCommand.java b/src/main/java/duke/command/ExitCommand.java index f3db221f5e..1b7bfc4fbf 100644 --- a/src/main/java/duke/command/ExitCommand.java +++ b/src/main/java/duke/command/ExitCommand.java @@ -2,6 +2,7 @@ import duke.task.TaskList; import duke.util.Ui; +import duke.util.UiMessage; /** * Exits the application. @@ -15,7 +16,7 @@ public class ExitCommand implements Command { */ @Override public void execute(TaskList tasks, Ui ui) { - // do nothing + ui.showMessage(UiMessage.GOODBYE); } /** diff --git a/src/main/java/duke/gui/MainWindow.java b/src/main/java/duke/gui/MainWindow.java index ad780e92ed..fff548e746 100644 --- a/src/main/java/duke/gui/MainWindow.java +++ b/src/main/java/duke/gui/MainWindow.java @@ -57,4 +57,8 @@ private void handleUserInput() { DialogBox outputDialog = getDukeDialog(response); dialogContainer.getChildren().add(outputDialog); } + + public VBox getDialogContainer() { + return this.dialogContainer; + } } \ No newline at end of file diff --git a/src/main/java/duke/util/Ui.java b/src/main/java/duke/util/Ui.java index 7868394aca..7bd8d7a30b 100644 --- a/src/main/java/duke/util/Ui.java +++ b/src/main/java/duke/util/Ui.java @@ -3,9 +3,11 @@ import duke.task.TaskList; import duke.util.exception.DukeException; import java.util.Scanner; +import javafx.scene.layout.VBox; public class Ui { private Scanner in; + private VBox dialogContainer; public Ui() { this.in = new Scanner(System.in); From 97eaa87a5550b2b7c262c990fc54ea12a4ca2458 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Mon, 30 Sep 2019 12:49:12 +0800 Subject: [PATCH 53/84] replace Ui class with Ui interface and Cli and Gui implementations, attempt to do the same for Duke --- .../java/duke/util/{Ui.java => cli/Cli.java} | 21 +++++++------------ .../java/duke/{ => util}/gui/DialogBox.java | 0 .../java/duke/{ => util}/gui/MainWindow.java | 0 3 files changed, 7 insertions(+), 14 deletions(-) rename src/main/java/duke/util/{Ui.java => cli/Cli.java} (63%) rename src/main/java/duke/{ => util}/gui/DialogBox.java (100%) rename src/main/java/duke/{ => util}/gui/MainWindow.java (100%) diff --git a/src/main/java/duke/util/Ui.java b/src/main/java/duke/util/cli/Cli.java similarity index 63% rename from src/main/java/duke/util/Ui.java rename to src/main/java/duke/util/cli/Cli.java index 7bd8d7a30b..0ff2982e2b 100644 --- a/src/main/java/duke/util/Ui.java +++ b/src/main/java/duke/util/cli/Cli.java @@ -3,13 +3,11 @@ import duke.task.TaskList; import duke.util.exception.DukeException; import java.util.Scanner; -import javafx.scene.layout.VBox; -public class Ui { +public class Cli implements Ui { private Scanner in; - private VBox dialogContainer; - public Ui() { + public Cli() { this.in = new Scanner(System.in); } @@ -29,25 +27,20 @@ public void showLine() { System.out.println(line); } - /** - * Displays the required message in the UI, given the type of message required. - * @param uiMessage Enum indicating type of message required to be displayed. - */ + @Override public void showMessage(UiMessage uiMessage) { System.out.println(uiMessage.getMessage()); } - /** - * Displays the required error message in the UI, given the type of exception thrown. - * @param exception Exception thrown by the application. - */ + @Override public void showError(DukeException exception) { System.out.println(exception.getMessage()); } - public void showTasks(TaskList matchingTasks) { + @Override + public void showTasks(TaskList tasks) { System.out.println("Here are the matching tasks in your list:"); - matchingTasks.printList(); + tasks.printList(); } // public String getResponse() { diff --git a/src/main/java/duke/gui/DialogBox.java b/src/main/java/duke/util/gui/DialogBox.java similarity index 100% rename from src/main/java/duke/gui/DialogBox.java rename to src/main/java/duke/util/gui/DialogBox.java diff --git a/src/main/java/duke/gui/MainWindow.java b/src/main/java/duke/util/gui/MainWindow.java similarity index 100% rename from src/main/java/duke/gui/MainWindow.java rename to src/main/java/duke/util/gui/MainWindow.java From be0d50fe5d62f7a150622d424875b8504c3d64c8 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Mon, 30 Sep 2019 12:53:06 +0800 Subject: [PATCH 54/84] continue refactoring in earlier commit --- src/main/java/duke/Duke.java | 34 ++++++++------------- src/main/java/duke/Main.java | 2 +- src/main/java/duke/command/FindCommand.java | 4 +-- src/main/java/duke/command/ListCommand.java | 4 +-- src/main/java/duke/util/Ui.java | 24 +++++++++++++++ src/main/java/duke/util/cli/Cli.java | 4 ++- src/main/java/duke/util/gui/DialogBox.java | 2 +- src/main/java/duke/util/gui/GuiDuke.java | 29 ++++++++++++++++++ src/main/java/duke/util/gui/MainWindow.java | 6 ++-- src/main/resources/view/MainWindow.fxml | 2 +- 10 files changed, 78 insertions(+), 33 deletions(-) create mode 100644 src/main/java/duke/util/Ui.java create mode 100644 src/main/java/duke/util/gui/GuiDuke.java diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index b317145301..b515ab9f5f 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -1,33 +1,36 @@ package duke; -import duke.util.UiMessage; import duke.command.Command; -import duke.util.exception.DukeException; import duke.task.TaskList; import duke.util.Parser; import duke.util.Storage; import duke.util.Ui; +import duke.util.UiMessage; +import duke.util.cli.Cli; +import duke.util.exception.DukeException; public class Duke { - private Storage storage; - private TaskList tasks; - private Ui ui; - private String filePath = "data/tasks.txt"; + Storage storage; + TaskList tasks; + String filePath = "data/tasks.txt"; + + /** CLI implementation of Duke uses a Cli object to represent its UI. */ + Ui ui; /** * Creates a new instance of Duke, with the default filePath. */ public Duke() { - ui = new Ui(); + ui = new Cli(); storage = new Storage(filePath); tasks = new TaskList(); } /** * Runs Duke from the CLI. All output is displayed in the CLI. - * Not used when Duke is run from the GUI. +// * Not used when Duke is run from the GUI. */ - private void run() { + void run() { ui.showMessage(UiMessage.WELCOME); initializeStorage(); @@ -58,19 +61,6 @@ public static void main(String[] args) { duke.run(); } - public String getResponse(String input) { - try { - Command c = Parser.parse(input); - c.execute(tasks, ui); - } catch (DukeException e) { - ui.showError(e); - } - - // dummy implementation - return "Duke heard: " + input; - //return ui.getResponse(); - } - /** * Attempts to import an existing task list. */ diff --git a/src/main/java/duke/Main.java b/src/main/java/duke/Main.java index 9fadabe68d..2d84c9f589 100644 --- a/src/main/java/duke/Main.java +++ b/src/main/java/duke/Main.java @@ -1,6 +1,6 @@ package duke; -import duke.gui.MainWindow; +import duke.util.gui.MainWindow; import java.io.IOException; import javafx.application.Application; import javafx.fxml.FXMLLoader; diff --git a/src/main/java/duke/command/FindCommand.java b/src/main/java/duke/command/FindCommand.java index 693a372e42..d650ba221d 100644 --- a/src/main/java/duke/command/FindCommand.java +++ b/src/main/java/duke/command/FindCommand.java @@ -1,9 +1,9 @@ package duke.command; -import duke.util.exception.DukeException; -import duke.util.exception.ExceptionType; import duke.task.TaskList; import duke.util.Ui; +import duke.util.exception.DukeException; +import duke.util.exception.ExceptionType; import java.util.InputMismatchException; import java.util.Scanner; diff --git a/src/main/java/duke/command/ListCommand.java b/src/main/java/duke/command/ListCommand.java index eeb292d940..a0bfd6a228 100644 --- a/src/main/java/duke/command/ListCommand.java +++ b/src/main/java/duke/command/ListCommand.java @@ -1,9 +1,9 @@ package duke.command; -import duke.util.exception.DukeException; -import duke.util.exception.ExceptionType; import duke.task.TaskList; import duke.util.Ui; +import duke.util.exception.DukeException; +import duke.util.exception.ExceptionType; public class ListCommand implements Command { diff --git a/src/main/java/duke/util/Ui.java b/src/main/java/duke/util/Ui.java new file mode 100644 index 0000000000..d90f109be3 --- /dev/null +++ b/src/main/java/duke/util/Ui.java @@ -0,0 +1,24 @@ +package duke.util; + +import duke.task.TaskList; +import duke.util.exception.DukeException; + +public interface Ui { + /** + * Displays the required message in the UI, given the type of message required. + * @param uiMessage Enum indicating type of message required to be displayed. + */ + void showMessage(UiMessage uiMessage); + + /** + * Displays the required error message in the UI, given the type of exception thrown. + * @param exception Exception thrown by the application. + */ + void showError(DukeException exception); + + /** + * Displays a list of tasks in the UI. + * @param tasks Tasks to be shown in the UI. + */ + void showTasks(TaskList tasks); +} diff --git a/src/main/java/duke/util/cli/Cli.java b/src/main/java/duke/util/cli/Cli.java index 0ff2982e2b..6e6a19d74d 100644 --- a/src/main/java/duke/util/cli/Cli.java +++ b/src/main/java/duke/util/cli/Cli.java @@ -1,6 +1,8 @@ -package duke.util; +package duke.util.cli; import duke.task.TaskList; +import duke.util.Ui; +import duke.util.UiMessage; import duke.util.exception.DukeException; import java.util.Scanner; diff --git a/src/main/java/duke/util/gui/DialogBox.java b/src/main/java/duke/util/gui/DialogBox.java index 3b794679d8..ce7c7c3351 100644 --- a/src/main/java/duke/util/gui/DialogBox.java +++ b/src/main/java/duke/util/gui/DialogBox.java @@ -1,4 +1,4 @@ -package duke.gui; +package duke.util.gui; import java.io.IOException; import java.util.Collections; diff --git a/src/main/java/duke/util/gui/GuiDuke.java b/src/main/java/duke/util/gui/GuiDuke.java new file mode 100644 index 0000000000..6fb6f1a66c --- /dev/null +++ b/src/main/java/duke/util/gui/GuiDuke.java @@ -0,0 +1,29 @@ +package duke.util.gui; + +import duke.Duke; + +public class GuiDuke extends Duke { + + /** + * Creates a new instance of Duke to be run from the GUI, with the default filePath. + */ + public GuiDuke() { +// ui = new Gui(); +// storage = new Storage(filePath); +// tasks = new TaskList(); + } + + public String getResponse(String input) { +// try { +// Command c = Parser.parse(input); +// c.execute(tasks, ui); +// } catch (DukeException e) { +// ui.showError(e); +// } + + // dummy implementation + return "Duke heard: " + input; + //return ui.getResponse(); + } + +} diff --git a/src/main/java/duke/util/gui/MainWindow.java b/src/main/java/duke/util/gui/MainWindow.java index fff548e746..7fde8f0c81 100644 --- a/src/main/java/duke/util/gui/MainWindow.java +++ b/src/main/java/duke/util/gui/MainWindow.java @@ -1,7 +1,7 @@ -package duke.gui; +package duke.util.gui; -import static duke.gui.DialogBox.getDukeDialog; -import static duke.gui.DialogBox.getUserDialog; +import static duke.util.gui.DialogBox.getDukeDialog; +import static duke.util.gui.DialogBox.getUserDialog; import duke.Duke; import javafx.fxml.FXML; diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml index b2579e0adf..3eb49b1d29 100644 --- a/src/main/resources/view/MainWindow.fxml +++ b/src/main/resources/view/MainWindow.fxml @@ -9,7 +9,7 @@ - + From d5daa2dc21f4c79d2ab958a29d5a459ebf6d82d1 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Mon, 30 Sep 2019 13:14:51 +0800 Subject: [PATCH 55/84] create CliDuke and GuiDuke classes to implement Duke interface, set default invocation of Duke from CLI to use CliDuke and GUI to use GuiDuke --- src/main/java/duke/Duke.java | 68 ++----------------- src/main/java/duke/Main.java | 3 +- src/main/java/duke/util/Ui.java | 6 ++ src/main/java/duke/util/cli/Cli.java | 23 +++---- src/main/java/duke/util/cli/CliDuke.java | 73 +++++++++++++++++++++ src/main/java/duke/util/gui/Gui.java | 29 ++++++++ src/main/java/duke/util/gui/GuiDuke.java | 25 +++++-- src/main/java/duke/util/gui/MainWindow.java | 5 +- 8 files changed, 148 insertions(+), 84 deletions(-) create mode 100644 src/main/java/duke/util/cli/CliDuke.java create mode 100644 src/main/java/duke/util/gui/Gui.java diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java index b515ab9f5f..dea6dd64a7 100644 --- a/src/main/java/duke/Duke.java +++ b/src/main/java/duke/Duke.java @@ -1,76 +1,22 @@ package duke; -import duke.command.Command; -import duke.task.TaskList; -import duke.util.Parser; -import duke.util.Storage; -import duke.util.Ui; -import duke.util.UiMessage; -import duke.util.cli.Cli; -import duke.util.exception.DukeException; +import duke.util.cli.CliDuke; -public class Duke { - Storage storage; - TaskList tasks; - String filePath = "data/tasks.txt"; - - /** CLI implementation of Duke uses a Cli object to represent its UI. */ - Ui ui; +public interface Duke { /** - * Creates a new instance of Duke, with the default filePath. + * Runs Duke. */ - public Duke() { - ui = new Cli(); - storage = new Storage(filePath); - tasks = new TaskList(); - } - - /** - * Runs Duke from the CLI. All output is displayed in the CLI. -// * Not used when Duke is run from the GUI. - */ - void run() { - ui.showMessage(UiMessage.WELCOME); - initializeStorage(); - - boolean isExit = false; - while (!isExit) { - try { - String fullCommand = ui.readCommand(); - ui.showLine(); // show the divider line ("_______") - Command c = Parser.parse(fullCommand); - c.execute(tasks, ui); - isExit = c.isExit(); - } catch (DukeException e) { - ui.showError(e); - } finally { - ui.showLine(); - } - } - storage.save(tasks); - } + void run(); /** * Creates and runs a new instance of Duke. * Invoked when Duke is run from the CLI. * @param args Arguments supplied by the user. */ - public static void main(String[] args) { - Duke duke = new Duke(); + static void main(String[] args) { + // running Duke from the CLI should instantiate CliDuke, as usual + Duke duke = new CliDuke(); duke.run(); } - - /** - * Attempts to import an existing task list. - */ - private void initializeStorage() { - try { - TaskList tasksFromFile = storage.load(); - tasks = tasksFromFile; - } catch (Exception e) { - // temporary haxx - e.printStackTrace(); - } - } } diff --git a/src/main/java/duke/Main.java b/src/main/java/duke/Main.java index 2d84c9f589..a2b576b30b 100644 --- a/src/main/java/duke/Main.java +++ b/src/main/java/duke/Main.java @@ -1,5 +1,6 @@ package duke; +import duke.util.gui.GuiDuke; import duke.util.gui.MainWindow; import java.io.IOException; import javafx.application.Application; @@ -18,7 +19,7 @@ public class Main extends Application { private Image dukeIcon = new Image(getClass().getResourceAsStream("/images/coffee.png")); /** Underlying instance of Duke created when application runs.*/ - private Duke duke = new Duke(); + private GuiDuke duke = new GuiDuke(); @Override public void start(Stage stage) { diff --git a/src/main/java/duke/util/Ui.java b/src/main/java/duke/util/Ui.java index d90f109be3..0fa72e7bd9 100644 --- a/src/main/java/duke/util/Ui.java +++ b/src/main/java/duke/util/Ui.java @@ -4,6 +4,12 @@ import duke.util.exception.DukeException; public interface Ui { + /** + * Returns the command entered by the user. + * @return Command entered by the user. + */ + String readCommand(); + /** * Displays the required message in the UI, given the type of message required. * @param uiMessage Enum indicating type of message required to be displayed. diff --git a/src/main/java/duke/util/cli/Cli.java b/src/main/java/duke/util/cli/Cli.java index 6e6a19d74d..74b6605038 100644 --- a/src/main/java/duke/util/cli/Cli.java +++ b/src/main/java/duke/util/cli/Cli.java @@ -13,22 +13,11 @@ public Cli() { this.in = new Scanner(System.in); } - /** - * Returns the command entered by the user. - * @return Command entered by the user. - */ + @Override public String readCommand() { return in.nextLine(); } - /** - * Displays a divider line in the UI. - */ - public void showLine() { - String line = "____________________________________________________________"; - System.out.println(line); - } - @Override public void showMessage(UiMessage uiMessage) { System.out.println(uiMessage.getMessage()); @@ -45,7 +34,11 @@ public void showTasks(TaskList tasks) { tasks.printList(); } -// public String getResponse() { -// // todo -// } + /** + * Displays a divider line in the UI. + */ + public void showLine() { + String line = "____________________________________________________________"; + System.out.println(line); + } } diff --git a/src/main/java/duke/util/cli/CliDuke.java b/src/main/java/duke/util/cli/CliDuke.java new file mode 100644 index 0000000000..22642a474b --- /dev/null +++ b/src/main/java/duke/util/cli/CliDuke.java @@ -0,0 +1,73 @@ +package duke.util.cli; + +import duke.Duke; +import duke.command.Command; +import duke.task.TaskList; +import duke.util.Parser; +import duke.util.Storage; +import duke.util.UiMessage; +import duke.util.exception.DukeException; + +public class CliDuke implements Duke { + Storage storage; + TaskList tasks; + String filePath = "data/tasks.txt"; + + /** CLI implementation of Duke uses a Cli object to represent its UI. */ + Cli ui; + + /** + * Creates a new instance of Duke, with the default filePath. + */ + public CliDuke() { + ui = new Cli(); + storage = new Storage(filePath); + tasks = new TaskList(); + } + + /** + * Runs Duke from the CLI. All output is displayed in the CLI. + */ + public void run() { + ui.showMessage(UiMessage.WELCOME); + initializeStorage(); + + boolean isExit = false; + while (!isExit) { + try { + String fullCommand = ui.readCommand(); + ui.showLine(); // show the divider line ("_______") + Command c = Parser.parse(fullCommand); + c.execute(tasks, ui); + isExit = c.isExit(); + } catch (DukeException e) { + ui.showError(e); + } finally { + ui.showLine(); + } + } + storage.save(tasks); + } + + /** + * Creates and runs a new instance of Duke from the CLI. + * @param args Arguments supplied by the user. + */ + public static void main(String[] args) { + CliDuke duke = new CliDuke(); + duke.run(); + } + + /** + * Attempts to import an existing task list. + */ + private void initializeStorage() { + try { + TaskList tasksFromFile = storage.load(); + tasks = tasksFromFile; + } catch (Exception e) { + // temporary haxx + e.printStackTrace(); + } + } +} diff --git a/src/main/java/duke/util/gui/Gui.java b/src/main/java/duke/util/gui/Gui.java new file mode 100644 index 0000000000..36f6b1d412 --- /dev/null +++ b/src/main/java/duke/util/gui/Gui.java @@ -0,0 +1,29 @@ +package duke.util.gui; + +import duke.task.TaskList; +import duke.util.Ui; +import duke.util.UiMessage; +import duke.util.exception.DukeException; + +public class Gui implements Ui { + + @Override + public String readCommand() { + return null; + } + + @Override + public void showMessage(UiMessage uiMessage) { + + } + + @Override + public void showError(DukeException exception) { + + } + + @Override + public void showTasks(TaskList tasks) { + + } +} diff --git a/src/main/java/duke/util/gui/GuiDuke.java b/src/main/java/duke/util/gui/GuiDuke.java index 6fb6f1a66c..5c2b0aefaa 100644 --- a/src/main/java/duke/util/gui/GuiDuke.java +++ b/src/main/java/duke/util/gui/GuiDuke.java @@ -1,18 +1,31 @@ package duke.util.gui; import duke.Duke; +import duke.task.TaskList; +import duke.util.Storage; -public class GuiDuke extends Duke { +public class GuiDuke implements Duke { + Storage storage; + TaskList tasks; + String filePath = "data/tasks.txt"; + + /** GUI implementation of Duke uses a Gui object to represent its UI. */ + Gui ui; /** * Creates a new instance of Duke to be run from the GUI, with the default filePath. */ public GuiDuke() { -// ui = new Gui(); -// storage = new Storage(filePath); -// tasks = new TaskList(); + ui = new Gui(); + storage = new Storage(filePath); + tasks = new TaskList(); } + /** + * Get response from Duke to be displayed in the UI. + * May not be required after UI implementation is refined. + * @return Response from Duke to be displayed in the UI. + */ public String getResponse(String input) { // try { // Command c = Parser.parse(input); @@ -26,4 +39,8 @@ public String getResponse(String input) { //return ui.getResponse(); } + @Override + public void run() { + + } } diff --git a/src/main/java/duke/util/gui/MainWindow.java b/src/main/java/duke/util/gui/MainWindow.java index 7fde8f0c81..8ab1fca04a 100644 --- a/src/main/java/duke/util/gui/MainWindow.java +++ b/src/main/java/duke/util/gui/MainWindow.java @@ -3,7 +3,6 @@ import static duke.util.gui.DialogBox.getDukeDialog; import static duke.util.gui.DialogBox.getUserDialog; -import duke.Duke; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.ScrollPane; @@ -24,7 +23,7 @@ public class MainWindow extends AnchorPane { @FXML private Button sendButton; - private Duke duke; + private GuiDuke duke; //private Image userImage = new Image(this.getClass().getResourceAsStream("/images/kawaii_robot.png")); //private Image dukeImage = new Image(this.getClass().getResourceAsStream("/images/kawaii_robot_power.png")); @@ -34,7 +33,7 @@ public void initialize() { scrollPane.vvalueProperty().bind(dialogContainer.heightProperty()); } - public void setDuke(Duke d) { + public void setDuke(GuiDuke d) { duke = d; } From 64b49d21505cca28703cb8f067e1cc43c5ca64ff Mon Sep 17 00:00:00 2001 From: nattanyz Date: Mon, 30 Sep 2019 13:48:31 +0800 Subject: [PATCH 56/84] refactor: rename DialogBox to MessageBox.add ColourScheme enum to take care of customisable colour schemes. configure getUserDialog and getDukeDialog to use background and text colour --- src/main/java/duke/util/gui/ColourScheme.java | 47 +++++++++++++++ src/main/java/duke/util/gui/DialogBox.java | 55 ------------------ src/main/java/duke/util/gui/MainWindow.java | 14 +++-- .../duke/util/gui/messagebox/MessageBox.java | 57 +++++++++++++++++++ .../view/{DialogBox.fxml => MessageBox.fxml} | 2 +- 5 files changed, 115 insertions(+), 60 deletions(-) create mode 100644 src/main/java/duke/util/gui/ColourScheme.java delete mode 100644 src/main/java/duke/util/gui/DialogBox.java create mode 100644 src/main/java/duke/util/gui/messagebox/MessageBox.java rename src/main/resources/view/{DialogBox.fxml => MessageBox.fxml} (89%) diff --git a/src/main/java/duke/util/gui/ColourScheme.java b/src/main/java/duke/util/gui/ColourScheme.java new file mode 100644 index 0000000000..a1634c4ed7 --- /dev/null +++ b/src/main/java/duke/util/gui/ColourScheme.java @@ -0,0 +1,47 @@ +package duke.util.gui; + +public enum ColourScheme { + MINT("#b2eee6", "#8ad6cc", "#66beb2", + "#f99192", "#f97171", "#333333"); + + private final String dukeLightColour; + private final String dukeMediumColour; + private final String dukeDarkColour; + private final String userLightColour; + private final String userDarkColour; + private final String textColour; + + public String getDukeLightColour() { + return dukeLightColour; + } + + public String getDukeMediumColour() { + return dukeMediumColour; + } + + public String getDukeDarkColour() { + return dukeDarkColour; + } + + public String getUserLightColour() { + return userLightColour; + } + + public String getUserDarkColour() { + return userDarkColour; + } + + public String getTextColour() { + return textColour; + } + + ColourScheme(String dukeLightColour, String dukeMediumColour, String dukeDarkColour, + String userLightColour, String userDarkColour, String textColour) { + this.dukeLightColour = dukeLightColour; + this.dukeMediumColour = dukeMediumColour; + this.dukeDarkColour = dukeDarkColour; + this.userLightColour = userLightColour; + this.userDarkColour = userDarkColour; + this.textColour = textColour; + } +} diff --git a/src/main/java/duke/util/gui/DialogBox.java b/src/main/java/duke/util/gui/DialogBox.java deleted file mode 100644 index ce7c7c3351..0000000000 --- a/src/main/java/duke/util/gui/DialogBox.java +++ /dev/null @@ -1,55 +0,0 @@ -package duke.util.gui; - -import java.io.IOException; -import java.util.Collections; -import javafx.collections.FXCollections; -import javafx.collections.ObservableList; -import javafx.fxml.FXML; -import javafx.fxml.FXMLLoader; -import javafx.geometry.Pos; -import javafx.scene.Node; -import javafx.scene.control.Label; -import javafx.scene.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; - - private DialogBox(String text) { - 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); - } - - /** - * 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) { - return new DialogBox(text); - } - - public static DialogBox getDukeDialog(String text) { - var db = new DialogBox(text); - db.flip(); - return db; - } -} diff --git a/src/main/java/duke/util/gui/MainWindow.java b/src/main/java/duke/util/gui/MainWindow.java index 8ab1fca04a..3d4b45cd34 100644 --- a/src/main/java/duke/util/gui/MainWindow.java +++ b/src/main/java/duke/util/gui/MainWindow.java @@ -1,8 +1,9 @@ package duke.util.gui; -import static duke.util.gui.DialogBox.getDukeDialog; -import static duke.util.gui.DialogBox.getUserDialog; +import static duke.util.gui.messagebox.MessageBox.getDukeDialog; +import static duke.util.gui.messagebox.MessageBox.getUserDialog; +import duke.util.gui.messagebox.MessageBox; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.ScrollPane; @@ -25,12 +26,17 @@ public class MainWindow extends AnchorPane { private GuiDuke duke; + /** Represents the colour scheme in use for the GUI. Hardcoded as MINT for now. */ + private ColourScheme colourScheme = ColourScheme.MINT; + //private Image userImage = new Image(this.getClass().getResourceAsStream("/images/kawaii_robot.png")); //private Image dukeImage = new Image(this.getClass().getResourceAsStream("/images/kawaii_robot_power.png")); @FXML public void initialize() { scrollPane.vvalueProperty().bind(dialogContainer.heightProperty()); + // todo: investigate why setting the scrollPane's background colour does not work + scrollPane.setStyle("-fx-background-color: " + colourScheme.getDukeLightColour()); } public void setDuke(GuiDuke d) { @@ -45,7 +51,7 @@ public void setDuke(GuiDuke d) { private void handleUserInput() { // get and display user input String input = userInput.getText(); - DialogBox inputDialog = getUserDialog(input); + MessageBox inputDialog = getUserDialog(input, this.colourScheme); dialogContainer.getChildren().add(inputDialog); // clear user input field @@ -53,7 +59,7 @@ private void handleUserInput() { // get and display output from Duke String response = duke.getResponse(input); - DialogBox outputDialog = getDukeDialog(response); + MessageBox outputDialog = getDukeDialog(response, this.colourScheme); dialogContainer.getChildren().add(outputDialog); } diff --git a/src/main/java/duke/util/gui/messagebox/MessageBox.java b/src/main/java/duke/util/gui/messagebox/MessageBox.java new file mode 100644 index 0000000000..6a01a7fe5d --- /dev/null +++ b/src/main/java/duke/util/gui/messagebox/MessageBox.java @@ -0,0 +1,57 @@ +package duke.util.gui.messagebox; + +import duke.util.gui.ColourScheme; +import duke.util.gui.MainWindow; +import java.io.IOException; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.control.Label; +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 MessageBox extends HBox { + @FXML + private Label message; + + private MessageBox(String text) { + try { + FXMLLoader fxmlLoader = new FXMLLoader(MainWindow.class.getResource( + "/view/MessageBox.fxml")); + fxmlLoader.setController(this); + fxmlLoader.setRoot(this); + fxmlLoader.load(); + } catch (IOException e) { + e.printStackTrace(); + } + + message.setText(text); + } + +// /** +// * 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 MessageBox getUserDialog(String text, ColourScheme colourScheme) { + MessageBox userDialogBox = new MessageBox(text); + userDialogBox.setStyle("-fx-background-color: " + colourScheme.getUserLightColour()); + userDialogBox.message.setStyle("-fx-fill: "+ colourScheme.getTextColour()); + return userDialogBox; + } + + public static MessageBox getDukeDialog(String text, ColourScheme colourScheme) { + MessageBox dukeDialogBox = new MessageBox(text); + dukeDialogBox.setStyle("-fx-background-color: " + colourScheme.getDukeMediumColour()); + dukeDialogBox.message.setStyle("-fx-fill: "+ colourScheme.getTextColour()); + return dukeDialogBox; + } +} diff --git a/src/main/resources/view/DialogBox.fxml b/src/main/resources/view/MessageBox.fxml similarity index 89% rename from src/main/resources/view/DialogBox.fxml rename to src/main/resources/view/MessageBox.fxml index e984468766..92ef04b42c 100644 --- a/src/main/resources/view/DialogBox.fxml +++ b/src/main/resources/view/MessageBox.fxml @@ -7,7 +7,7 @@ - - + - + From 4ed611367863dca6125f3a41575fb062d4d9d5ad Mon Sep 17 00:00:00 2001 From: nattanyz Date: Mon, 30 Sep 2019 14:29:31 +0800 Subject: [PATCH 58/84] complete refactoring from previous commit, add GREY colour scheme --- src/main/java/duke/util/gui/ColourScheme.java | 14 +++++---- src/main/java/duke/util/gui/Gui.java | 7 +++++ src/main/java/duke/util/gui/MainWindow.java | 4 +-- .../duke/util/gui/messagebox/MessageBox.java | 30 ++++++++----------- src/main/resources/view/MainWindow.fxml | 2 +- 5 files changed, 30 insertions(+), 27 deletions(-) diff --git a/src/main/java/duke/util/gui/ColourScheme.java b/src/main/java/duke/util/gui/ColourScheme.java index a1634c4ed7..13dbfac7a8 100644 --- a/src/main/java/duke/util/gui/ColourScheme.java +++ b/src/main/java/duke/util/gui/ColourScheme.java @@ -2,17 +2,19 @@ public enum ColourScheme { MINT("#b2eee6", "#8ad6cc", "#66beb2", - "#f99192", "#f97171", "#333333"); + "#f99192", "#f97171", "#333333"), + GREY("#f4f6f9", "#e5e8ec", "#cbd0d8", + "#a9b1bc", "#646c77", "#424953"); - private final String dukeLightColour; + private final String backgroundColour; private final String dukeMediumColour; private final String dukeDarkColour; private final String userLightColour; private final String userDarkColour; private final String textColour; - public String getDukeLightColour() { - return dukeLightColour; + public String getBackgroundColour() { + return backgroundColour; } public String getDukeMediumColour() { @@ -35,9 +37,9 @@ public String getTextColour() { return textColour; } - ColourScheme(String dukeLightColour, String dukeMediumColour, String dukeDarkColour, + ColourScheme(String backgroundColour, String dukeMediumColour, String dukeDarkColour, String userLightColour, String userDarkColour, String textColour) { - this.dukeLightColour = dukeLightColour; + this.backgroundColour = backgroundColour; this.dukeMediumColour = dukeMediumColour; this.dukeDarkColour = dukeDarkColour; this.userLightColour = userLightColour; diff --git a/src/main/java/duke/util/gui/Gui.java b/src/main/java/duke/util/gui/Gui.java index 2f90a9961e..97125e7c05 100644 --- a/src/main/java/duke/util/gui/Gui.java +++ b/src/main/java/duke/util/gui/Gui.java @@ -7,6 +7,13 @@ public class Gui implements Ui { + /** Represents the colour scheme in use for the GUI. Hardcoded as MINT for now. */ +// private ColourScheme colourScheme = ColourScheme.MINT; + + /** + * Not in use for Duke's GUI. + * @return Nothing. + */ @Override public String readCommand() { return null; diff --git a/src/main/java/duke/util/gui/MainWindow.java b/src/main/java/duke/util/gui/MainWindow.java index 9627521661..6164a76e0a 100644 --- a/src/main/java/duke/util/gui/MainWindow.java +++ b/src/main/java/duke/util/gui/MainWindow.java @@ -27,7 +27,7 @@ public class MainWindow extends AnchorPane { private GuiDuke duke; /** Represents the colour scheme in use for the GUI. Hardcoded as MINT for now. */ - private ColourScheme colourScheme = ColourScheme.MINT; + private ColourScheme colourScheme = ColourScheme.GREY; //private Image userImage = new Image(this.getClass().getResourceAsStream("/images/kawaii_robot.png")); //private Image dukeImage = new Image(this.getClass().getResourceAsStream("/images/kawaii_robot_power.png")); @@ -35,7 +35,7 @@ public class MainWindow extends AnchorPane { @FXML public void initialize() { scrollPane.vvalueProperty().bind(messageBoxContainer.heightProperty()); - messageBoxContainer.setStyle("-fx-background-color: " + colourScheme.getDukeLightColour()); + messageBoxContainer.setStyle("-fx-background-color: " + colourScheme.getBackgroundColour()); } public void setDuke(GuiDuke d) { diff --git a/src/main/java/duke/util/gui/messagebox/MessageBox.java b/src/main/java/duke/util/gui/messagebox/MessageBox.java index 3df7b89fca..d688c4a01d 100644 --- a/src/main/java/duke/util/gui/messagebox/MessageBox.java +++ b/src/main/java/duke/util/gui/messagebox/MessageBox.java @@ -13,6 +13,8 @@ * This control represents a dialog box consisting of an ImageView to represent the speaker's face and a label * containing text from the speaker. */ +// todo: replace Label with TextFlow to enable text to wrap multiple lines! +// todo: still can't get user input to align right :( public class MessageBox extends HBox { @FXML private Label message; @@ -31,27 +33,19 @@ private MessageBox(String text) { message.setText(text); } -// /** -// * 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 MessageBox getUserMessageBox(String text, ColourScheme colourScheme) { - MessageBox userDialogBox = new MessageBox(text); - userDialogBox.setStyle("-fx-background-color: " + colourScheme.getUserLightColour()); - userDialogBox.message.setStyle("-fx-fill: "+ colourScheme.getTextColour()); - return userDialogBox; + MessageBox userMessageBox = new MessageBox(text); + userMessageBox.setStyle("-fx-background-color: " + colourScheme.getUserLightColour()); + userMessageBox.message.setStyle("-fx-fill: "+ colourScheme.getTextColour()); +// userMessageBox.setAlignment(Pos.TOP_RIGHT); + return userMessageBox; } public static MessageBox getDukeMessageBox(String text, ColourScheme colourScheme) { - MessageBox dukeDialogBox = new MessageBox(text); - dukeDialogBox.setStyle("-fx-background-color: " + colourScheme.getDukeMediumColour()); - dukeDialogBox.message.setStyle("-fx-fill: "+ colourScheme.getTextColour()); - return dukeDialogBox; + MessageBox dukeMessageBox = new MessageBox(text); + dukeMessageBox.setStyle("-fx-background-color: " + colourScheme.getDukeMediumColour()); + dukeMessageBox.message.setStyle("-fx-fill: "+ colourScheme.getTextColour()); +// dukeMessageBox.setAlignment(Pos.TOP_LEFT); + return dukeMessageBox; } } diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml index 2be344cd33..e869c08f9b 100644 --- a/src/main/resources/view/MainWindow.fxml +++ b/src/main/resources/view/MainWindow.fxml @@ -36,7 +36,7 @@ - + From 660800652ecb239d5874e75fb9b56c8095cde8a4 Mon Sep 17 00:00:00 2001 From: nattanyz Date: Mon, 30 Sep 2019 15:18:51 +0800 Subject: [PATCH 59/84] partially implement GUI using messageBoxQueue. changed font family and size. add DropShadow to MessageBox. --- src/main/java/duke/util/Ui.java | 3 ++ src/main/java/duke/util/UiMessage.java | 1 + src/main/java/duke/util/cli/Cli.java | 3 ++ src/main/java/duke/util/gui/Gui.java | 28 ++++++++++++++++--- src/main/java/duke/util/gui/GuiDuke.java | 19 +++++++------ src/main/java/duke/util/gui/MainWindow.java | 10 +++---- .../duke/util/gui/messagebox/MessageBox.java | 6 ++++ src/main/resources/view/MainWindow.fxml | 4 +-- src/main/resources/view/MessageBox.fxml | 4 +-- 9 files changed, 57 insertions(+), 21 deletions(-) diff --git a/src/main/java/duke/util/Ui.java b/src/main/java/duke/util/Ui.java index 0fa72e7bd9..194308f654 100644 --- a/src/main/java/duke/util/Ui.java +++ b/src/main/java/duke/util/Ui.java @@ -3,6 +3,9 @@ import duke.task.TaskList; import duke.util.exception.DukeException; +/** + * Encapsulates methods related to displaying responses from Duke in the UI. + */ public interface Ui { /** * Returns the command entered by the user. diff --git a/src/main/java/duke/util/UiMessage.java b/src/main/java/duke/util/UiMessage.java index b126de3208..e837b30c9c 100644 --- a/src/main/java/duke/util/UiMessage.java +++ b/src/main/java/duke/util/UiMessage.java @@ -15,6 +15,7 @@ public enum UiMessage { // commands TASK_ADDED("Okay! I've added the task."), TASK_SNOOZED("Okay! The task has been snoozed by 1 day."), + MATCHING_TASKS("Here are the matching tasks in your list..."), // helpers HINT_LIST("Use list to see all your tasks!"); diff --git a/src/main/java/duke/util/cli/Cli.java b/src/main/java/duke/util/cli/Cli.java index 74b6605038..e92d7f5b49 100644 --- a/src/main/java/duke/util/cli/Cli.java +++ b/src/main/java/duke/util/cli/Cli.java @@ -6,6 +6,9 @@ import duke.util.exception.DukeException; import java.util.Scanner; +/** + * Handles Duke's UI when in CLI mode. + */ public class Cli implements Ui { private Scanner in; diff --git a/src/main/java/duke/util/gui/Gui.java b/src/main/java/duke/util/gui/Gui.java index 97125e7c05..fd89c16e0b 100644 --- a/src/main/java/duke/util/gui/Gui.java +++ b/src/main/java/duke/util/gui/Gui.java @@ -1,14 +1,25 @@ package duke.util.gui; +import duke.task.Task; import duke.task.TaskList; import duke.util.Ui; import duke.util.UiMessage; import duke.util.exception.DukeException; - +import duke.util.gui.messagebox.MessageBox; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Queue; + +/** + * Handles Duke's UI when in GUI mode. + */ public class Gui implements Ui { /** Represents the colour scheme in use for the GUI. Hardcoded as MINT for now. */ -// private ColourScheme colourScheme = ColourScheme.MINT; + private ColourScheme colourScheme = ColourScheme.MINT; + + /** Represents the queue of messages to be displayed in the GUI. */ + public Queue messageBoxQueue = new LinkedList<>(); /** * Not in use for Duke's GUI. @@ -21,17 +32,26 @@ public String readCommand() { @Override public void showMessage(UiMessage uiMessage) { - + messageBoxQueue.add(MessageBox.getDukeMessageBox(uiMessage.getMessage(), this.colourScheme)); } @Override public void showError(DukeException exception) { - + // todo: replace with custom exception message box once created + messageBoxQueue.add(MessageBox.getDukeMessageBox(exception.getMessage(), this.colourScheme)); } @Override public void showTasks(TaskList tasks) { + showMessage(UiMessage.MATCHING_TASKS); + ArrayList listOfTasks = tasks.getTasks(); + for (Task task : listOfTasks) { + showTask(task); + } + } + public void showTask(Task task) { + messageBoxQueue.add(MessageBox.getDukeMessageBox(task.toString(), this.colourScheme)); } // public void setColourScheme(ColourScheme colourScheme) { diff --git a/src/main/java/duke/util/gui/GuiDuke.java b/src/main/java/duke/util/gui/GuiDuke.java index 5c2b0aefaa..cf10e684e6 100644 --- a/src/main/java/duke/util/gui/GuiDuke.java +++ b/src/main/java/duke/util/gui/GuiDuke.java @@ -1,8 +1,11 @@ package duke.util.gui; import duke.Duke; +import duke.command.Command; import duke.task.TaskList; +import duke.util.Parser; import duke.util.Storage; +import duke.util.exception.DukeException; public class GuiDuke implements Duke { Storage storage; @@ -26,16 +29,16 @@ public GuiDuke() { * May not be required after UI implementation is refined. * @return Response from Duke to be displayed in the UI. */ - public String getResponse(String input) { -// try { -// Command c = Parser.parse(input); -// c.execute(tasks, ui); -// } catch (DukeException e) { -// ui.showError(e); -// } + public void getResponse(String input) { + try { + Command c = Parser.parse(input); + c.execute(tasks, ui); + } catch (DukeException e) { + ui.showError(e); + } // dummy implementation - return "Duke heard: " + input; +// return "Duke heard: " + input; //return ui.getResponse(); } diff --git a/src/main/java/duke/util/gui/MainWindow.java b/src/main/java/duke/util/gui/MainWindow.java index 6164a76e0a..d9b0e28bcc 100644 --- a/src/main/java/duke/util/gui/MainWindow.java +++ b/src/main/java/duke/util/gui/MainWindow.java @@ -1,9 +1,9 @@ package duke.util.gui; -import static duke.util.gui.messagebox.MessageBox.getDukeMessageBox; import static duke.util.gui.messagebox.MessageBox.getUserMessageBox; import duke.util.gui.messagebox.MessageBox; +import java.util.Queue; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.ScrollPane; @@ -27,7 +27,7 @@ public class MainWindow extends AnchorPane { private GuiDuke duke; /** Represents the colour scheme in use for the GUI. Hardcoded as MINT for now. */ - private ColourScheme colourScheme = ColourScheme.GREY; + private ColourScheme colourScheme = ColourScheme.MINT; //private Image userImage = new Image(this.getClass().getResourceAsStream("/images/kawaii_robot.png")); //private Image dukeImage = new Image(this.getClass().getResourceAsStream("/images/kawaii_robot_power.png")); @@ -57,9 +57,9 @@ private void handleUserInput() { userInput.clear(); // get and display output from Duke - String response = duke.getResponse(input); - MessageBox dukeMessageBox = getDukeMessageBox(response, this.colourScheme); - messageBoxContainer.getChildren().add(dukeMessageBox); + Queue messageBoxQueue = duke.ui.messageBoxQueue; + messageBoxContainer.getChildren().addAll(messageBoxQueue); + messageBoxQueue.clear(); } // /** diff --git a/src/main/java/duke/util/gui/messagebox/MessageBox.java b/src/main/java/duke/util/gui/messagebox/MessageBox.java index d688c4a01d..30a5f48953 100644 --- a/src/main/java/duke/util/gui/messagebox/MessageBox.java +++ b/src/main/java/duke/util/gui/messagebox/MessageBox.java @@ -6,7 +6,9 @@ import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.scene.control.Label; +import javafx.scene.effect.DropShadow; import javafx.scene.layout.HBox; +import javafx.scene.paint.Color; /** * An example of a custom control using FXML. @@ -37,6 +39,8 @@ public static MessageBox getUserMessageBox(String text, ColourScheme colourSchem MessageBox userMessageBox = new MessageBox(text); userMessageBox.setStyle("-fx-background-color: " + colourScheme.getUserLightColour()); userMessageBox.message.setStyle("-fx-fill: "+ colourScheme.getTextColour()); + DropShadow dropShadow = new DropShadow(5.0, Color.web(colourScheme.getUserDarkColour())); + userMessageBox.setEffect(dropShadow); // userMessageBox.setAlignment(Pos.TOP_RIGHT); return userMessageBox; } @@ -45,6 +49,8 @@ public static MessageBox getDukeMessageBox(String text, ColourScheme colourSchem MessageBox dukeMessageBox = new MessageBox(text); dukeMessageBox.setStyle("-fx-background-color: " + colourScheme.getDukeMediumColour()); dukeMessageBox.message.setStyle("-fx-fill: "+ colourScheme.getTextColour()); + DropShadow dropShadow = new DropShadow(5.0, Color.web(colourScheme.getDukeDarkColour())); + dukeMessageBox.setEffect(dropShadow); // dukeMessageBox.setAlignment(Pos.TOP_LEFT); return dukeMessageBox; } diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml index e869c08f9b..5130f7926e 100644 --- a/src/main/resources/view/MainWindow.fxml +++ b/src/main/resources/view/MainWindow.fxml @@ -18,7 +18,7 @@ - + diff --git a/src/main/resources/view/MessageBox.fxml b/src/main/resources/view/MessageBox.fxml index 92ef04b42c..654732c08d 100644 --- a/src/main/resources/view/MessageBox.fxml +++ b/src/main/resources/view/MessageBox.fxml @@ -5,11 +5,11 @@ - +