diff --git a/.gitignore b/.gitignore index 2873e189e1..84d22db998 100644 --- a/.gitignore +++ b/.gitignore @@ -13,5 +13,6 @@ src/main/resources/docs/ *.iml bin/ -/text-ui-test/ACTUAL.TXT text-ui-test/EXPECTED-UNIX.TXT +duke.txt +tasks.txt diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..439f54024f --- /dev/null +++ b/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: duke.main.Duke + diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000000..5b10c9d6a7 --- /dev/null +++ b/build.gradle @@ -0,0 +1,56 @@ +plugins { + id 'java' + id 'application' + id 'com.github.johnrengelman.shadow' version '5.1.0' +} + +repositories { + mavenCentral() +} + +dependencies { + String javaFxVersion = '11' + + implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'linux' + implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'linux' + implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'linux' + implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'linux' + + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0' + testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.0' +} + +test { + useJUnitPlatform() + + testLogging { + events "passed", "skipped", "failed" + + showExceptions true + exceptionFormat "full" + showCauses true + showStackTraces true + showStandardStreams = false + } +} + +application { + mainClassName = "duke.main.Launcher" +} + +shadowJar { + archiveBaseName = "duke.main.Launcher" + archiveClassifier = null +} + +run{ + standardInput = System.in +} diff --git a/data/archive.txt b/data/archive.txt new file mode 100644 index 0000000000..dc85f70c2b --- /dev/null +++ b/data/archive.txt @@ -0,0 +1,38 @@ +T / [ ] / a +D / [ ] / b / Jan 01 2022 1800 PM +E / [ ] / read book / Jan 01 2020 1800 PM-Jan 01 2020 2000 PM +T / [ ] / d +D / [ ] / b / Jan 01 2022 1800 PM +T / [ ] / a +T / [ ] / b +T / [ ] / c +D / [ ] / / Jan 01 2020 1800 PM +T / [ ] / a +T / [ ] / b +T / [ ] / c +T / [ ] / e +T / [ ] / a +T / [ ] / b +T / [ ] / c +E / [ ] / f / Jan 01 2020 1800 PM-Jan 01 2020 2000 PM +T / [ ] / a +T / [ ] / b +T / [ ] / c +T / [ ] / a +T / [ ] / b +T / [ ] / c +T / [ ] / a +T / [ ] / b +T / [ ] / c +T / [ ] / a +T / [ ] / b +T / [ ] / a +T / [ ] / b +T / [ ] / a +T / [ ] / b +T / [ ] / a +T / [ ] / b +T / [ ] / a +T / [ ] / b +T / [ ] / a +T / [ ] / b diff --git a/data/archiveAll.txt b/data/archiveAll.txt new file mode 100644 index 0000000000..081bcc6a5f --- /dev/null +++ b/data/archiveAll.txt @@ -0,0 +1,3 @@ +E / [ ] / f / Jan 01 2020 1800 PM-Jan 01 2020 2000 PM +null +null diff --git a/docs/README IMAGES/archive.png b/docs/README IMAGES/archive.png new file mode 100644 index 0000000000..40bfda777e Binary files /dev/null and b/docs/README IMAGES/archive.png differ diff --git a/docs/README IMAGES/deadline.png b/docs/README IMAGES/deadline.png new file mode 100644 index 0000000000..eff5757681 Binary files /dev/null and b/docs/README IMAGES/deadline.png differ diff --git a/docs/README IMAGES/delete.png b/docs/README IMAGES/delete.png new file mode 100644 index 0000000000..75337645f1 Binary files /dev/null and b/docs/README IMAGES/delete.png differ diff --git a/docs/README IMAGES/event.png b/docs/README IMAGES/event.png new file mode 100644 index 0000000000..85ff70fa18 Binary files /dev/null and b/docs/README IMAGES/event.png differ diff --git a/docs/README IMAGES/find.png b/docs/README IMAGES/find.png new file mode 100644 index 0000000000..4b9ba44138 Binary files /dev/null and b/docs/README IMAGES/find.png differ diff --git a/docs/README IMAGES/list.png b/docs/README IMAGES/list.png new file mode 100644 index 0000000000..6f2c720ff7 Binary files /dev/null and b/docs/README IMAGES/list.png differ diff --git a/docs/README IMAGES/mark.png b/docs/README IMAGES/mark.png new file mode 100644 index 0000000000..6198dc13fe Binary files /dev/null and b/docs/README IMAGES/mark.png differ diff --git a/docs/README IMAGES/showdeadlinesoreventson.png b/docs/README IMAGES/showdeadlinesoreventson.png new file mode 100644 index 0000000000..354a221ab9 Binary files /dev/null and b/docs/README IMAGES/showdeadlinesoreventson.png differ diff --git a/docs/README IMAGES/todo.png b/docs/README IMAGES/todo.png new file mode 100644 index 0000000000..01c2e312a4 Binary files /dev/null and b/docs/README IMAGES/todo.png differ diff --git a/docs/README IMAGES/unmark.png b/docs/README IMAGES/unmark.png new file mode 100644 index 0000000000..3071fb8401 Binary files /dev/null and b/docs/README IMAGES/unmark.png differ diff --git a/docs/README.md b/docs/README.md index 8077118ebe..26e5950b2b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,29 +1,116 @@ -# User Guide +# Welcome to Duke +>App that helps you to manage daily tasks e.g. deadlines, events, to do lists. + +## Environment settings +This app requires Java version 11. + +You can go to your terminal and cd into the directory you downloaded the app into. +``` +java -jar duke.jar +``` ## Features +1. Add a todo, deadline, or event task. +2. Delete a task. +3. Mark/ unmark a task as done. +4. Archive your tasks. +5. Search your tasks by keyword. +6. Find out what tasks are happening/ due on a certain day. + +## Usage + +### `Keyword` - Describe action -### Feature-ABC +### `todo {description}` - Adds a Todo task +Example of usage: -Description of the feature. +`todo read book` -### Feature-XYZ +Expected outcome: -Description of the feature. +![todo](https://github.com/ZhuLeYao/ip/blob/master/docs/README%20IMAGES/todo.png?raw=true) +### `deadline {description} /by {deadline date}` - Adds a Deadline task +Example of usage: -## Usage +`deadline read book /by 2020-01-01 1800` -### `Keyword` - Describe action +Expected outcome: -Describe the action and its outcome. +![deadline](https://github.com/ZhuLeYao/ip/blob/master/docs/README%20IMAGES/deadline.png?raw=true) -Example of usage: +### `event {description} /from {event start time} /to {event end time}` - Adds an event task +Example of usage: -`keyword (optional arguments)` +`event read book /from 2020-01-01 1800 /to 2020-01-01 2000` Expected outcome: -Description of the outcome. +![event](https://github.com/ZhuLeYao/ip/blob/master/docs/README%20IMAGES/event.png?raw=true) + +### `mark {index of task}` - Marks a task as done +Example of usage: + +`mark 1` + +Expected outcome: + +![mark](https://github.com/ZhuLeYao/ip/blob/master/docs/README%20IMAGES/mark.png?raw=true) + +### `unmark {index of task}` - Unmarks a task +Example of usage: + +`unmark 1` + +Expected outcome: + +![unmark](https://github.com/ZhuLeYao/ip/blob/master/docs/README%20IMAGES/unmark.png?raw=true) + +### `delete {index of task}` - Deletes a task +Example of usage: + +`delete 1` + +Expected outcome: + +![delete](https://github.com/ZhuLeYao/ip/blob/master/docs/README%20IMAGES/delete.png?raw=true) + +### `find {description}` - Finds tasks containing description +Example of usage: + +`find book` + +Expected outcome: + +![find](https://github.com/ZhuLeYao/ip/blob/master/docs/README%20IMAGES/find.png?raw=true) + +### `show deadlines or events on {date}` - Shows tasks happening on specified date +Example of usage: + +`show deadlines or events on 2020-01-01` + +Expected outcome: + +![show](https://github.com/ZhuLeYao/ip/blob/master/docs/README%20IMAGES/showdeadlinesoreventson.png?raw=true) + +### `archive` - Archives current list of tasks into archiveAll.txt +note: archive.txt contains all historical tasks. +Example of usage: + +`archive` + +Expected outcome: + +![archive](https://github.com/ZhuLeYao/ip/blob/master/docs/README%20IMAGES/archive.png?raw=true) + +### `list` - Shows current list of tasks +Example of usage: + +`list` + +Expected outcome: + +![list](https://github.com/ZhuLeYao/ip/blob/master/docs/README%20IMAGES/list.png?raw=true) + +### `bye` - Stops the app + -``` -expected output -``` diff --git a/docs/Ui.png b/docs/Ui.png new file mode 100644 index 0000000000..d6c87fcfa8 Binary files /dev/null and b/docs/Ui.png differ diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..f3d88b1c2f Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..b7c8c5dbf5 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000000..2fe81a7d95 --- /dev/null +++ b/gradlew @@ -0,0 +1,183 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000000..62bd9b9cce --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,103 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java deleted file mode 100644 index 5d313334cc..0000000000 --- a/src/main/java/Duke.java +++ /dev/null @@ -1,10 +0,0 @@ -public class Duke { - public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); - } -} diff --git a/src/main/java/duke/exception/DukeException.java b/src/main/java/duke/exception/DukeException.java new file mode 100644 index 0000000000..008932b85f --- /dev/null +++ b/src/main/java/duke/exception/DukeException.java @@ -0,0 +1,99 @@ +package duke.exception; + +/** + * Handles all exceptions. + */ +public class DukeException extends Exception { + DukeException(String message) { + super(message); + } + + /** + * Handles exception to missing time input for deadline and event. + * + * @param command Command entered by user. + * @throws DukeException if missing time input. + */ + public static void missingTimingException(String command) throws DukeException { + if (command.startsWith("deadline") && !command.contains("/by")) { + throw new DukeException("\t ☹ OOPS!!! The timing of a deadline cannot be empty."); + } else if (command.startsWith("event") && !command.contains("/from")) { + throw new DukeException("\t ☹ OOPS!!! The start time of an event cannot be empty."); + } else if (command.startsWith("event") && !command.contains("/to")) { + throw new DukeException("\t ☹ OOPS!!! The end time of an event cannot be empty."); + } + } + + /** + * Handles exception to missing index input of task when marking/ + * unmarking/ deleting task. + * + * @param command Command entered by user. + * @throws DukeException if missing index input. + */ + public static void missingIndexException(String command) throws DukeException { + if (command.equals("mark")) { + throw new DukeException("\t ☹ OOPS!!! The task index to mark a task as done cannot be empty."); + } else if (command.equals("unmark")) { + throw new DukeException("\t ☹ OOPS!!! The task index to unmark a task as not done cannot be empty."); + } else if (command.equals("delete")) { + throw new DukeException("\t ☹ OOPS!!! The task index to delete a task as not done cannot be empty."); + } + } + + /** + * Handles exception to invalid index input of task when marking/ + * unmarking/ deleting task. + * This occurs when index input is more or less than number of + * existing tasks. + * + * @param command Command entered by user. + * @param taskSize Total number of tasks. + * @throws DukeException if wrong index input. + */ + public static void invalidIndexException(String command, int taskSize) throws DukeException { + if (command.startsWith("mark") || command.startsWith("unmark") ||command.startsWith("delete")) { + String index = command.split(" ")[1]; + int index1 = Integer.parseInt(index); + if (index1 <= 0) { + throw new DukeException("\t ☹ OOPS!!! The task index to delete or un/mark a task cannot be zero or less."); + } else if (index.equals("")) { + throw new DukeException("\t ☹ OOPS!!! The task index to delete or un/mark a task cannot be empty."); + } else if (index1 > taskSize) { + throw new DukeException("\t ☹ OOPS!!! The task index to delete or un/mark a task cannot be more than" + + " number of tasks."); + } + } + } + + /** + * Handles exception to missing command keyword. + * + * @param command Command entered by user. + * @throws DukeException if invalid command input. + */ + public static void invalidCommandException(String command) throws DukeException { + if (!command.startsWith("event") || !(command.startsWith("deadline")) || + !command.startsWith("todo") || command.startsWith("mark") || !command.startsWith("unmark")) { + throw new DukeException("\t ☹ OOPS!!! I'm sorry, but I don't know what that means :-("); + } + } + + /** + * Handles exception to missing task description. + * + * @param command Command entered by user. + * @throws DukeException if missing command information. + */ + public static void emptyCommandException(String command) throws DukeException { + if (command.equals("todo")) { + throw new DukeException("\t ☹ OOPS!!! The description of a todo cannot be empty."); + } else if (command.equals("deadline")) { + throw new DukeException("\t ☹ OOPS!!! The description of a deadline cannot be empty."); + } else if (command.equals("event")) { + throw new DukeException("\t ☹ OOPS!!! The description of an event cannot be empty."); + } else if (command.equals("find deadlines or events on")) { + throw new DukeException("\t ☹ OOPS!!! The date of a deadline/ event cannot be empty."); + } + } +} diff --git a/src/main/java/duke/main/DialogBox.java b/src/main/java/duke/main/DialogBox.java new file mode 100644 index 0000000000..7759ec3303 --- /dev/null +++ b/src/main/java/duke/main/DialogBox.java @@ -0,0 +1,64 @@ +package duke.main; + +import javafx.geometry.Pos; +import javafx.scene.control.Label; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; +import javafx.scene.Node; +import javafx.scene.image.Image; + +import java.io.IOException; + +import java.util.Collections; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; + +/** + * 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/main/Duke.java b/src/main/java/duke/main/Duke.java new file mode 100644 index 0000000000..579362ef46 --- /dev/null +++ b/src/main/java/duke/main/Duke.java @@ -0,0 +1,49 @@ +package duke.main; + +import java.io.*; + +/** + * Runs the app. + */ +public class Duke { + private Storage storage; + private TaskList tasks; + private Ui ui; + private static final String filePath = "data/tasks.txt"; + + /** + * Initialises Storage, TaskList and Ui. + * Previous tasks are loaded up. + * Loading error will be shown if file cannot be found/ generated. + */ + public Duke() { + ui = new Ui(); + storage = new Storage(filePath); + try { + tasks = new TaskList(storage.loadTxtFile()); + } catch (IOException e) { + ui.showLoadingError(e.getMessage()); + tasks = new TaskList(); + } + } + + /** + * Runs the app. + * + * @param input Command input by user. + * @return Response by Duke. + */ + String getResponse(String input) throws IOException { + + Storage storageArchive = new Storage("data/archive.txt"); + storageArchive.loadTxtFile(); + + while (!input.equals("bye")) { + Parser parser = new Parser(); + return parser.parse(input, ui, tasks, storage, storageArchive); + } + + return ui.printByeMessage(); + } + +} diff --git a/src/main/java/duke/main/Launcher.java b/src/main/java/duke/main/Launcher.java new file mode 100644 index 0000000000..2120be7e5c --- /dev/null +++ b/src/main/java/duke/main/Launcher.java @@ -0,0 +1,11 @@ +package duke.main; + +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); + } +} diff --git a/src/main/java/duke/main/Main.java b/src/main/java/duke/main/Main.java new file mode 100644 index 0000000000..138781d90b --- /dev/null +++ b/src/main/java/duke/main/Main.java @@ -0,0 +1,32 @@ +package duke.main; + +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); + stage.setTitle("Duke"); + fxmlLoader.getController().setDuke(duke); + stage.show(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/duke/main/MainWindow.java b/src/main/java/duke/main/MainWindow.java new file mode 100644 index 0000000000..c47c0afeda --- /dev/null +++ b/src/main/java/duke/main/MainWindow.java @@ -0,0 +1,55 @@ +package duke.main; + +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; + +import java.io.IOException; + +/** + * 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() throws IOException { + String input = userInput.getText(); + String response = duke.getResponse(input); + dialogContainer.getChildren().addAll( + DialogBox.getUserDialog(input, userImage), + DialogBox.getDukeDialog(response, dukeImage) + ); + userInput.clear(); + } +} diff --git a/src/main/java/duke/main/Parser.java b/src/main/java/duke/main/Parser.java new file mode 100644 index 0000000000..974cf69cb8 --- /dev/null +++ b/src/main/java/duke/main/Parser.java @@ -0,0 +1,378 @@ +package duke.main; + +import java.io.IOException; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +import duke.exception.DukeException; + +import duke.task.*; + +/** + * Understands what the command is asking for. + */ +public class Parser { + + public int checkExceptionAndGetTask(String command, TaskList allTasks) throws DukeException { + DukeException.missingIndexException(command); + DukeException.invalidIndexException(command, allTasks.getNumberOfTask()); + String[] str = command.split(" "); + int taskIndex = Integer.parseInt(str[1]) - 1; + + return taskIndex; + } + + /** + * Parses the command to process. + * If command calls for list, task list is printed. + * If command starts with "mark", task will be mark as done. + * If command starts with "unmark", task will be unmarked as + * undone. + * If command starts with "todo", "deadline" or "event", task will + * be added to task list. + * If command starts with "delete", task will be deleted from task + * list. + * If command starts with "show deadlines or events on", matching + * tasks on input date will be shown. + * If command starts with "find", matching tasks to keyword will + * be shown. + * If command starts with "archive", current task list will be + * saved to archive. + * If command starts with "bye", exit message will be printed. + * Task list and text file on hard disk containing all commands + * updates if possible after each command. + * Corresponding messages will also be printed to signify + * completion of command. + * Each command has its corresponding exceptions catching. + * + * @param command Command typed by user. + * @param ui Ui object to print corresponding messages. + * @param allTasks A list of existing tasks. + * @param storage Storage object to update text file of task list + * on hard disk. + * @return Ui response to user. + */ + public String parse(String command, Ui ui, TaskList allTasks, Storage storage, Storage storageArchive) { + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm"); + try { + if (command.equals("list")) { + return listCommand(ui, allTasks); + } else if (command.startsWith("mark") || command.startsWith("unmark")) { + return markOrUnmarkCommand(command, allTasks, storage); + } else if (command.startsWith("todo") || command.startsWith("deadline") || command.startsWith("event")) { + return tasksCommands(command, allTasks, storage, storageArchive, dateTimeFormatter); + } else if (command.startsWith("delete")) { + return deleteCommand(command, allTasks, storage); + } else if (command.startsWith("show deadlines or events on") || command.startsWith("find")) { + return showOrFindCommands(command, ui, allTasks); + } else if (command.equals("archive")) { + return archiveCommand(ui, command, allTasks, storage); + } else if (command.equals("bye")){ + return ui.printByeMessage(); + } else { + DukeException.invalidCommandException(command); + } + } catch (DukeException d) { + return d.getMessage(); + } catch (NumberFormatException nfe) { + return "\t ☹ OOPS!!! The task index to delete or un/mark a task cannot be a non-integer."; + } catch (IOException e) { + throw new RuntimeException(e); + } + assert false: "Uncaught error"; + return "Uncaught error"; + } + + /** + * Prints task list. + * Corresponding messages will be printed to signify + * completion of command. + * + * @param ui Ui object to print corresponding messages. + * @param allTasks A list of existing tasks. + * @return Ui response to user. + */ + public String listCommand(Ui ui, TaskList allTasks) { + String output; + output = ui.printCommandList(allTasks.getAllTasks()); + return output; + } + + /** + * Marks task as done. + * Corresponding messages will be printed to signify + * completion of command. + * + * @param command Command typed by user. + * @param allTasks A list of existing tasks. + * @param storage Storage object to update text file of task list + * on hard disk. + * @return Ui response to user. + * @throws DukeException if input is invalid. + * @throws IOException if file cannot be loaded. + */ + public String markCommand(String command, TaskList allTasks, Storage storage) throws DukeException, IOException { + int taskIndex = checkExceptionAndGetTask(command, allTasks); + Task oldTask = allTasks.getTask(taskIndex); + Task task = allTasks.markTaskAsDone(oldTask, taskIndex); + storage.saveListToFile(command, task, allTasks); + return task.markAsDone(); + } + + /** + * Unmarks task as undone. + * Corresponding messages will be printed to signify + * completion of command. + * + * @param command Command typed by user. + * @param allTasks A list of existing tasks. + * @param storage Storage object to update text file of task list + * on hard disk. + * @return Ui response to user. + * @throws DukeException if input is invalid. + * @throws IOException if file cannot be loaded. + */ + public String unmarkCommand(String command, TaskList allTasks, Storage storage) throws DukeException, IOException { + int taskIndex = checkExceptionAndGetTask(command, allTasks); + Task oldTask = allTasks.getTask(taskIndex); + Task task = allTasks.unmarkTaskAsUndone(oldTask, taskIndex); + storage.saveListToFile(command, task, allTasks); + return task.unmarkAsUndone(); + } + + /** + * Marks or unmarks task as done or undone respectively. + * Corresponding messages will be printed to signify + * completion of command. + * + * @param command Command typed by user. + * @param allTasks A list of existing tasks. + * @param storage Storage object to update text file of task list + * on hard disk. + * @return Ui response to user. + * @throws DukeException if input is invalid. + * @throws IOException if file cannot be loaded. + */ + public String markOrUnmarkCommand(String command, TaskList allTasks, Storage storage) + throws DukeException, IOException { + if (command.startsWith("mark")) { + return markCommand(command, allTasks, storage); + } else { + return unmarkCommand(command, allTasks, storage); + } + } + + /** + * Adds todo task to task list. + * Corresponding messages will be printed to signify + * completion of command. + * + * @param command Command typed by user. + * @param allTasks A list of existing tasks. + * @param storage Storage object to update text file of task list + * on hard disk. + * @return Ui response to user. + * @throws DukeException if input is invalid. + * @throws IOException if file cannot be loaded. + */ + public String todoCommand(String command, TaskList allTasks, Storage storage, Storage storageArchive) + throws DukeException, IOException { + DukeException.emptyCommandException(command); + String[] str = command.split("todo"); + String taskName = str[1]; + Todo todo = new Todo(allTasks.getNumberOfTask(), false, + taskName, allTasks.getNumberOfTask() + 1); + allTasks.addTask(todo); + storage.saveListToFile(command, todo, allTasks); + storageArchive.saveListToFile(command, todo, allTasks); + return todo.printToDoTask(); + } + + /** + * Adds deadline task to task list. + * Corresponding messages will be printed to signify + * completion of command. + * + * @param command Command typed by user. + * @param allTasks A list of existing tasks. + * @param storage Storage object to update text file of task list + * on hard disk. + * @return Ui response to user. + * @throws DukeException if input is invalid. + * @throws IOException if file cannot be loaded. + */ + public String deadlineCommand(String command, TaskList allTasks, Storage storage, Storage storageArchive, + DateTimeFormatter dateTimeFormatter) throws DukeException, IOException { + DukeException.emptyCommandException(command); + DukeException.missingTimingException(command); + String[] str = command.split("/by "); + String taskName = str[0].split("deadline")[1]; + LocalDateTime taskDeadline = LocalDateTime.parse(str[1], dateTimeFormatter); + Deadline deadline = new Deadline(allTasks.getNumberOfTask(), false, + taskName, taskDeadline, allTasks.getNumberOfTask() + 1); + allTasks.addTask(deadline); + storage.saveListToFile(command, deadline, allTasks); + storageArchive.saveListToFile(command, deadline, allTasks); + return deadline.printDeadlineTask(); + } + + /** + * Adds event task to task list. + * Corresponding messages will be printed to signify + * completion of command. + * + * @param command Command typed by user. + * @param allTasks A list of existing tasks. + * @param storage Storage object to update text file of task list + * on hard disk. + * @return Ui response to user. + * @throws DukeException if input is invalid. + * @throws IOException if file cannot be loaded. + */ + public String eventCommand(String command, TaskList allTasks, Storage storage, Storage storageArchive, + DateTimeFormatter dateTimeFormatter) throws DukeException, IOException { + DukeException.emptyCommandException(command); + DukeException.missingTimingException(command); + String[] str = command.split("/from "); + String taskName = str[0].split("event")[1]; + String[] eventStartEndTime = str[1].split(" /to "); + LocalDateTime eventStartTime = LocalDateTime.parse(eventStartEndTime[0], dateTimeFormatter); + LocalDateTime eventEndTime = LocalDateTime.parse(eventStartEndTime[1], dateTimeFormatter); + Event event = new Event(allTasks.getNumberOfTask(), false, + taskName, eventStartTime, eventEndTime, allTasks.getNumberOfTask() + 1); + allTasks.addTask(event); + storage.saveListToFile(command, event, allTasks); + storageArchive.saveListToFile(command, event, allTasks); + return event.printEventTask(); + } + + /** + * Adds todo, deadline or event to task list. + * Corresponding messages will be printed to signify + * completion of command. + * + * @param command Command typed by user. + * @param allTasks A list of existing tasks. + * @param storage Storage object to update text file of task list + * on hard disk. + * @return Ui response to user. + * @throws DukeException if input is invalid. + * @throws IOException if file cannot be loaded. + */ + public String tasksCommands(String command, TaskList allTasks, Storage storage, Storage storageArchive, + DateTimeFormatter dateTimeFormatter) throws DukeException, IOException { + if (command.startsWith("todo")) { + return todoCommand(command, allTasks, storage, storageArchive); + } else if (command.startsWith("deadline")) { + return deadlineCommand(command, allTasks, storage, storageArchive, dateTimeFormatter); + } else { + return eventCommand(command, allTasks, storage, storageArchive, dateTimeFormatter); + } + } + + /** + * Deletes task from task list. + * Corresponding messages will be printed to signify + * completion of command. + * + * @param command Command typed by user. + * @param allTasks A list of existing tasks. + * @param storage Storage object to update text file of task list + * on hard disk. + * @return Ui response to user. + * @throws DukeException if input is invalid. + * @throws IOException if file cannot be loaded. + */ + public String deleteCommand(String command, TaskList allTasks, Storage storage) + throws DukeException, IOException { + int taskIndex = checkExceptionAndGetTask(command, allTasks); + Task task = allTasks.getTask(taskIndex); + allTasks.deleteTask(taskIndex); + storage.saveListToFile(command, task, allTasks); + return task.printDelete(allTasks.getAllTasks()); + } + + /** + * Shows matching tasks on input date. + * Corresponding messages will be printed to signify + * completion of command. + * + * @param command Command typed by user. + * @param ui Ui object to print corresponding messages. + * @param allTasks A list of existing tasks. + * @return Ui response to user. + * @throws DukeException if input is invalid. + */ + public String showDeadlinesEventsCommand(Ui ui, String command, TaskList allTasks) throws DukeException { + DukeException.emptyCommandException(command); + String[] str = command.split("show deadlines or events on "); + String dateTime = str[1]; + DateTimeFormatter dateTimeFormatter2 = + DateTimeFormatter.ofPattern("yyyy-MM-dd"); + LocalDate dateTime1 = LocalDate.parse(dateTime, dateTimeFormatter2); + return ui.printDeadlineOrEventsOnDay(dateTime1, allTasks); + } + + /** + * Shows matching tasks to keyword. + * Corresponding messages will be printed to signify + * completion of command. + * + * @param command Command typed by user. + * @param ui Ui object to print corresponding messages. + * @param allTasks A list of existing tasks. + * @return Ui response to user. + */ + public String findCommand(Ui ui, String command, TaskList allTasks) { + String[] str = command.split("find"); + String keyword = str[1]; + return ui.printFindResults(keyword, allTasks); + } + + /** + * If command starts with "show deadlines or events on", matching + * tasks on input date will be shown. + * If command starts with "find", matching tasks to keyword will + * be shown. + * Corresponding messages will be printed to signify + * completion of command. + * + * @param command Command typed by user. + * @param ui Ui object to print corresponding messages. + * @param allTasks A list of existing tasks. + * @throws DukeException if input is invalid. + * @return Ui response to user. + */ + public String showOrFindCommands(String command, Ui ui, TaskList allTasks) throws DukeException { + if (command.startsWith("show deadlines or events on")) { + return showDeadlinesEventsCommand(ui, command, allTasks); + } else { + return findCommand(ui, command, allTasks); + } + } + + /** + * Saves current task list to archive on archiveAll.txt. + * Corresponding messages will be printed to signify + * completion of command. + * + * @param command Command typed by user. + * @param ui Ui object to print corresponding messages. + * @param allTasks A list of existing tasks. + * @return Ui response to user. + * @throws IOException if file cannot be loaded. + */ + public String archiveCommand(Ui ui, String command, TaskList allTasks, Storage storage) throws IOException { + Storage storage1 = new Storage("data/archiveAll.txt"); + storage1.loadTxtFile(); + storage1.saveWholeListToFile(allTasks); + storage.clear(); + allTasks.deleteAllTasks(); + return ui.printArchiveMessage(); + } + +} + + diff --git a/src/main/java/duke/main/Storage.java b/src/main/java/duke/main/Storage.java new file mode 100644 index 0000000000..f880d9fafb --- /dev/null +++ b/src/main/java/duke/main/Storage.java @@ -0,0 +1,348 @@ +package duke.main; + +import java.io.*; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +import java.util.ArrayList; +import java.util.List; + +import java.nio.file.Paths; + +import duke.task.*; + +/** + * Loads previous task list and saves updated task list to a file on + * hard disk. + */ +public class Storage { + + private final String filePath; + private final String filePathParent; + + Storage(String filePath) { + this.filePath = filePath; + this.filePathParent = Paths.get(filePath).getParent().toString(); + } + + /** + * Loads previous task list if it exists. + * Existing text file on hard disk containing all tasks loops + * through to read each line. + * + * @return List of tasks. + * @throws IOException if file cannot be loaded. + */ + public List loadTxtFile() throws IOException { + + List allTasks = new ArrayList<>(); + + File file3 = new File(this.filePathParent); + assert !this.filePath.equals(""); + assert !this.filePathParent.equals(null); + if (!file3.exists()) { + file3.mkdir(); + } + File file = new File(this.filePath); + if (file.exists()) { + List taskList = new ArrayList<>(); + FileReader file2 = new FileReader(file); + BufferedReader bufferedReader = new BufferedReader(file2); + String taskInformation = bufferedReader.readLine(); + while (taskInformation != null) { + taskList.add(taskInformation); + taskInformation = bufferedReader.readLine(); + } + addAllTasks(taskList, allTasks); + } + return allTasks; + } + + /** + * Adds all tasks from tasks.txt to task list. + * + * @param taskList List of tasks from tasks.txt. + * @param allTasks List to add task to. + */ + public void addAllTasks(List taskList, List allTasks) { + for (int i = 0; i < taskList.size(); i++) { + String task = taskList.get(i); + String[] task1 = task.split(" / "); + boolean isMarked = false; + if (task1[1].equals("[ ]")) { + isMarked = false; + } else if (task1[1].equals("[X]")){ + isMarked = true; + } + DateTimeFormatter dateTimeFormatter1 = DateTimeFormatter.ofPattern("MMM dd yyyy HHmm a"); + if (task.startsWith("T") || task.startsWith("D") || task.startsWith("E")) { + addTask(i, task, task1, isMarked, taskList, dateTimeFormatter1, allTasks); + } else { + assert false: "Erroneous task"; + } + } + } + + /** + * Adds task to task list. + * + * @param index Index of task list. + * @param task Task from tasks.txt to be added. + * @param task1 Parsed task from tasks.txt to be added. + * @param isMarked Task status. + * @param taskList List of tasks from tasks.txt. + * @param dateTimeFormatter1 Datetime format to be used. + * @param allTasks List to add task to. + */ + public void addTask(int index, String task, String[] task1, boolean isMarked, List taskList, + DateTimeFormatter dateTimeFormatter1, List allTasks) { + if (task.startsWith("T")) { + Todo todo = new Todo(index + 1, isMarked, task1[2], + taskList.size()); + allTasks.add(todo); + } else if (task.startsWith("D")) { + Deadline deadline = new Deadline(index + 1, isMarked, task1[2], + LocalDateTime.parse(task1[3], dateTimeFormatter1), taskList.size()); + allTasks.add(deadline); + } else if (task.startsWith("E")) { + String[] taskTiming = task1[3].split("-"); + Event event = new Event(index + 1, isMarked, task1[2], + LocalDateTime.parse(taskTiming[0], dateTimeFormatter1), + LocalDateTime.parse(taskTiming[1], dateTimeFormatter1), taskList.size()); + allTasks.add(event); + } + } + + public String markOrUnmarkStorage(File file, String command, Task task, DateTimeFormatter dateTimeFormatter1, + TaskList taskList, String markOrUnmark) throws IOException { + FileReader file2 = new FileReader(file); + BufferedReader bufferedReader = new BufferedReader(file2); + String[] str = command.split(" "); + int taskIndex = Integer.parseInt(str[1]); + String unchangedTasks = ""; + for (int i = 1; i < taskIndex; i++) { + unchangedTasks = unchangedTasks + bufferedReader.readLine() + "\n"; + } + if (task.getTaskType().equals("[T]")) { + unchangedTasks = unchangedTasks + "T / " + markOrUnmark + " / " + task.getTask() + "\n"; + } else if (task.getTaskType().equals("[D]")) { + unchangedTasks = unchangedTasks + "D / " + markOrUnmark + " / " + + task.getTask() + " / " + + task.getDeadline().format(dateTimeFormatter1) + "\n"; + } else if (task.getTaskType().equals("[E]")) { + unchangedTasks = unchangedTasks + "E / " + markOrUnmark + " / " + + task.getTask() + " / " + + task.getEventStartTime().format(dateTimeFormatter1) + "-" + + task.getEventEndTime().format(dateTimeFormatter1) + "\n"; + } + bufferedReader.readLine(); + for (int i = taskIndex + 1; i <= taskList.getNumberOfTask(); i++) { + unchangedTasks = unchangedTasks + bufferedReader.readLine() + "\n"; + } + return unchangedTasks; + } + + public String deleteStorage(File file, String command, TaskList taskList) throws IOException { + FileReader file2 = new FileReader(file); + BufferedReader bufferedReader = new BufferedReader(file2); + String undeletedTasks = ""; + String[] str = command.split(" "); + int taskIndex = Integer.parseInt(str[1]); + for (int i = 1; i < taskIndex; i++) { + undeletedTasks = undeletedTasks + bufferedReader.readLine() + "\n"; + } + bufferedReader.readLine(); + for (int i = taskIndex; i <= taskList.getNumberOfTask(); i++) { + undeletedTasks = undeletedTasks + bufferedReader.readLine() + "\n"; + } + return undeletedTasks; + } + + /** + * Saves the updated task list to existing file on hard disk. + * If file does not exist, create a new one. + * + * @param command Command input from user. + * @param task Task to be added to text file. + * @param taskList Task list that updates with task changes. + * @throws IOException if file cannot be loaded. + */ + public void saveListToFile(String command, Task task, TaskList taskList) throws IOException { + File file3 = new File(this.filePathParent); + if (!file3.exists()) { + file3.mkdir(); + } + File file = new File(this.filePath); + FileWriter file1 = new FileWriter(file, true); + BufferedWriter buffer = new BufferedWriter(file1); + + DateTimeFormatter dateTimeFormatter1 = + DateTimeFormatter.ofPattern("MMM dd yyyy HHmm a"); + + if (command.startsWith("todo")) { + saveTodo(buffer, task); + } else if (command.startsWith("deadline")) { + saveDeadline(buffer, task, dateTimeFormatter1); + } else if (command.startsWith("event")) { + saveEvent(buffer, task, dateTimeFormatter1); + } else if (command.startsWith("mark")) { + String unchangedTasks = saveMarking(file, command, taskList, task, dateTimeFormatter1); + buffer.write(unchangedTasks); + } else if (command.startsWith("unmark")) { + String unchangedTasks = saveUnmarking(file, command, taskList, task, dateTimeFormatter1); + buffer.write(unchangedTasks); + } else if (command.startsWith("delete")) { + String undeletedTasks = saveDeleting(file, command, taskList); + buffer.write(undeletedTasks); + } + buffer.close(); + } + + /** + * Deletes task from existing file on hard disk. + * + * @param file Existing file to delete the task from. + * @param command Input from user. + * @param taskList Task list that updates with task changes. + * @throws IOException if file cannot be loaded. + */ + public String saveDeleting(File file, String command, TaskList taskList) throws IOException { + String undeletedTasks = deleteStorage(file, command, taskList); + file.createNewFile(); + FileWriter file1 = new FileWriter(file); + BufferedWriter buffer = new BufferedWriter(file1); + return undeletedTasks; + } + + /** + * Saves new marking on task to existing file on hard disk. + * + * @param task Task to be updated on text file. + * @param file Existing file to save the updated task on. + * @param command Input from user. + * @param dateTimeFormatter1 Datetime format to be used + * @param taskList Task list that updates with task changes. + * @throws IOException if file cannot be loaded. + */ + public String saveMarking(File file, String command, TaskList taskList, Task task + , DateTimeFormatter dateTimeFormatter1) throws IOException { + String unchangedTasks = markOrUnmarkStorage(file, command, task, dateTimeFormatter1, + taskList, "[X]"); + file.createNewFile(); + FileWriter file1 = new FileWriter(file); + BufferedWriter buffer = new BufferedWriter(file1); + return unchangedTasks; + } + + /** + * Saves new unmarking on task to existing file on hard disk. + * + * @param task Task to be updated on text file. + * @param file Existing file to save the updated task on. + * @param command Input from user. + * @param dateTimeFormatter1 Datetime format to be used + * @param taskList Task list that updates with task changes. + * @throws IOException if file cannot be loaded. + */ + public String saveUnmarking(File file, String command, TaskList taskList, Task task + , DateTimeFormatter dateTimeFormatter1) throws IOException { + String unchangedTasks = markOrUnmarkStorage(file, command, task, dateTimeFormatter1, + taskList, "[ ]"); + file.createNewFile(); + FileWriter file1 = new FileWriter(file); + BufferedWriter buffer = new BufferedWriter(file1); + return unchangedTasks; + } + + /** + * Saves new todo task to existing file on hard disk. + * + * @param buffer BufferedWriter to write task to existing file. + * @param task Task to be added to text file. + * @throws IOException if file cannot be loaded. + */ + public void saveTodo(BufferedWriter buffer, Task task) throws IOException { + String content = "T / " + task.getTaskStatus() + " / " + task.getTask() + "\n"; + buffer.write(content); + } + + /** + * Saves new deadline task to existing file on hard disk. + * + * @param buffer BufferedWriter to write task to existing file. + * @param task Task to be added to text file. + * @param dateTimeFormatter1 Datetime format to be used + * @throws IOException if file cannot be loaded. + */ + public void saveDeadline(BufferedWriter buffer, Task task, DateTimeFormatter dateTimeFormatter1) + throws IOException { + String content = "D / " + task.getTaskStatus() + " / " + + task.getTask() + " / " + + task.getDeadline().format(dateTimeFormatter1) + "\n"; + buffer.write(content); + } + + /** + * Saves new event task to existing file on hard disk. + * + * @param buffer BufferedWriter to write task to existing file. + * @param task Task to be added to text file. + * @param dateTimeFormatter1 Datetime format to be used + * @throws IOException if file cannot be loaded. + */ + public void saveEvent(BufferedWriter buffer, Task task, DateTimeFormatter dateTimeFormatter1) + throws IOException { + String content = "E / " + task.getTaskStatus() + " / " + + task.getTask() + " / " + + task.getEventStartTime().format(dateTimeFormatter1) + "-" + + task.getEventEndTime().format(dateTimeFormatter1) + "\n"; + buffer.write(content); + } + + + + public void saveWholeListToFile(TaskList taskList) throws IOException { + File file3 = new File(this.filePathParent); + if (!file3.exists()) { + file3.mkdir(); + } + File file = new File(this.filePath); + if (!file.exists()) { + file.createNewFile(); + } + + String filePathParent = Paths.get("data/tasks.txt").getParent().toString(); + File file4 = new File(filePathParent); + if (!file4.exists()) { + file4.mkdir(); + } + File file5 = new File("data/tasks.txt"); + + FileReader file2 = new FileReader(file5); + BufferedReader bufferedReader = new BufferedReader(file2); + String undeletedTasks = ""; + for (int i = 1; i <= taskList.getNumberOfTask(); i++) { + undeletedTasks = undeletedTasks + bufferedReader.readLine() + "\n"; + } + + FileWriter file1 = new FileWriter(file); + BufferedWriter buffer = new BufferedWriter(file1); + buffer.write(undeletedTasks); + buffer.close(); + } + + public void clear() throws IOException { + File file3 = new File(this.filePathParent); + if (!file3.exists()) { + file3.mkdir(); + } + File file = new File(this.filePath); + FileWriter file1 = new FileWriter(file, false); + BufferedWriter buffer = new BufferedWriter(file1); + buffer.flush(); + buffer.close(); + file1.close(); + } + +} diff --git a/src/main/java/duke/main/TaskList.java b/src/main/java/duke/main/TaskList.java new file mode 100644 index 0000000000..ff1f38b4d8 --- /dev/null +++ b/src/main/java/duke/main/TaskList.java @@ -0,0 +1,142 @@ +package duke.main; + +import java.util.ArrayList; +import java.util.List; + +import duke.task.*; + +/** + * Keeps track of and updates the list of tasks. + */ +public class TaskList { + + private List allTasks; + + TaskList() { + this.allTasks = new ArrayList(); + } + + TaskList(List allTasks) { + this.allTasks = allTasks; + } + + /** + * Updates relevant task's status as done. + * + * @param oldTask Task to be marked as done. + * @param taskIndex Index of task to be marked as done. + * @return New task that is marked as done. + */ + public Task markTaskAsDone(Task oldTask, int taskIndex) { + if (oldTask.getTaskType().equals("[T]")) { + Todo todo = new Todo(oldTask.getTaskNumber(), + true, oldTask.getTask(), + this.allTasks.size()); + this.allTasks.set(taskIndex, todo); + assert taskIndex == this.allTasks.indexOf(oldTask); + oldTask = todo; + } else if (oldTask.getTaskType().equals("[D]")) { + Deadline deadline = new Deadline(oldTask.getTaskNumber(), + true, oldTask.getTask(), + oldTask.getDeadline(), this.allTasks.size()); + this.allTasks.set(taskIndex, deadline); + assert taskIndex == this.allTasks.indexOf(oldTask); + oldTask = deadline; + } else if (oldTask.getTaskType().equals("[E]")) { + Event event = new Event(oldTask.getTaskNumber(), + true, oldTask.getTask(), + oldTask.getEventStartTime(), + oldTask.getEventEndTime(), this.allTasks.size()); + this.allTasks.set(taskIndex, event); + assert taskIndex == this.allTasks.indexOf(oldTask); + oldTask = event; + } else { + assert false: "No such class type"; + } + return oldTask; + } + + /** + * Updates relevant task's status as undone. + * + * @param oldTask Task to be unmarked as undone. + * @param taskIndex Index of task to be unmarked as undone. + * @return New task that is unmarked as undone. + */ + public Task unmarkTaskAsUndone(Task oldTask, int taskIndex) { + if (oldTask.getTaskType().equals("[T]")) { + Todo todo = new Todo(oldTask.getTaskNumber(), + false, oldTask.getTask(), + this.allTasks.size()); + this.allTasks.set(taskIndex, todo); + assert taskIndex == this.allTasks.indexOf(oldTask); + } else if (oldTask.getTaskType().equals("[D]")) { + Deadline deadline = new Deadline(oldTask.getTaskNumber(), + false, oldTask.getTask(), + oldTask.getDeadline(), this.allTasks.size()); + this.allTasks.set(taskIndex, deadline); + assert taskIndex == this.allTasks.indexOf(oldTask); + } else if (oldTask.getTaskType().equals("[E]")) { + Event event = new Event(oldTask.getTaskNumber(), + false, oldTask.getTask(), + oldTask.getEventStartTime(), + oldTask.getEventEndTime(), this.allTasks.size()); + this.allTasks.set(taskIndex, event); + assert taskIndex == this.allTasks.indexOf(oldTask); + } else { + assert false: "No such class type"; + } + return oldTask; + } + + /** + * Deletes task from task list. + * + * @param taskIndex Index of task to be deleted. + */ + public void deleteTask(int taskIndex) { + this.allTasks.remove(taskIndex); + } + + /** + * Adds task to task list. + * + * @param task Task to be added to task list. + */ + public void addTask(Task task) { + this.allTasks.add(task); + } + + /** + * Shows all tasks. + * + * @return List of existing tasks. + */ + public List getAllTasks() { + return this.allTasks; + } + + /** + * Gets a specific task based on its index. + * + * @param index Index of task to be retrieved. + * @return Task that is retrieved. + */ + public Task getTask(int index) { + return this.allTasks.get(index); + } + + /** + * Gets total number of tasks. + * + * @return Total number of tasks. + */ + public int getNumberOfTask() { + return this.allTasks.size(); + } + + public void deleteAllTasks() { + allTasks.removeAll(allTasks); + } + +} diff --git a/src/main/java/duke/main/Ui.java b/src/main/java/duke/main/Ui.java new file mode 100644 index 0000000000..20556a1078 --- /dev/null +++ b/src/main/java/duke/main/Ui.java @@ -0,0 +1,162 @@ +package duke.main; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +import java.util.List; + +import duke.task.*; + +/** + * Prints responses to commands. + */ +public class Ui { + + Ui() { } + /** + * Prints greeting message when app is started. + * + * @return String of greeting response. + */ + public String printGreetingMessage() { + String output; + String logo; + logo = " ____ _ \n" + + "| _ \\ _ _| | _____ \n" + + "| | | | | | | |/ / _ \\\n" + + "| |_| | |_| | < __/\n" + + "|____/ \\__,_|_|\\_\\___|\n"; + output = "Hello from\n" + logo; + output += "\n\t Hello! I'm Duke\n" + + "\t What can I do for you?"; + return output; + } + + /** + * Prints a list of current tasks. + * + * @param allTasks List of all existing tasks. + * @return String of existing list of tasks. + */ + public String printCommandList(List allTasks) { + DateTimeFormatter dateTimeFormatter1 = + DateTimeFormatter.ofPattern("MMM dd yyyy HHmm a"); + + String output; + output = "\t Here are the tasks in your list:"; + for (int i = 0; i < allTasks.size(); i++) { + int numbering = i + 1; + Task task = allTasks.get(i); + String time = ""; + if (task.getTaskType().equals("[D]")) { + time = " (by: " + + task.getDeadline().format(dateTimeFormatter1) + ")"; + } else if (task.getTaskType().equals("[E]")) { + time = " (from: " + task.getEventStartTime().format(dateTimeFormatter1) + + " to: " + task.getEventEndTime().format(dateTimeFormatter1) + ")"; + } + assert task.getTaskType() != ""; + output += "\n\t " + numbering + "." + task.getTaskType() + task.getTaskStatus() + " " + + task.getTask() + time; + } + return output; + } + + /** + * Prints a list of deadlines or events happening on this day. + * + * @param dateTime Date that user wants to find tasks on. + * @param allTasks List of all existing tasks. + * @return String of list of deadlines or events due on stated day. + */ + public String printDeadlineOrEventsOnDay(LocalDate dateTime, TaskList allTasks) { + DateTimeFormatter dateTimeFormatter1 = + DateTimeFormatter.ofPattern("MMM dd yyyy HHmm a"); + + String output; + output = "\t Here are the tasks in your list at this day:"; + int numbering = 1; + for (int i = 0; i < allTasks.getNumberOfTask(); i++) { + Task task = allTasks.getTask(i); + String time = ""; + if (task.getTaskType().equals("[D]") && task.getDate().equals(dateTime)) { + time = " (by: " + + task.getDeadline().format(dateTimeFormatter1) + ")"; + output += "\n\t " + numbering + "." + + task.getTaskType() + task.getTaskStatus() + " " + + task.getTask() + time; + numbering += 1; + } else if (task.getTaskType().equals("[E]") && task.getDate().equals(dateTime)) { + time = " (from: " + + task.getEventStartTime().format(dateTimeFormatter1) + + " to: " + + task.getEventEndTime().format(dateTimeFormatter1) + + ")"; + output += "\n\t " + numbering + "." + + task.getTaskType() + task.getTaskStatus() + " " + + task.getTask() + time; + numbering += 1; + } + } + return output; + } + + /** + * Prints a list of tasks contains keyword. + * + * @param keyword Keyword that user wants to search for relevant + * tasks. + * @param allTasks List of all existing tasks. + * @return String of tasks relating to keyword. + */ + public String printFindResults(String keyword, TaskList allTasks) { + DateTimeFormatter dateTimeFormatter1 = + DateTimeFormatter.ofPattern("MMM dd yyyy HHmm a"); + + String output; + output = "\t Here are the matching tasks in your list:"; + int numbering = 1; + for (int i = 0; i < allTasks.getNumberOfTask(); i++) { + Task task = allTasks.getTask(i); + String time = ""; + if (task.getTaskType().equals("[D]") && task.getTask().contains(keyword)) { + time = " (by: " + task.getDeadline().format(dateTimeFormatter1) + ")"; + output += "\n\t " + numbering + "." + task.getTaskType() + task.getTaskStatus() + " " + + task.getTask() + time; + numbering += 1; + } else if (task.getTaskType().equals("[E]") && task.getTask().contains(keyword)) { + time = " (from: " + + task.getEventStartTime().format(dateTimeFormatter1) + " to: " + + task.getEventEndTime().format(dateTimeFormatter1) + ")"; + output += "\n\t " + numbering + "." + task.getTaskType() + task.getTaskStatus() + " " + + task.getTask() + time; + numbering += 1; + } else if (task.getTaskType().equals("[T]") && task.getTask().contains(keyword)) { + time = ""; + output += "\n\t " + numbering + "." + task.getTaskType() + task.getTaskStatus() + " " + + task.getTask() + time; + numbering += 1; + } + } + return output; + } + + /** + * Prints exit message when app is terminated. + * + * @return String of exit response. + */ + public String printByeMessage() { + String output; + output = "\t Bye. Hope to see you again soon!"; + return output; + } + + public String printArchiveMessage() { + return "\t Previous archive has been cleared. \n\t Current tasks have been archived."; + } + + public void showLoadingError(String message) { + System.out.println(message); + } +} diff --git a/src/main/java/duke/task/Deadline.java b/src/main/java/duke/task/Deadline.java new file mode 100644 index 0000000000..1fce2b38b3 --- /dev/null +++ b/src/main/java/duke/task/Deadline.java @@ -0,0 +1,102 @@ +package duke.task; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +import java.util.List; + +/** + * Represents task type of deadline. + */ +public class Deadline extends Task { + private final String taskType; + private final LocalDateTime taskDeadline; + DateTimeFormatter dateTimeFormatter1 = + DateTimeFormatter.ofPattern("MMM dd yyyy HHmm a"); + + public Deadline(int taskNumber, boolean isMarked, String task, LocalDateTime taskDeadline, int totalNumOfTasks) { + super(taskNumber, isMarked, task, totalNumOfTasks); + this.taskType = "[D]"; + this.taskDeadline = taskDeadline; + } + + /** + * Prints that task is marked as done when task is done. + * + * @return String response that show task is marked as done. + */ + @Override + public String markAsDone() { + return "\t Nice! I've marked this task as done:\n" + + "\t " + this.taskType + "[X]" + " " + super.task + + " (by: " + this.taskDeadline.format(dateTimeFormatter1) + ")"; + } + + /** + * Prints that task is marked as not done when task is unmarked. + * + * @return String response that show task is unmarked as undone. + */ + @Override + public String unmarkAsUndone() { + return "\t OK, I've marked this task as not done yet:\n" + + "\t " + this.taskType + "[ ]" + " " + super.task + + " (by: " + this.taskDeadline.format(dateTimeFormatter1) + ")"; + } + + /** + * Prints task information when added to task list. + * + * @return String response that show task is added. + */ + public String printDeadlineTask() { + return "\t Got it. I've added this task:" + + "\n\t [D]" + super.getTaskStatus() + " " + super.task + + "(by: " + this.taskDeadline.format(dateTimeFormatter1) + ")" + + "\n\t Now you have " + super.totalNumOfTasks + " tasks in the list."; + } + + /** + * Prints that task is deleted. + * + * @return String response that show task is deleted. + */ + @Override + public String printDelete(List allTasks) { + return "\t Noted. I've removed this task:" + "\n\t " + this.taskType + + super.getTaskStatus() + " " + super.task + " (by: " + + this.taskDeadline.format(dateTimeFormatter1) + ")" + + "\n\t Now you have " + allTasks.size() + " tasks in the list."; + } + + /** + * Returns that this is a deadline task type. + * + * @return Type of task. + */ + @Override + public String getTaskType() { + return this.taskType; + } + + /** + * Gets task deadline. + * + * @return Date and time of deadline. + */ + @Override + public LocalDateTime getDeadline() { + return this.taskDeadline; + } + + /** + * Gets date of task deadline. + * + * @return Date of deadline. + */ + @Override + public LocalDate getDate() { + return this.taskDeadline.toLocalDate(); + } +} diff --git a/src/main/java/duke/task/Event.java b/src/main/java/duke/task/Event.java new file mode 100644 index 0000000000..e15c0d7953 --- /dev/null +++ b/src/main/java/duke/task/Event.java @@ -0,0 +1,121 @@ +package duke.task; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +import java.util.List; + +/** + * Represents task type of event. + */ +public class Event extends Task { + private final String taskType; + private final LocalDateTime eventStartTime; + private final LocalDateTime eventEndTime; + DateTimeFormatter dateTimeFormatter1 = + DateTimeFormatter.ofPattern("MMM dd yyyy HHmm a"); + + public Event(int taskNumber, boolean isMarked, String task, + LocalDateTime eventStartTime, LocalDateTime eventEndTime, int totalNumOfTasks) { + super(taskNumber, isMarked, task, totalNumOfTasks); + this.taskType = "[E]"; + this.eventStartTime = eventStartTime; + this.eventEndTime = eventEndTime; + } + + /** + * Prints that task is marked as done when task is done. + * + * @return String response that show task is marked as done. + */ + @Override + public String markAsDone() { + return "\t Nice! I've marked this task as done:\n" + + "\t " + this.taskType + "[X]" + " " + super.task + + " (from: " + this.eventStartTime.format(dateTimeFormatter1) + + " to: " + + this.eventEndTime.format(dateTimeFormatter1); + } + + /** + * Prints that task is marked as not done when task is unmarked. + * + * @return String response that show task is unmarked as undone. + */ + @Override + public String unmarkAsUndone() { + return "\t OK, I've marked this task as not done yet:\n" + + "\t " + this.taskType + "[ ]" + " " + super.task + + " (from: " + this.eventStartTime.format(dateTimeFormatter1) + + " to: " + + this.eventEndTime.format(dateTimeFormatter1); + } + + /** + * Prints task information when added to task list. + * + * @return String response that show task is added. + */ + public String printEventTask() { + return "\t Got it. I've added this task:" + + "\n\t [E]" + super.getTaskStatus() + " " + super.task + + "(from: " + this.eventStartTime.format(dateTimeFormatter1) + + " to: " + this.eventEndTime.format(dateTimeFormatter1) + ")" + + "\n\t Now you have " + super.totalNumOfTasks + " tasks in the list."; + } + + /** + * Prints that task is deleted. + * + * @return String response that show task is deleted. + */ + @Override + public String printDelete(List allTasks) { + return "\t Noted. I've removed this task:" + "\n\t " + this.taskType + + super.getTaskStatus() + " " + super.task + " (from: " + + this.eventStartTime.format(dateTimeFormatter1) + " to: " + + this.eventEndTime.format(dateTimeFormatter1) + ")" + "\n\t Now you have " + + allTasks.size() + " tasks in the list."; + } + + /** + * Returns that this is an event task type. + * + * @return Task type. + */ + @Override + public String getTaskType() { + return this.taskType; + } + + /** + * Get the starting time of event. + * + * @return Date and time of event start time. + */ + @Override + public LocalDateTime getEventStartTime() { + return this.eventStartTime; + } + + /** + * Get the ending time of event. + * + * @return Date and time of event end time. + */ + @Override + public LocalDateTime getEventEndTime() { + return this.eventEndTime; + } + + /** + * Get the date of event. + * + * @return Date of event. + */ + @Override + public LocalDate getDate() { + return this.eventStartTime.toLocalDate(); + } +} diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java new file mode 100644 index 0000000000..d07a63899c --- /dev/null +++ b/src/main/java/duke/task/Task.java @@ -0,0 +1,149 @@ +package duke.task; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +import java.util.List; + +/** + * Represents a Task. + * Task information are stored here. + */ +public class Task { + protected final int taskNumber; + protected final boolean isMarked; + protected final String task; + protected final int totalNumOfTasks; + + Task(int taskNumber, boolean isMarked, String task, int totalNumOfTasks) { + this.taskNumber = taskNumber; + this.isMarked = isMarked; + this.task = task; + this.totalNumOfTasks = totalNumOfTasks; + } + + /** + * Prints that task is marked as done when task is done. + * + * @return String response that show task is marked as done. + */ + public String markAsDone() { + return "\t Nice! I've marked this task as done:\n" + + "\t " + "[X]" + " " + this.task; + } + + /** + * Prints that task is marked as not done when task is unmarked. + * + * @return String response that show task is unmarked as undone. + */ + public String unmarkAsUndone() { + return "\t OK, I've marked this task as not done yet:\n" + + "\t " + "[ ]" + " " + this.task; + } + + /** + * Prints that task is deleted. + * + * @return String response that show task is deleted. + */ + public String printDelete(List allTasks) { + return "\t Noted. I've removed this task:" + "\n\t " + + this.getTaskStatus() + " " + this.task + + "\n\t Now you have " + allTasks.size() + " tasks in the list."; + } + + /** + * Gets task number. + * + * @return Index of task on task list. + */ + public int getTaskNumber() { + return this.taskNumber; + } + + /** + * Gets type of task. + * Returns empty string as parent class is not a specific type of + * task. + * + * @return String of task type. + */ + public String getTaskType() { + return ""; + } + + /** + * Gets whether task is done. + * + * @return String of brackets that fills with X if task is done. + */ + public String getTaskStatus() { + if (!this.isMarked) { + return "[ ]"; + } else { + return "[X]"; + } + } + + /** + * Gets task. + * + * @return Task. + */ + public String getTask() { + return this.task; + } + + /** + * Gets deadline. + * Returns null as parent class does not require deadlines. + * + * @return Date and time of deadline. + */ + public LocalDateTime getDeadline() { + return null; + } + + /** + * Gets event start time. + * Returns null as parent class does not have a start time. + * + * @return Date and time of event start time. + */ + public LocalDateTime getEventStartTime() { + return null; + } + + /** + * Gets event start time. + * Returns null as parent class does not have an end time. + * + * @return Date and time of event end time. + */ + public LocalDateTime getEventEndTime() { + return null; + } + + /** + * Gets task date. + * Returns null as parent class does not have a date required. + * + * @return Date of task. + */ + public LocalDate getDate() { + return null; + } + + /** + * Overrides default equal method such that same type of object + * can pass Junit test. + * + * @param o Object to be compared to. + * @return Boolean of whether object has same class. + */ + @Override + public boolean equals(Object o) { + return getClass() == o.getClass(); + } +} diff --git a/src/main/java/duke/task/Todo.java b/src/main/java/duke/task/Todo.java new file mode 100644 index 0000000000..a633661804 --- /dev/null +++ b/src/main/java/duke/task/Todo.java @@ -0,0 +1,70 @@ +package duke.task; + +import java.util.List; + +/** + * Represents task type of event. + */ +public class Todo extends Task { + private final String taskType; + + public Todo(int taskNumber, boolean isMarked, String task, int totalNumOfTasks) { + super(taskNumber, isMarked, task, totalNumOfTasks); + this.taskType = "[T]"; + } + + /** + * Prints that task is marked as done when task is done. + * + * @return String response that show task is marked as done. + */ + @Override + public String markAsDone() { + return "\t Nice! I've marked this task as done:\n" + + "\t " + this.taskType + "[X]" + " " + this.task; + } + + /** + * Prints that task is marked as not done when task is unmarked. + * + * @return String response that show task is unmarked as undone. + */ + @Override + public String unmarkAsUndone() { + return "\t OK, I've marked this task as not done yet:\n" + + "\t " + this.taskType + "[ ]" + " " + this.task; + } + + /** + * Prints task information when added to task list. + * + * @return String response that show task is added. + */ + public String printToDoTask() { + return "\t Got it. I've added this task:" + + "\n\t [T]" + super.getTaskStatus() + " " + super.task + + "\n\t Now you have " + super.totalNumOfTasks + " tasks in the list."; + } + + /** + * Prints that task is deleted. + * + * @return String response that show task is deleted. + */ + @Override + public String printDelete(List allTasks) { + return "\t Noted. I've removed this task:" + "\n\t " + this.taskType + + super.getTaskStatus() + " " + super.task + + "\n\t Now you have " + allTasks.size() + " tasks in the list."; + } + + /** + * Returns that this is a todo task type. + * + * @return Task type. + */ + @Override + public String getTaskType() { + return this.taskType; + } +} diff --git a/src/main/resources/.idea/.gitignore b/src/main/resources/.idea/.gitignore new file mode 100644 index 0000000000..26d33521af --- /dev/null +++ b/src/main/resources/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/src/main/resources/.idea/misc.xml b/src/main/resources/.idea/misc.xml new file mode 100644 index 0000000000..639900d13c --- /dev/null +++ b/src/main/resources/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/main/resources/.idea/modules.xml b/src/main/resources/.idea/modules.xml new file mode 100644 index 0000000000..e8782072ec --- /dev/null +++ b/src/main/resources/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/.idea/vcs.xml b/src/main/resources/.idea/vcs.xml new file mode 100644 index 0000000000..c2365ab11f --- /dev/null +++ b/src/main/resources/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/main/resources/images/DaDuke.png b/src/main/resources/images/DaDuke.png new file mode 100644 index 0000000000..3284ded67c Binary files /dev/null and b/src/main/resources/images/DaDuke.png differ diff --git a/src/main/resources/images/DaUser.png b/src/main/resources/images/DaUser.png new file mode 100644 index 0000000000..6f3132b0c8 Binary files /dev/null and b/src/main/resources/images/DaUser.png differ diff --git a/src/main/resources/view/DialogBox.fxml b/src/main/resources/view/DialogBox.fxml new file mode 100644 index 0000000000..ce49256c32 --- /dev/null +++ b/src/main/resources/view/DialogBox.fxml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml new file mode 100644 index 0000000000..430df3ea52 --- /dev/null +++ b/src/main/resources/view/MainWindow.fxml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + +