diff --git a/README.md b/README.md index 8715d4d915..4306cadcce 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,197 @@ -# Duke project template - -This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it. - -## Setting up in Intellij - -Prerequisites: JDK 11, update Intellij to the most recent version. - -1. Open Intellij (if you are not in the welcome screen, click `File` > `Close Project` to close the existing project first) -1. Open the project into Intellij as follows: - 1. Click `Open`. - 1. Select the project directory, and click `OK`. - 1. If there are any further prompts, accept the defaults. -1. Configure the project to use **JDK 11** (not other versions) as explained in [here](https://www.jetbrains.com/help/idea/sdk.html#set-up-jdk).
- In the same dialog, set the **Project language level** field to the `SDK default` option. -3. After that, locate the `src/main/java/Duke.java` file, right-click it, and choose `Run Duke.main()` (if the code editor is showing compile errors, try restarting the IDE). If the setup is correct, you should see something like the below as the output: - ``` - Hello from - ____ _ - | _ \ _ _| | _____ - | | | | | | | |/ / _ \ - | |_| | |_| | < __/ - |____/ \__,_|_|\_\___| - ``` +# Duke User Guide + +An application which aims to help you to manage your tasks through the use of Command Line Interface (CLI). +With a variety of features, this will help the users to sort their tasks in an efficient manner. + +## Features + +1. Add task + - You can add task to this application. +2. Delete task + - You can delete the tasks you previously added. +3. Find task + - You can find the tasks which have the common keyword. +4. Mark/Unmark task + - You can mark/unmark task to indicate whether it has been done. +5. View task + - You can view all the tasks on a specific day too. +6. List task + - You can list all the tasks you added. + +## Usage + +### 1. Add Task +There are three different types of tasks - Todo, Deadline and Event. +Todo is for tasks without time while Deadline and Event have time component. + +**Add Todo** + +Format: + +- `todo TASK` +- TASK are the tasks to be added. It cannot be null/empty. + +Example of usage: + +`todo help kris do cs2103` + +Expected outcome: + +``` +Got it. I've added this task: +[T][ ] help kris do cs2103 +Now you have 1 tasks in the list. +``` +**Add Deadline** + +Format: + +- `deadline TASK /by DATE TIME` +- TASK are the tasks to be added. It cannot be null/empty. +- DATE are the date which the tasks are due by. It should be entered with this format: `DD/MM/YYYY`. It cannot be null/empty. +- TIME are the time which the tasks are due by. It should be entered with this format: `HHMM`. It cannot be null/empty. + +Example of usage: + +`deadline help kris do cs2103 /by 18/2/2022 2359` + +Expected outcome: + +``` +Got it. I've added this task: +[D][ ] help kris do cs2103 (by: Feb 18 2022 11:59 PM) +Now you have 1 tasks in the list. +``` + +**Add Event** + +Format: + +- `event TASK /at DATE TIME` +- TASK are the tasks to be added. It cannot be null/empty. +- DATE are the date which the tasks are due by. It should be entered with this format: `DD/MM/YYYY`. It cannot be null/empty. +- TIME are the time which the tasks are due by. It should be entered with this format: `HHMM`. It cannot be null/empty. + +Example of usage: + +`event help kris do cs2103 /at 18/2/2022 1500` + +Expected outcome: + +``` +Got it. I've added this task: +[E][ ] help kris do cs2103 (by: Feb 18 2022 3:00 PM) +Now you have 1 tasks in the list. +``` + +### 2. Delete Task + +Format: + +- `delete TASK_INDEX` +- TASK_INDEX are the index of the tasks. The index can be viewed by typing `list`. It cannot be null/empty. + +Example of usage: + +`delete 1` + +Expected outcome: + +``` +Noted.I've removed this task: +[T][ ] help kris do cs2103 +Now you have 2 tasks in the list. +``` + +### 3. Find Task + +Format: + +- `find KEYWORD` +- KEYWORD are the keyword found in the tasks. It cannot be null/empty + +Example of usage: + +`find cs2103` + +Expected outcome: + +``` +Here are the matching tasks in your list: +1.[D][ ] help kris do cs2103 (by: Feb 18 2022 11:59 PM) +2.[E][ ] help kris do cs2103 (at: Feb 18 2022 3:00 PM) +``` + +### 4. Mark/Unmark Task + +**Mark Task** + +Format: + +- `mark TASK_INDEX` +- TASK_INDEX are the index of the tasks. The index can be viewed by typing `list`. It cannot be null/empty. + +Example of usage: + +`mark 1` + +Expected outcome: + +``` +Nice!I've marked this task as done: +[D][X] help kris do cs2103 (by: Feb 18 2022 11:59 PM) +``` + +**Unmark Task** + +Format: + +- `unmark TASK_INDEX` +- TASK_INDEX are the index of the tasks. The index can be viewed by typing `list`. It cannot be null/empty. + +Example of usage: + +`unmark 1` + +Expected outcome: + +``` +OK,I've marked this task as not done yet: +[D][ ] help kris do cs2103 (by: Feb 18 2022 11:59 PM) +``` +### 5. View Task + +Format: + +- `view DATE` +- DATE are the date which the tasks are due by. It should be entered with this format: `DD/MM/YYYY`. It cannot be null/empty. + +Example of usage: + +`view 18/2/2022` + +Expected outcome: + +``` +Your task for the day,Feb 18 2022: +1.[E][ ] help kris do cs2103 (at: Feb 18 2022 3:00 PM) +2.[D][ ] help kris do cs2103 (by: Feb 18 2022 11:59 PM) +``` +### 6. List Task + +Format: + +- `list` + +Example of usage: + +`list` + +Expected outcome: + +``` +Here are the tasks in your list: +1.[D][ ] help kris do cs2103 (by: Feb 18 2022 11:59 PM) +2.[E][ ] help kris do cs2103 (by: Feb 18 2022 3:00 PM) +``` + diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000000..46b9671e45 --- /dev/null +++ b/build.gradle @@ -0,0 +1,60 @@ +plugins { + id 'java' + id 'application' + id 'checkstyle' + 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.Launcher" +} + +shadowJar { + archiveBaseName = "duke" + archiveClassifier = null +} + +checkstyle { + toolVersion = '8.29' +} + +run{ + standardInput = System.in +} diff --git a/data/tasks.txt b/data/tasks.txt new file mode 100644 index 0000000000..db51f0ace8 --- /dev/null +++ b/data/tasks.txt @@ -0,0 +1,13 @@ +List +deadline help Kris do cs3132 /by 2/3/2001 1800 +Todo buy bread +deadline help Kris do cs2103 /by 2/3/2001 1800 +Event help Kris do cn4122 /at 3/2/1222 1800 +list +Mark 1 +Mark 2 +List +Find cs +Find help +Bye + diff --git a/docs/README.md b/docs/README.md index 8077118ebe..92301b570d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,29 +1,198 @@ -# User Guide +# Duke User Guide + +An application which aims to help you to manage your tasks through the use of Command Line Interface (CLI). +With a variety of features, this will help the users to sort their tasks in an efficient manner. ## Features -### Feature-ABC +1. Add task + - You can add task to this application. +2. Delete task + - You can delete the tasks you previously added. +3. Find task + - You can find the tasks which have the common keyword. +4. Mark/Unmark task + - You can mark/unmark task to indicate whether it has been done. +5. View task + - You can view all the tasks on a specific day too. +6. List task + - You can list all the tasks you added. -Description of the feature. +## Usage -### Feature-XYZ +### 1. Add Task +There are three different types of tasks - Todo, Deadline and Event. +Todo is for tasks without time while Deadline and Event have time component. -Description of the feature. +**Add Todo** -## Usage +Format: + +- `todo TASK` +- TASK are the tasks to be added. It cannot be null/empty. + +Example of usage: + +`todo help kris do cs2103` + +Expected outcome: + +``` +Got it. I've added this task: +[T][ ] help kris do cs2103 +Now you have 1 tasks in the list. +``` +**Add Deadline** -### `Keyword` - Describe action +Format: -Describe the action and its outcome. +- `deadline TASK /by DATE TIME` +- TASK are the tasks to be added. It cannot be null/empty. +- DATE are the date which the tasks are due by. It should be entered with this format: `DD/MM/YYYY`. It cannot be null/empty. +- TIME are the time which the tasks are due by. It should be entered with this format: `HHMM`. It cannot be null/empty. Example of usage: -`keyword (optional arguments)` +`deadline help kris do cs2103 /by 18/2/2022 2359` Expected outcome: -Description of the outcome. +``` +Got it. I've added this task: +[D][ ] help kris do cs2103 (by: Feb 18 2022 11:59 PM) +Now you have 1 tasks in the list. +``` + +**Add Event** + +Format: + +- `event TASK /at DATE TIME` +- TASK are the tasks to be added. It cannot be null/empty. +- DATE are the date which the tasks are due by. It should be entered with this format: `DD/MM/YYYY`. It cannot be null/empty. +- TIME are the time which the tasks are due by. It should be entered with this format: `HHMM`. It cannot be null/empty. + +Example of usage: + +`event help kris do cs2103 /at 18/2/2022 1500` + +Expected outcome: ``` -expected output +Got it. I've added this task: +[E][ ] help kris do cs2103 (by: Feb 18 2022 3:00 PM) +Now you have 1 tasks in the list. ``` + +### 2. Delete Task + +Format: + +- `delete TASK_INDEX` +- TASK_INDEX are the index of the tasks. The index can be viewed by typing `list`. It cannot be null/empty. + +Example of usage: + +`delete 1` + +Expected outcome: + +``` +Noted.I've removed this task: +[T][ ] help kris do cs2103 +Now you have 2 tasks in the list. +``` + +### 3. Find Task + +Format: + +- `find KEYWORD` +- KEYWORD are the keyword found in the tasks. It cannot be null/empty + +Example of usage: + +`find cs2103` + +Expected outcome: + +``` +Here are the matching tasks in your list: +1.[D][ ] help kris do cs2103 (by: Feb 18 2022 11:59 PM) +2.[E][ ] help kris do cs2103 (at: Feb 18 2022 3:00 PM) +``` + +### 4. Mark/Unmark Task + +**Mark Task** + +Format: + +- `mark TASK_INDEX` +- TASK_INDEX are the index of the tasks. The index can be viewed by typing `list`. It cannot be null/empty. + +Example of usage: + +`mark 1` + +Expected outcome: + +``` +Nice!I've marked this task as done: +[D][X] help kris do cs2103 (by: Feb 18 2022 11:59 PM) +``` + +**Unmark Task** + +Format: + +- `unmark TASK_INDEX` +- TASK_INDEX are the index of the tasks. The index can be viewed by typing `list`. It cannot be null/empty. + +Example of usage: + +`unmark 1` + +Expected outcome: + +``` +OK,I've marked this task as not done yet: +[D][ ] help kris do cs2103 (by: Feb 18 2022 11:59 PM) +``` +### 5. View Task + +Format: + +- `view DATE` +- DATE are the date which the tasks are due by. It should be entered with this format: `DD/MM/YYYY`. It cannot be null/empty. + +Example of usage: + +`view 18/2/2022` + +Expected outcome: + +``` +Your task for the day,Feb 18 2022: +1.[E][ ] help kris do cs2103 (at: Feb 18 2022 3:00 PM) +2.[D][ ] help kris do cs2103 (by: Feb 18 2022 11:59 PM) +``` +### 6. List Task + +Format: + +- `list` + +Example of usage: + +`list` + +Expected outcome: + +``` +Here are the tasks in your list: +1.[D][ ] help kris do cs2103 (by: Feb 18 2022 11:59 PM) +2.[E][ ] help kris do cs2103 (by: Feb 18 2022 3:00 PM) +``` + + diff --git a/docs/Ui.png b/docs/Ui.png new file mode 100644 index 0000000000..511f6b6af4 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/.idea/.name b/src/.idea/.name new file mode 100644 index 0000000000..85d32edfa3 --- /dev/null +++ b/src/.idea/.name @@ -0,0 +1 @@ +Duke.java \ No newline at end of file diff --git a/src/.idea/checkstyle-idea.xml b/src/.idea/checkstyle-idea.xml new file mode 100644 index 0000000000..6fb7092bb5 --- /dev/null +++ b/src/.idea/checkstyle-idea.xml @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/src/.idea/vcs.xml b/src/.idea/vcs.xml new file mode 100644 index 0000000000..6c0b863585 --- /dev/null +++ b/src/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/.idea/workspace.xml b/src/.idea/workspace.xml new file mode 100644 index 0000000000..3ef3d6a907 --- /dev/null +++ b/src/.idea/workspace.xml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1644256189842 + + + + + + + \ No newline at end of file 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/Deadline.java b/src/main/java/duke/Deadline.java new file mode 100644 index 0000000000..e552935b8c --- /dev/null +++ b/src/main/java/duke/Deadline.java @@ -0,0 +1,27 @@ +package duke; + +class Deadline extends Task { + + protected String by; + + public Deadline(String description, String by) { + super(description); + this.by = by; + } + + @Override + public String toString() { + return "[D]" + super.toString() + "(by: " + by + ")"; + } + + @Override + public String getInitial() { + return "[D]"; + } + + @Override + public String getTime() { + String timeFormat = "hh:mm AM"; + return by.substring(by.length() - timeFormat.length()); + } +} diff --git a/src/main/java/duke/DialogBox.java b/src/main/java/duke/DialogBox.java new file mode 100644 index 0000000000..09eeb11b34 --- /dev/null +++ b/src/main/java/duke/DialogBox.java @@ -0,0 +1,48 @@ +package duke; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; + +public class DialogBox extends HBox { + + private Label text; + private ImageView displayPicture; + + public DialogBox(Label l, ImageView iv) { + text = l; + displayPicture = iv; + + text.setWrapText(true); + displayPicture.setFitWidth(100.0); + displayPicture.setFitHeight(100.0); + + this.setAlignment(Pos.TOP_RIGHT); + this.getChildren().addAll(text, displayPicture); + } + + /** + * Flips the dialog box such that the ImageView is on the left and text on the right. + */ + private void flip() { + this.setAlignment(Pos.TOP_LEFT); + ObservableList tmp = FXCollections.observableArrayList(this.getChildren()); + FXCollections.reverse(tmp); + this.getChildren().setAll(tmp); + } + + public static DialogBox getUserDialog(Label l, ImageView iv) { + return new DialogBox(l, iv); + } + + public static DialogBox getDukeDialog(Label l, ImageView iv) { + var db = new DialogBox(l, iv); + db.flip(); + return db; + } + +} diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java new file mode 100644 index 0000000000..ecd428f424 --- /dev/null +++ b/src/main/java/duke/Duke.java @@ -0,0 +1,169 @@ +package duke; + +import javafx.animation.PauseTransition; +import javafx.application.Application; +import javafx.application.Platform; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.TextField; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.Region; +import javafx.scene.layout.VBox; +import javafx.stage.Stage; +import javafx.util.Duration; + +/** + * Represents the main class of the program in order to start the Application. + */ +public class Duke extends Application { + + private Storage storage = new Storage(); + private TaskList taskList = new TaskList(storage); + private Ui ui = new Ui(); + + private ScrollPane scrollPane; + private VBox dialogContainer; + private TextField userInput; + private Button sendButton; + private Scene scene; + + private Image user = new Image(this.getClass().getResourceAsStream("/images/DaUser.png")); + private Image duke = new Image(this.getClass().getResourceAsStream("/images/DaDuke.png")); + + @Override + public void start(Stage stage) { + storage.load(); + + //Taken from JavaFX Tutorial @SE-EDU/guides + //Step 1. Setting up required components + //The container for the content of the chat to scroll. + scrollPane = new ScrollPane(); + dialogContainer = new VBox(); + scrollPane.setContent(dialogContainer); + + userInput = new TextField(); + sendButton = new Button("Send"); + + AnchorPane mainLayout = new AnchorPane(); + mainLayout.getChildren().addAll(scrollPane, userInput, sendButton); + + scene = new Scene(mainLayout); + + stage.setScene(scene); + stage.show(); + + //Step 2. Formatting the window to look as expected + stage.setTitle("Duke"); + stage.setResizable(false); + stage.setMinHeight(600.0); + stage.setMinWidth(400.0); + + mainLayout.setPrefSize(400.0, 600.0); + + scrollPane.setPrefSize(385, 535); + scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.ALWAYS); + + scrollPane.setVvalue(1.0); + scrollPane.setFitToWidth(true); + + // You will need to import `javafx.scene.layout.Region` for this. + dialogContainer.setPrefHeight(Region.USE_COMPUTED_SIZE); + + userInput.setPrefWidth(325.0); + + sendButton.setPrefWidth(55.0); + + AnchorPane.setTopAnchor(scrollPane, 1.0); + + AnchorPane.setBottomAnchor(sendButton, 1.0); + AnchorPane.setRightAnchor(sendButton, 1.0); + + AnchorPane.setLeftAnchor(userInput , 1.0); + AnchorPane.setBottomAnchor(userInput, 1.0); + + //Adding Welcome message + startMessage(); + + //Step 3. Add functionality to handle user input. + sendButton.setOnMouseClicked((event) -> { + dialogContainer.getChildren().add(getDialogLabel(userInput.getText())); + userInput.clear(); + }); + + userInput.setOnAction((event) -> { + dialogContainer.getChildren().add(getDialogLabel(userInput.getText())); + userInput.clear(); + }); + + //Scroll down to the end every time dialogContainer's height changes. + dialogContainer.heightProperty().addListener((observable) -> scrollPane.setVvalue(1.0)); + + //Part 3. Add functionality to handle user input. + sendButton.setOnMouseClicked((event) -> { + handleUserInput(); + }); + + userInput.setOnAction((event) -> { + handleUserInput(); + }); + + } + + /** + * Iteration 1: + * Creates a label with the specified text and adds it to the dialog container. + * @param text String containing text to add + * @return a label with the specified text that has word wrap enabled. + */ + private Label getDialogLabel(String text) { + // You will need to import `javafx.scene.control.Label`. + Label textToAdd = new Label(text); + textToAdd.setWrapText(true); + + return textToAdd; + } + + /** + * Iteration 2: + * 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. + */ + private void handleUserInput() { + String input = getResponse(userInput.getText()); + Label dukeText = new Label(input); + Label userText = new Label(userInput.getText()); + dialogContainer.getChildren().addAll( + DialogBox.getUserDialog(userText, new ImageView(user)), + DialogBox.getDukeDialog(dukeText, new ImageView(duke)) + ); + userInput.clear(); + //Reused from https://stackoverflow.com/questions/27334455/ + // how-to-close-a-stage-after-a-certain-amount-of-time-javafx + //with minor modifications + //@authors: James_D + if (input.equals(ui.showGoodbyeMessage())) { + storage.writeFile(); + PauseTransition delay = new PauseTransition(Duration.seconds(5)); + delay.setOnFinished( event -> Platform.exit()); + delay.play(); + } + } + private void startMessage() { + Label dukeText = new Label(ui.showWelcomeMessage()); + dialogContainer.getChildren().add(DialogBox.getDukeDialog(dukeText, new ImageView(duke))); + } + + private String getResponse(String input) { + assert input != null : "input cannot be null!"; + Parser parser = new Parser(taskList); + String result = parser.execute(input); + return result; + } + + +} diff --git a/src/main/java/duke/Event.java b/src/main/java/duke/Event.java new file mode 100644 index 0000000000..8374e33f45 --- /dev/null +++ b/src/main/java/duke/Event.java @@ -0,0 +1,27 @@ +package duke; + +class Event extends Task { + + protected String at; + + public Event(String description, String at) { + super(description); + this.at = at; + } + + @Override + public String toString() { + return "[E]" + super.toString() + "(at: " + at + ")"; + } + + @Override + public String getInitial() { + return "[E]"; + } + + @Override + public String getTime() { + String timeFormat = "hh:mm AM"; + return at.substring(at.length() - timeFormat.length()); + } +} diff --git a/src/main/java/duke/FileClass.java b/src/main/java/duke/FileClass.java new file mode 100644 index 0000000000..a833d401e5 --- /dev/null +++ b/src/main/java/duke/FileClass.java @@ -0,0 +1,73 @@ +package duke; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * Represents a class which contains methods with regard to + * creating a file, writing an output to a specific file and + * creating a directory. + */ +class FileClass { + + /** + * Creates a file in the specific path. + * If the file does not exist in the path, + * a file at the specific file will be created instead. + * + * @param filePath Location of the file. + * @throws IOException If the directory is invalid. + */ + public void createFile(String filePath) { + File f = new File(filePath); + if (!f.exists()) { + try { + f.createNewFile(); + } catch (IOException e) { + System.out.println("Path Directory is invalid!"); + } + } + } + + /** + * Writes output in a file in the specific path. + * If the file does not exist in the path, + * IOException will be thrown instead. + * + * @param filePath Location of the file. + * @param textToAdd Texts that will be written in the file. + * @throws IOException if the directory is invalid. + */ + //taken from W3.3c File Access + public void writeFile(String filePath, String textToAdd) throws IOException { + FileWriter fw = new FileWriter(filePath, true); + fw.write(textToAdd + "\r\n"); + fw.close(); + } + + /** + * Creates a directory in the specific path. + * If the path does not exist, + * it will be created instead. + * + * @param filePath Location of the file. + * @throws IOException If the path directory is invalid. + */ + public void createDirectory(String filePath) { + File f = new File(filePath); + Path path = Paths.get(filePath); + if (!f.exists()) { + try { + Files.createDirectory(path); + } catch (IOException e) { + System.out.println("Path Directory cannot be created!"); + } + } + + + } +} diff --git a/src/main/java/duke/Launcher.java b/src/main/java/duke/Launcher.java new file mode 100644 index 0000000000..d152a69453 --- /dev/null +++ b/src/main/java/duke/Launcher.java @@ -0,0 +1,12 @@ +package duke; + +import javafx.application.Application; + +/** + * A launcher class to work around classpath issues. + */ +public class Launcher { + public static void main(String[] args) { + Application.launch(Duke.class, args); + } +} diff --git a/src/main/java/duke/Parser.java b/src/main/java/duke/Parser.java new file mode 100644 index 0000000000..8c12a43e4d --- /dev/null +++ b/src/main/java/duke/Parser.java @@ -0,0 +1,196 @@ +package duke; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * Represents a class which is responsile to make sense + * of the user input. + */ +class Parser { + private TaskList taskList; + private Ui ui; + + Parser(TaskList taskList) { + this.taskList = taskList; + this.ui = new Ui(); + } + + /** + * Executes and makes sense of the user command. + * + * @param input Input given by the user. + * @return String output which will be shown in the Duke chat. + */ + public String execute(String input) { + String[] checkCase = input.split(" "); + switch (checkCase[0].toLowerCase()) { + case ("list"): + return taskList.showTask(); + + case ("mark"): + try { + int index = Integer.parseInt(checkCase[1]) - 1; + Task tasks = taskList.getTaskArray().get(index); + String output = tasks.mark(); + taskList.getTaskArray().set(index, tasks); + return output; + } catch (ArrayIndexOutOfBoundsException e) { + return ui.showInvalidInput(); + } catch (IndexOutOfBoundsException e) { + return ui.showInvalidInput(); + } + + case ("unmark"): + try { + int index = Integer.parseInt(checkCase[1]) - 1; + Task tasks = taskList.getTaskArray().get(index); + String output = tasks.unmark(); + taskList.getTaskArray().set(index, tasks); + return output; + } catch (ArrayIndexOutOfBoundsException e) { + return ui.showInvalidInput(); + } catch (IndexOutOfBoundsException e) { + return ui.showInvalidInput(); + } + + case ("todo"): + + try { + String stringSliced = parseString(input); + Todo todoTask = new Todo(stringSliced); + taskList.addTask(todoTask); + String noOfTask = String.valueOf(taskList.getTaskArray().size()); + return ui.showAddedMessage(todoTask, noOfTask); + } catch (StringIndexOutOfBoundsException e) { + return ui.showTodoError(); + } + + case ("deadline"): + + try { + String parsedTime = parseByCondition(input); + String convertedTime = convertTime(parsedTime); + String stringSliced = parseString(input); + Deadline deadlineTask = new Deadline(stringSliced, convertedTime); + taskList.addTask(deadlineTask); + String noOfTask = String.valueOf(taskList.getTaskArray().size()); + return ui.showAddedMessage(deadlineTask, noOfTask); + } catch (StringIndexOutOfBoundsException e) { + return ui.showDeadlineError(); + } + + case ("event"): + + try { + String parsedTime = parseByCondition(input); + String convertedTime = convertTime(parsedTime); + String stringSliced = parseString(input); + Event eventTask = new Event(stringSliced, convertedTime); + taskList.addTask(eventTask); + String noOfTask = String.valueOf(taskList.getTaskArray().size()); + return ui.showAddedMessage(eventTask, noOfTask); + + } catch (StringIndexOutOfBoundsException e) { + return ui.showEventError(); + } + + case("delete"): + + try { + int index = Integer.parseInt(checkCase[1]) - 1; + Task task = taskList.getTaskArray().get(index); + taskList.deleteTask(index); + String noOfTask = String.valueOf(taskList.getTaskArray().size()); + return ui.showDeletedMessage(task, noOfTask); + } catch (ArrayIndexOutOfBoundsException e) { + return ui.showDeleteError(); + } + + case("find"): + String stringSliced = parseString(input); + return ui.showFindMessage(taskList.findTask(stringSliced)); + + case("view"): + String parsedDate = parseString(input); + String convertedDate = convertDate(parsedDate); + return ui.showScheduleMessage(taskList, convertedDate); + + case("bye"): + return ui.showGoodbyeMessage(); + + default: + return ui.showDefaultMessage(); + } + } + + /** + * Parses the input by the respective conditions - 'by' for deadline and 'at' for event. + * + * @param input Input given by the user. + * @return String output of the parsed input. + */ + public String parseByCondition(String input) { + String deadlineCondition = "/by "; + int indexBy = input.indexOf(deadlineCondition); + String eventCondition = "/at "; + int indexAt = input.indexOf(eventCondition); + String output; + if (input.contains(deadlineCondition)) { + output = input.substring(indexBy + deadlineCondition.length()); + } else { + output = input.substring(indexAt + eventCondition.length()); + } + return output; + } + /** + * Converts the time input into correct format. + * + * @param dateTime Input given by the user. + * @return String result of the converted date and time in the right format. + */ + public String convertTime(String dateTime) { + LocalDateTime convertedTime = LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern("d/M/y Hmm")); + String result = convertedTime.format(DateTimeFormatter.ofPattern("MMM d yyyy hh:mm a")); + return result; + } + + /** + * Parses the input by the respective tasks. + * + * @param input Input given by the user. + * @return String output of the parsed input. + */ + public String parseString(String input) { + String deadline = "deadline "; + String event = "event "; + String todo = "todo "; + String find = "find "; + String view = "view "; + String deadlineCondition = "/by"; + String eventCondition = "/at "; + String output; + if (input.contains(todo)) { + output = input.substring(todo.length()); + } else if (input.contains(event)) { + output = input.substring(event.length(), input.indexOf(eventCondition)); + } else if (input.contains(deadline)) { + output = input.substring(deadline.length(), input.indexOf(deadlineCondition)); + } else if (input.contains(find)) { + output = input.substring(find.length()); + } else { + output = input.substring(view.length()); + } + return output; + } + public String convertDate(String date) { + LocalDate convertedDate = LocalDate.parse(date, DateTimeFormatter.ofPattern("d/M/y")); + String result = convertedDate.format(DateTimeFormatter.ofPattern("MMM d yyyy")); + return result; + } + + + + +} diff --git a/src/main/java/duke/Storage.java b/src/main/java/duke/Storage.java new file mode 100644 index 0000000000..ca02c7ea8a --- /dev/null +++ b/src/main/java/duke/Storage.java @@ -0,0 +1,63 @@ +package duke; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; + +/** + * Represents the storage class which is responsible + * to store different tasks into a specific file or + * to read different tasks from a specific file. + */ +class Storage { + private static String HOME = System.getProperty("user.home"); + private ArrayList taskArray; + Storage() { + taskArray = new ArrayList(); + } + + /** + * Loads the different tasks from a specific file. + * If the file does not exist at the given path, + * a new file will then be created. + * @return the loaded file. + */ + public File load() { + FileClass fc = new FileClass(); //file class + String homePath = HOME + "/data"; + fc.createDirectory(homePath); //create directory first + fc.createFile(homePath); //create a file in the /home/data/tasks.txt + File file = new File(homePath); + return file; + } + + /** + * Writes the output to a specific file. + * If the file does not exist at the given path, + * a new file will then be created. + */ + public void writeFile() { + FileClass fc = new FileClass(); + String filePath = HOME + "/data/stored.txt"; + fc.createFile(filePath); + for (int i = 0; i < taskArray.size(); i++) { + Task tasks = taskArray.get(i); + try { + String firstInitial = tasks.getInitial(); //first initial character + String textToAdd = firstInitial + " | " + tasks.getStatusIcon() + " | " + + taskArray.get(i).getDescription(); + fc.writeFile(filePath, textToAdd); + } catch (IOException e) { + System.out.println("File is not found :(!"); + } + + } + } + /** + * Returns an ArrayList which contains different tasks. + * @return an ArrayList + */ + public ArrayList getList() { + return this.taskArray; + } +} diff --git a/src/main/java/duke/Task.java b/src/main/java/duke/Task.java new file mode 100644 index 0000000000..d60458737a --- /dev/null +++ b/src/main/java/duke/Task.java @@ -0,0 +1,99 @@ +package duke; + +import java.util.ArrayList; + +/** + * Represents the Task class which contains + * the description of a specific task and its + * status. + */ +class Task { + protected String description; + protected String time; + protected ArrayList isDone; + + public Task(String description) { + this.description = description; + this.isDone = new ArrayList(); + isDone.add(false); + } + + public Task(String description, String time) { + this.description = description; + this.time = time; + this.isDone = new ArrayList(); + isDone.add(false); + } + + /** + * Returns the status of a specific task. + * returns String which symbolises whether it has been marked. + */ + public String getStatusIcon() { + return (isDone.get(0) ? "[X]" : "[ ]"); // mark done task with X // if done is "X" then " " + } + + /** + * Sets a specific task to be marked. + */ + public void setAsMarked() { + isDone.set(0, true); + } + + /** + * Sets a specific task to be unmarked. + */ + public void setAsUnmarked() { + isDone.set(0, false); + } + + /** + * Returns a String which indicates that the task has been marked. + * @return String which indicates that the task has been marked. + */ + public String mark() { + setAsMarked(); + String messageMarked = "Nice! I've marked this task as done: \n" + + this.toString() + "\n "; + return messageMarked; + } + + /** + * Returns a String which indicates that the task has been unmarked. + * @return String which indicates that the task has been unmarked. + */ + public String unmark() { + setAsUnmarked(); + String messageUnmarked = "OK, I've marked this task as not done yet: \n" + + this.toString() + "\n "; + return messageUnmarked; + } + + /** + * Returns a String of given Task. + * @return String of the task. + */ + public String toString() { + return getStatusIcon() + " " + this.description; + } + + /** + * Returns the initial of the task. + * @return initial of the task. + */ + public String getInitial() { + return "Task"; + } + + /** + * Returns the description a specific task. + * @return description of the task. + */ + public String getDescription() { + return description; + } + + public String getTime() { + return this.time; + } +} diff --git a/src/main/java/duke/TaskList.java b/src/main/java/duke/TaskList.java new file mode 100644 index 0000000000..fb5c7f3014 --- /dev/null +++ b/src/main/java/duke/TaskList.java @@ -0,0 +1,65 @@ +package duke; + +import java.util.ArrayList; + +/** + * Represents a class which is responsible to handle + * operations such as adding or deleting tasks. + */ +class TaskList { + private Storage storage; + private Ui Ui; + + TaskList(Storage storage) { + this.storage = storage; + this.Ui = new Ui(); + } + + /** + * Adds a task into the current storage. + * @param task Specific task to be added. + */ + public void addTask(Task task) { + storage.getList().add(task); + } + + /** + * Deletes a task from the current storage. + * @param index Index of a specific task to be deleted. + */ + public void deleteTask(int index) { + this.getTaskArray().remove(index); + } + + /** + * Returns an ArrayList which is used to store tasks which contains + * the specific keyword. + * @param keyword Keyword used to find matching tasks in the list. + * @return all String in the Tasklist which contains the matching keywords. + */ + public ArrayList findTask(String keyword) { + ArrayList containsInput = new ArrayList(); + for (Task task: this.getTaskArray()) { + if (task.toString().contains(keyword)) { + containsInput.add(task); + } + } + return containsInput; + } + + /** + * Shows a list of tasks from the current storage. + * @return String which contains all the tasks in the current storage. + */ + public String showTask() { + return Ui.showListMessage(this); + } + + /** + * Returns an ArrayList which contains different tasks. + * @return an arrayList which contains tasks. + */ + public ArrayList getTaskArray() { + return storage.getList(); + } +} diff --git a/src/main/java/duke/TimeComparator.java b/src/main/java/duke/TimeComparator.java new file mode 100644 index 0000000000..b19e2c2e2e --- /dev/null +++ b/src/main/java/duke/TimeComparator.java @@ -0,0 +1,22 @@ +package duke; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Comparator; + +class TimeComparator implements Comparator { + + //Reused from StackOverFlow https://stackoverflow.com/questions/35671959/sort-arraylist-with-times-in-java/35672291 + //@author ΦXocę 웃 Пepeúpa ツ + //with minor modifications + @Override + public int compare(Task taskTime1, Task taskTime2) { + try { + String time1 = taskTime1.getTime(); + String time2 = taskTime2.getTime(); + return new SimpleDateFormat("hh:mm a").parse(time1).compareTo(new SimpleDateFormat("hh:mm a").parse(time2)); + } catch (ParseException e) { + return 0; + } + } +} diff --git a/src/main/java/duke/Todo.java b/src/main/java/duke/Todo.java new file mode 100644 index 0000000000..aad7053b5d --- /dev/null +++ b/src/main/java/duke/Todo.java @@ -0,0 +1,17 @@ +package duke; + +class Todo extends Task { + public Todo(String description) { + super(description); + } + + @Override + public String toString() { + return "[T]" + super.toString(); + } + + @Override + public String getInitial() { + return "[T]"; + } +} diff --git a/src/main/java/duke/Ui.java b/src/main/java/duke/Ui.java new file mode 100644 index 0000000000..02e3a8d707 --- /dev/null +++ b/src/main/java/duke/Ui.java @@ -0,0 +1,112 @@ +package duke; + +import java.util.ArrayList; +import java.util.Collections; + +class Ui { + Ui() { + } + public String showGoodbyeMessage() { + String endMessage = "Bye. Hope to see you again soon!"; + return endMessage; + } + + public String showWelcomeMessage() { + String startMessage = "Hello! I'm Duke\n" + + "What can I do for you?"; + return startMessage; + } + + public String showListMessage(TaskList tasklist) { + if (tasklist.getTaskArray().isEmpty()) { + String listMessage = "The list is empty"; + return listMessage; + } else { + String listMessage = "Here are the tasks in your list: \n"; + for (int i = 0; i < tasklist.getTaskArray().size(); i++) { + String index = String.valueOf(i + 1); + listMessage = listMessage + index + "." + + tasklist.getTaskArray().get(i) + "\n"; + } + return listMessage; + } + } + + public String showFindMessage(ArrayList taskArray) { + String listMessage; + if (taskArray.isEmpty()) { + listMessage = "There are no matching tasks in your list."; + } else { + listMessage = "Here are the matching tasks in your list: \n"; + for (int i = 0; i < taskArray.size(); i++) { + String index = String.valueOf(i + 1); + listMessage = listMessage + index + "." + taskArray.get(i) + "\n"; + } + } + return listMessage; + } + + public String showAddedMessage(Task task, String no0fTask) { + assert task != null : "Task cannot be null"; + assert no0fTask != null : "noOfTask cannot be null"; + String messageTask = "Got it. I've added this task: \n"; + String taskString = task.toString(); + String output = messageTask + taskString + "\n" + + "Now you have " + no0fTask + " tasks in the list."; + return output; + } + + public String showDeletedMessage(Task task, String noOfTask) { + assert task != null : "Task cannot be null"; + assert noOfTask != null : "noOfTask cannot be null"; + String messageTask = "Noted. I've removed this task: \n"; + String taskString = task.toString(); + String output = messageTask + taskString + + "\n" + "Now you have " + noOfTask + + " tasks in the list."; + return output; + } + + public String showScheduleMessage(TaskList taskList, String dateTime) { + ArrayList tasks = taskList.findTask(dateTime); + Collections.sort(tasks, new TimeComparator()); + String listMessage; + if (tasks.isEmpty()) { + listMessage = "There are no tasks on the day " + dateTime + "."; + } else { + listMessage = "Your task for the day, " + dateTime + ": \n"; + for (int i = 0; i < tasks.size(); i++) { + String index = String.valueOf(i + 1); + listMessage = listMessage + index + "." + + tasks.get(i) + "\n"; + } + } + return listMessage; + } + + public String showDeleteError() { + return "There are no tasks to be deleted!"; + } + + public String showInvalidInput() { + return "The input is not valid :("; + } + + public String showTodoError() { + return "☹ OOPS!!! The description of a todo cannot be empty."; + } + + public String showDeadlineError() { + return "☹ OOPS!!! The description of a deadline cannot be empty."; + } + + public String showEventError() { + return "☹ OOPS!!! The description of a event cannot be empty."; + } + + public String showDefaultMessage() { + return "☹ OOPS!!! I'm sorry, but I don't know what that means :-("; + } + + +} diff --git a/src/main/resources/images/DaDuke.png b/src/main/resources/images/DaDuke.png new file mode 100644 index 0000000000..259faa7814 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..81257972ac Binary files /dev/null and b/src/main/resources/images/DaUser.png differ diff --git a/src/out/production/main/duke/Deadline.class b/src/out/production/main/duke/Deadline.class new file mode 100644 index 0000000000..6472df5ee4 Binary files /dev/null and b/src/out/production/main/duke/Deadline.class differ diff --git a/src/out/production/main/duke/Duke.class b/src/out/production/main/duke/Duke.class new file mode 100644 index 0000000000..8d71b3cc28 Binary files /dev/null and b/src/out/production/main/duke/Duke.class differ diff --git a/src/out/production/main/duke/DukeException.class b/src/out/production/main/duke/DukeException.class new file mode 100644 index 0000000000..81b27dd640 Binary files /dev/null and b/src/out/production/main/duke/DukeException.class differ diff --git a/src/out/production/main/duke/Event.class b/src/out/production/main/duke/Event.class new file mode 100644 index 0000000000..98c1a00bd6 Binary files /dev/null and b/src/out/production/main/duke/Event.class differ diff --git a/src/out/production/main/duke/FileClass.class b/src/out/production/main/duke/FileClass.class new file mode 100644 index 0000000000..a3aa074265 Binary files /dev/null and b/src/out/production/main/duke/FileClass.class differ diff --git a/src/out/production/main/duke/Parser.class b/src/out/production/main/duke/Parser.class new file mode 100644 index 0000000000..e38cf7f2b1 Binary files /dev/null and b/src/out/production/main/duke/Parser.class differ diff --git a/src/out/production/main/duke/Storage.class b/src/out/production/main/duke/Storage.class new file mode 100644 index 0000000000..b8d8c5a582 Binary files /dev/null and b/src/out/production/main/duke/Storage.class differ diff --git a/src/out/production/main/duke/Task.class b/src/out/production/main/duke/Task.class new file mode 100644 index 0000000000..6bf46e3c81 Binary files /dev/null and b/src/out/production/main/duke/Task.class differ diff --git a/src/out/production/main/duke/TaskList.class b/src/out/production/main/duke/TaskList.class new file mode 100644 index 0000000000..289877586b Binary files /dev/null and b/src/out/production/main/duke/TaskList.class differ diff --git a/src/out/production/main/duke/Todo.class b/src/out/production/main/duke/Todo.class new file mode 100644 index 0000000000..c187b34710 Binary files /dev/null and b/src/out/production/main/duke/Todo.class differ diff --git a/src/out/production/main/duke/Ui.class b/src/out/production/main/duke/Ui.class new file mode 100644 index 0000000000..6201f23e1c Binary files /dev/null and b/src/out/production/main/duke/Ui.class differ diff --git a/src/out/test/test/duke/DeadlineTest.class b/src/out/test/test/duke/DeadlineTest.class new file mode 100644 index 0000000000..529abe1288 Binary files /dev/null and b/src/out/test/test/duke/DeadlineTest.class differ diff --git a/src/out/test/test/duke/TodoTest.class b/src/out/test/test/duke/TodoTest.class new file mode 100644 index 0000000000..2322b4e8dd Binary files /dev/null and b/src/out/test/test/duke/TodoTest.class differ diff --git a/src/test/java/duke/DeadlineTest.java b/src/test/java/duke/DeadlineTest.java new file mode 100644 index 0000000000..34add16b2f --- /dev/null +++ b/src/test/java/duke/DeadlineTest.java @@ -0,0 +1,17 @@ +package duke; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + + +class DeadlineTest { + + @Test + public void DeadlineTest() { + String test1 = "help Kris do cs2103"; + String answer1 = "[D][ ] help Kris do cs2103 (by: Mar 2 2001 06:00 PM)"; + assertEquals(answer1, new Deadline(test1, "Mar 2 2001 06:00 PM").toString()); + } + +} \ No newline at end of file diff --git a/src/test/java/duke/TodoTest.java b/src/test/java/duke/TodoTest.java new file mode 100644 index 0000000000..e98922eac3 --- /dev/null +++ b/src/test/java/duke/TodoTest.java @@ -0,0 +1,19 @@ +package duke; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + + +class TodoTest { + + @Test + public void testTodo() { + String test1 = "[T][ ] buy bread"; + String test2 = "[T][ ] help Kris do cs2103"; + assertEquals(test1, new Todo("buy bread").toString()); + assertEquals(test2, new Todo("help Kris do cs2103").toString()); + } + + +} \ No newline at end of file diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT deleted file mode 100644 index 657e74f6e7..0000000000 --- a/text-ui-test/EXPECTED.TXT +++ /dev/null @@ -1,7 +0,0 @@ -Hello from - ____ _ -| _ \ _ _| | _____ -| | | | | | | |/ / _ \ -| |_| | |_| | < __/ -|____/ \__,_|_|\_\___| - diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat deleted file mode 100644 index 0873744649..0000000000 --- a/text-ui-test/runtest.bat +++ /dev/null @@ -1,21 +0,0 @@ -@ECHO OFF - -REM create bin directory if it doesn't exist -if not exist ..\bin mkdir ..\bin - -REM delete output from previous run -if exist ACTUAL.TXT del ACTUAL.TXT - -REM compile the code into the bin folder -javac -cp ..\src\main\java -Xlint:none -d ..\bin ..\src\main\java\*.java -IF ERRORLEVEL 1 ( - echo ********** BUILD FAILURE ********** - exit /b 1 -) -REM no error here, errorlevel == 0 - -REM run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT -java -classpath ..\bin Duke < input.txt > ACTUAL.TXT - -REM compare the output to the expected output -FC ACTUAL.TXT EXPECTED.TXT diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh deleted file mode 100644 index c9ec870033..0000000000 --- a/text-ui-test/runtest.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env bash - -# create bin directory if it doesn't exist -if [ ! -d "../bin" ] -then - mkdir ../bin -fi - -# delete output from previous run -if [ -e "./ACTUAL.TXT" ] -then - rm ACTUAL.TXT -fi - -# compile the code into the bin folder, terminates if error occurred -if ! javac -cp ../src/main/java -Xlint:none -d ../bin ../src/main/java/*.java -then - echo "********** BUILD FAILURE **********" - exit 1 -fi - -# run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT -java -classpath ../bin Duke < input.txt > ACTUAL.TXT - -# convert to UNIX format -cp EXPECTED.TXT EXPECTED-UNIX.TXT -dos2unix ACTUAL.TXT EXPECTED-UNIX.TXT - -# compare the output to the expected output -diff ACTUAL.TXT EXPECTED-UNIX.TXT -if [ $? -eq 0 ] -then - echo "Test result: PASSED" - exit 0 -else - echo "Test result: FAILED" - exit 1 -fi \ No newline at end of file