diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000000..fe39b1c73f
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,53 @@
+plugins {
+ id 'java'
+ id 'application'
+ id 'checkstyle'
+ id 'com.github.johnrengelman.shadow' version '5.1.0'
+}
+
+repositories {
+ mavenCentral()
+ jcenter()
+ google()
+ maven {
+ url "https://maven.springframework.org/release"
+ }
+ maven {
+ url "https://maven.restlet.com"
+ }
+}
+
+dependencies {
+ testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0'
+ testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
+ 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'
+}
+
+application {
+ mainClassName = "duke.Launcher"
+}
+
+test {
+ useJUnitPlatform()
+}
+
+checkstyle {
+ toolVersion = '8.29'
+}
+
+run {
+ enableAssertions = true
+}
+
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
new file mode 100644
index 0000000000..370eda80cf
--- /dev/null
+++ b/config/checkstyle/checkstyle.xml
@@ -0,0 +1,403 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml
new file mode 100644
index 0000000000..39efb6e4ac
--- /dev/null
+++ b/config/checkstyle/suppressions.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
diff --git a/data/duke.txt b/data/duke.txt
new file mode 100644
index 0000000000..0e2829a572
--- /dev/null
+++ b/data/duke.txt
@@ -0,0 +1,3 @@
+[T] [] read book
+[D] [] return book (by: 20 Feb 2021, 5:00pm)
+[E] [] team meeting (at: 21 Feb 2021, 8:00pm-11:00pm)
diff --git a/docs/README.md b/docs/README.md
index fd44069597..18d11890c2 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,20 +1,215 @@
-# User Guide
+# Duke User Guide
-## Features
+
-### Feature 1
-Description of feature.
+## Features
+
+- `List` down all the tasks from the list.
+
+- Add `todo`, `deadline` and `event` tasks to the list.
+
+- Mark any task in the list as `done`.
+
+- `Find` all tasks in the list whose description contains the keyword.
+
+- `Delete` any task in the list.
+
+- `Delete all` tasks in the list.
+
+
+
+## A Screenshot of Duke in Action!
+
+
+
+
## Usage
-### `Keyword` - Describe action
+### `List`
+
+#### What it does:
+
+List down all the tasks from the list.
+
+#### Usage example:
+
+`list`
+
+#### Expected outcome:
+
+```
+Here are the tasks in your list:
+1. [T] [] read book
+2. [D] [] return book (by: 28 Feb 2021, 5:00pm)
+3. [E] [] formal dinner (at: 2 Apr 2021, 6:00pm-9:00pm)
+```
+
+
+
+### `Todo`
+
+#### What it does:
+
+Add a todo task to the list.
+
+#### Usage format:
+
+todo *discription of task*
+
+#### Usage example:
+
+`todo do homework`
+
+#### Expected outcome:
+
+```
+Got it. I've added this task:
+[T] [] do homework
+Now you have 4 tasks in the list.
+```
+
+
+
+### `Deadline`
+
+#### What it does:
+
+Add a deadline task to the list.
+
+#### Usage format:
+
+deadline *discription of task* /by *DD/MM/YYYY HHMM*
+
+#### Usage example:
+
+`deadline submit homework /by 05/04/2021 1800`
+
+#### Expected outcome:
+
+```
+Got it. I've added this task:
+[D] [] submit homework (by: 5 Apr 2021, 6:00pm)
+Now you have 5 tasks in the list.
+```
+
+
+
+### `Event`
+
+#### What it does:
+
+Add an event task to the list.
+
+#### Usage format:
+
+event *discription of task* /at *DD/MM/YYYY HHMM-HHMM*
+
+#### Usage example:
+
+`event team meeting /at 06/04/2021 2000-2200`
+
+#### Expected outcome:
+
+```
+Got it. I've added this task:
+[E] [] team meeting (by: 6 Apr 2021, 8:00pm-10:00pm)
+Now you have 6 tasks in the list.
+```
+
+
+
+### `Done`
+
+#### What it does:
+
+Mark a task as done.
+
+#### Usage format:
+
+done *line number*
+
+#### Usage example:
+
+`done 1`
+
+#### Expected outcome:
+
+```
+Nice! I've marked this task as done:
+[T] [/] read book
+```
+
+
+
+### `Find`
+
+#### What it does:
+
+Find all tasks with descriptions containing the keyword.
+
+#### Usage format:
+
+find *keyword*
+
+#### Usage example:
+
+`find book`
+
+#### Expected outcome:
+
+```
+Here are the matching tasks in your list:
+1. [T] [/] read book
+2. [D] [] return book (by: 28 Feb 2021, 5:00pm)
+```
+
+
+
+### `Delete`
+
+#### What it does:
+
+Delete a task **or** all tasks.
+
+#### Usage format (delete a task):
+
+delete *line number*
+
+#### Usage example: (delete a task):
+
+`delete 1`
+
+#### Expected outcome (delete a task):
+
+```
+Noted. I've removed this task:
+[T] [/] read book
+Now you have 5 tasks in the list.
+```
+
+#### Usage example: (delete all tasks):
+
+`delete all`
+
+#### Expected outcome (delete all tasks):
+
+```
+Noted. I've removed all the tasks from the list.
+```
+
+
+
+### `Bye`
+
+#### What it does:
-Describe action and its outcome.
+Exit the Duke application.
-Example of usage:
+#### Usage example:
-`keyword (optional arguments)`
+`bye`
-Expected outcome:
+#### Expected outcome:
-`outcome`
+The Duke application closes.
diff --git a/docs/Ui.png b/docs/Ui.png
new file mode 100644
index 0000000000..f93b01aef8
Binary files /dev/null and b/docs/Ui.png differ
diff --git a/docs/_config.yml b/docs/_config.yml
new file mode 100644
index 0000000000..c4192631f2
--- /dev/null
+++ b/docs/_config.yml
@@ -0,0 +1 @@
+theme: jekyll-theme-cayman
\ No newline at end of file
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000..e708b1c023
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..1c4bcc29e1
--- /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.8.1-all.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100644
index 0000000000..4f906e0c81
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,185 @@
+#!/usr/bin/env sh
+
+#
+# Copyright 2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000000..107acd32c4
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,89 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/lib/apiguardian-api-1.0.0-javadoc.jar b/lib/apiguardian-api-1.0.0-javadoc.jar
new file mode 100644
index 0000000000..42d7d6aa64
Binary files /dev/null and b/lib/apiguardian-api-1.0.0-javadoc.jar differ
diff --git a/lib/apiguardian-api-1.0.0-sources.jar b/lib/apiguardian-api-1.0.0-sources.jar
new file mode 100644
index 0000000000..297363ec8a
Binary files /dev/null and b/lib/apiguardian-api-1.0.0-sources.jar differ
diff --git a/lib/apiguardian-api-1.0.0.jar b/lib/apiguardian-api-1.0.0.jar
new file mode 100644
index 0000000000..6cbff70f22
Binary files /dev/null and b/lib/apiguardian-api-1.0.0.jar differ
diff --git a/lib/junit-jupiter-5.4.2-javadoc.jar b/lib/junit-jupiter-5.4.2-javadoc.jar
new file mode 100644
index 0000000000..f31885d910
Binary files /dev/null and b/lib/junit-jupiter-5.4.2-javadoc.jar differ
diff --git a/lib/junit-jupiter-5.4.2-sources.jar b/lib/junit-jupiter-5.4.2-sources.jar
new file mode 100644
index 0000000000..f31885d910
Binary files /dev/null and b/lib/junit-jupiter-5.4.2-sources.jar differ
diff --git a/lib/junit-jupiter-5.4.2.jar b/lib/junit-jupiter-5.4.2.jar
new file mode 100644
index 0000000000..b3bf697621
Binary files /dev/null and b/lib/junit-jupiter-5.4.2.jar differ
diff --git a/lib/junit-jupiter-api-5.4.2-javadoc.jar b/lib/junit-jupiter-api-5.4.2-javadoc.jar
new file mode 100644
index 0000000000..ebb65fd422
Binary files /dev/null and b/lib/junit-jupiter-api-5.4.2-javadoc.jar differ
diff --git a/lib/junit-jupiter-api-5.4.2-sources.jar b/lib/junit-jupiter-api-5.4.2-sources.jar
new file mode 100644
index 0000000000..3cb82c7622
Binary files /dev/null and b/lib/junit-jupiter-api-5.4.2-sources.jar differ
diff --git a/lib/junit-jupiter-api-5.4.2.jar b/lib/junit-jupiter-api-5.4.2.jar
new file mode 100644
index 0000000000..40828b7a90
Binary files /dev/null and b/lib/junit-jupiter-api-5.4.2.jar differ
diff --git a/lib/junit-jupiter-engine-5.4.2-javadoc.jar b/lib/junit-jupiter-engine-5.4.2-javadoc.jar
new file mode 100644
index 0000000000..14955d409c
Binary files /dev/null and b/lib/junit-jupiter-engine-5.4.2-javadoc.jar differ
diff --git a/lib/junit-jupiter-engine-5.4.2-sources.jar b/lib/junit-jupiter-engine-5.4.2-sources.jar
new file mode 100644
index 0000000000..699c3fc176
Binary files /dev/null and b/lib/junit-jupiter-engine-5.4.2-sources.jar differ
diff --git a/lib/junit-jupiter-engine-5.4.2.jar b/lib/junit-jupiter-engine-5.4.2.jar
new file mode 100644
index 0000000000..3444a9806a
Binary files /dev/null and b/lib/junit-jupiter-engine-5.4.2.jar differ
diff --git a/lib/junit-jupiter-params-5.4.2-javadoc.jar b/lib/junit-jupiter-params-5.4.2-javadoc.jar
new file mode 100644
index 0000000000..0cfed785e4
Binary files /dev/null and b/lib/junit-jupiter-params-5.4.2-javadoc.jar differ
diff --git a/lib/junit-jupiter-params-5.4.2-sources.jar b/lib/junit-jupiter-params-5.4.2-sources.jar
new file mode 100644
index 0000000000..c654f4083e
Binary files /dev/null and b/lib/junit-jupiter-params-5.4.2-sources.jar differ
diff --git a/lib/junit-jupiter-params-5.4.2.jar b/lib/junit-jupiter-params-5.4.2.jar
new file mode 100644
index 0000000000..ee5650412e
Binary files /dev/null and b/lib/junit-jupiter-params-5.4.2.jar differ
diff --git a/lib/junit-platform-commons-1.4.2-javadoc.jar b/lib/junit-platform-commons-1.4.2-javadoc.jar
new file mode 100644
index 0000000000..a470d7ec0e
Binary files /dev/null and b/lib/junit-platform-commons-1.4.2-javadoc.jar differ
diff --git a/lib/junit-platform-commons-1.4.2-sources.jar b/lib/junit-platform-commons-1.4.2-sources.jar
new file mode 100644
index 0000000000..37e4b89b5b
Binary files /dev/null and b/lib/junit-platform-commons-1.4.2-sources.jar differ
diff --git a/lib/junit-platform-commons-1.4.2.jar b/lib/junit-platform-commons-1.4.2.jar
new file mode 100644
index 0000000000..270552518e
Binary files /dev/null and b/lib/junit-platform-commons-1.4.2.jar differ
diff --git a/lib/junit-platform-engine-1.4.2-javadoc.jar b/lib/junit-platform-engine-1.4.2-javadoc.jar
new file mode 100644
index 0000000000..3cab8e0553
Binary files /dev/null and b/lib/junit-platform-engine-1.4.2-javadoc.jar differ
diff --git a/lib/junit-platform-engine-1.4.2-sources.jar b/lib/junit-platform-engine-1.4.2-sources.jar
new file mode 100644
index 0000000000..2f487c5105
Binary files /dev/null and b/lib/junit-platform-engine-1.4.2-sources.jar differ
diff --git a/lib/junit-platform-engine-1.4.2.jar b/lib/junit-platform-engine-1.4.2.jar
new file mode 100644
index 0000000000..2c46ae92d3
Binary files /dev/null and b/lib/junit-platform-engine-1.4.2.jar differ
diff --git a/lib/opentest4j-1.1.1-javadoc.jar b/lib/opentest4j-1.1.1-javadoc.jar
new file mode 100644
index 0000000000..dadc6af164
Binary files /dev/null and b/lib/opentest4j-1.1.1-javadoc.jar differ
diff --git a/lib/opentest4j-1.1.1-sources.jar b/lib/opentest4j-1.1.1-sources.jar
new file mode 100644
index 0000000000..7cb1de75d0
Binary files /dev/null and b/lib/opentest4j-1.1.1-sources.jar differ
diff --git a/lib/opentest4j-1.1.1.jar b/lib/opentest4j-1.1.1.jar
new file mode 100644
index 0000000000..3f355292e0
Binary files /dev/null and b/lib/opentest4j-1.1.1.jar differ
diff --git a/settings.gradle b/settings.gradle
new file mode 100644
index 0000000000..3fd3165952
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'ip'
\ No newline at end of file
diff --git a/src/main/java/Deadline.class b/src/main/java/Deadline.class
new file mode 100644
index 0000000000..f6e445eff2
Binary files /dev/null and b/src/main/java/Deadline.class differ
diff --git a/src/main/java/Duke.class b/src/main/java/Duke.class
new file mode 100644
index 0000000000..95cf6733e4
Binary files /dev/null and b/src/main/java/Duke.class differ
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/Event.class b/src/main/java/Event.class
new file mode 100644
index 0000000000..ad22e81342
Binary files /dev/null and b/src/main/java/Event.class differ
diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..9f37e4e0aa
--- /dev/null
+++ b/src/main/java/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: Duke
+
diff --git a/src/main/java/Parser.class b/src/main/java/Parser.class
new file mode 100644
index 0000000000..be8de31f2c
Binary files /dev/null and b/src/main/java/Parser.class differ
diff --git a/src/main/java/Storage.class b/src/main/java/Storage.class
new file mode 100644
index 0000000000..e35a433d15
Binary files /dev/null and b/src/main/java/Storage.class differ
diff --git a/src/main/java/Task.class b/src/main/java/Task.class
new file mode 100644
index 0000000000..45837cce6a
Binary files /dev/null and b/src/main/java/Task.class differ
diff --git a/src/main/java/TaskList.class b/src/main/java/TaskList.class
new file mode 100644
index 0000000000..d8440ea4d0
Binary files /dev/null and b/src/main/java/TaskList.class differ
diff --git a/src/main/java/Todo.class b/src/main/java/Todo.class
new file mode 100644
index 0000000000..937a49eb00
Binary files /dev/null and b/src/main/java/Todo.class differ
diff --git a/src/main/java/Ui.class b/src/main/java/Ui.class
new file mode 100644
index 0000000000..2d20bf94ed
Binary files /dev/null and b/src/main/java/Ui.class differ
diff --git a/src/main/java/duke/Deadline.java b/src/main/java/duke/Deadline.java
new file mode 100644
index 0000000000..d4708fc5df
--- /dev/null
+++ b/src/main/java/duke/Deadline.java
@@ -0,0 +1,10 @@
+package duke;
+
+/**
+ * A type of Task with a deadline.
+ */
+public class Deadline extends Task {
+ public Deadline(String description, String date, String time) {
+ super(description, date, time, "[D]", false);
+ }
+}
diff --git a/src/main/java/duke/DialogBox.java b/src/main/java/duke/DialogBox.java
new file mode 100644
index 0000000000..e66c7bad70
--- /dev/null
+++ b/src/main/java/duke/DialogBox.java
@@ -0,0 +1,42 @@
+package duke;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.geometry.Pos;
+import javafx.scene.control.Label;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.HBox;
+import javafx.scene.Node;
+
+public class DialogBox extends HBox {
+
+ public DialogBox(Label l, ImageView iv) {
+
+ l.setWrapText(true);
+ iv.setFitWidth(100.0);
+ iv.setFitHeight(100.0);
+
+ this.setAlignment(Pos.TOP_RIGHT);
+ this.getChildren().addAll(l, iv);
+ }
+
+ /**
+ * 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;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java
new file mode 100644
index 0000000000..ee115c51fb
--- /dev/null
+++ b/src/main/java/duke/Duke.java
@@ -0,0 +1,99 @@
+package duke;
+
+import javafx.application.Application;
+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.scene.Scene;
+import javafx.stage.Stage;
+
+public class Duke extends Application {
+ private final Parser parser;
+
+ private ScrollPane scrollPane;
+ private VBox dialogContainer;
+ private TextField userInput;
+ private final Image user = new Image(this.getClass().getResourceAsStream("/images/DaUser.png"));
+ private final Image duke = new Image(this.getClass().getResourceAsStream("/images/DaDuke.png"));
+
+ public Duke() {
+ Storage storage = new Storage("./data/duke.txt");
+ storage.retrieveOrCreate();
+ TaskList taskList = storage.getTaskList();
+ Ui ui = new Ui();
+ parser = new Parser(taskList, ui, storage);
+ }
+
+ @Override
+ public void start(Stage stage) {
+ scrollPane = new ScrollPane();
+ dialogContainer = new VBox();
+ scrollPane.setContent(dialogContainer);
+
+ userInput = new TextField();
+ Button sendButton = new Button("Send");
+
+ AnchorPane mainLayout = new AnchorPane();
+ mainLayout.getChildren().addAll(scrollPane, userInput, sendButton);
+
+ Scene scene = new Scene(mainLayout);
+
+ stage.setScene(scene);
+ stage.show();
+
+ 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);
+
+ 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);
+
+ sendButton.setOnMouseClicked((event) -> handleUserInput());
+
+ userInput.setOnAction((event) -> handleUserInput());
+
+ dialogContainer.heightProperty().addListener((observable) -> scrollPane.setVvalue(1.0));
+ }
+
+ private void handleUserInput() {
+ Label userText = new Label(userInput.getText());
+ Label dukeText = new Label(getResponse(userInput.getText()));
+ dialogContainer.getChildren().addAll(
+ DialogBox.getUserDialog(userText, new ImageView(user)),
+ DialogBox.getDukeDialog(dukeText, new ImageView(duke))
+ );
+ userInput.clear();
+ }
+
+ public String getResponse(String input) {
+ parser.addCommand(input);
+ return parser.process();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/duke/Event.java b/src/main/java/duke/Event.java
new file mode 100644
index 0000000000..d505c32b0f
--- /dev/null
+++ b/src/main/java/duke/Event.java
@@ -0,0 +1,24 @@
+package duke;
+
+/**
+ * A type of Task with a date and time.
+ */
+public class Event extends Task {
+ public Event(String description, String date, String time) {
+ super(description, date, time, "[E]", false);
+ }
+
+ /**
+ * Converts the start and end time from 24h to 12h format.
+ */
+ public void formatStartEndTime() {
+ String timeCopy = getTime();
+ String[] timeArr = timeCopy.split("-");
+ String startTime = timeArr[0];
+ String endTime = timeArr[1];
+ String formattedStartTime = formatTime(startTime);
+ String formattedEndTime = formatTime(endTime);
+ String formattedTime = formattedStartTime + "-" + formattedEndTime;
+ setTime(formattedTime);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/duke/Launcher.java b/src/main/java/duke/Launcher.java
new file mode 100644
index 0000000000..cef3c40d17
--- /dev/null
+++ b/src/main/java/duke/Launcher.java
@@ -0,0 +1,12 @@
+package duke;
+
+import javafx.application.Application;
+
+/**
+ * A launcher class to workaround classpath issues.
+ */
+public class Launcher {
+ public static void main(String[] args) {
+ Application.launch(Duke.class, args);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/duke/Parser.java b/src/main/java/duke/Parser.java
new file mode 100644
index 0000000000..8e4c3e0ac1
--- /dev/null
+++ b/src/main/java/duke/Parser.java
@@ -0,0 +1,291 @@
+package duke;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Deals with making sense of users' commands.
+ */
+public class Parser {
+ private String inputCommand;
+ private TaskList taskList;
+ private final Ui ui;
+ private final Storage storage;
+
+ public Parser(TaskList taskList, Ui ui, Storage storage) {
+ inputCommand = "";
+ this.taskList = taskList;
+ this.ui = ui;
+ this.storage = storage;
+ }
+
+ /**
+ * Inputs a new command to be processed.
+ * @param command The input command.
+ */
+ public void addCommand(String command) {
+ this.inputCommand = command;
+ }
+
+ /**
+ * Lists down all the tasks in the task list.
+ * @return Every tasks in the list.
+ */
+ public String processList() {
+ String list = taskList.listAllTasks();
+ return ui.provideList(list);
+ }
+
+ /**
+ * Checks if the input command is valid, if not, respond accordingly.
+ * Creates a Todo and adds it to the task list.
+ * Saves any changes to the hard drive.
+ * @param command The todo command followed its description, date and time.
+ * @return The newly added todo task with the number of tasks in the task list.
+ */
+ public String processTodo(String command) {
+ String description = command.replace("todo", "").strip();
+ if (description.length() == 0) {
+ return ui.missingDescriptionReply();
+ }
+ Todo todo = new Todo(description);
+ if (taskList.hasTask(todo)) {
+ return ui.detectDuplicateReply(todo.toString());
+ }
+ taskList.addTask(todo);
+ storage.writeToFile(taskList);
+ int numOfTasks = taskList.numOfTasks();
+ return ui.addTaskReply(todo.toString(), String.valueOf(numOfTasks));
+ }
+
+ /**
+ * Checks if the input command is valid, if not, respond accordingly.
+ * Creates a Deadline and adds it to the task list.
+ * Saves any changes to the hard drive.
+ * @param command The deadline command followed its description, date and time.
+ * @return The newly added deadline task with the number of tasks in the task list.
+ */
+ public String processDeadline(String command) {
+ String input = command.replace("deadline", "").strip();
+ if (input.length() == 0) {
+ return ui.missingDescriptionReply();
+ }
+ String[] inputArr = input.split(" ");
+ StringBuilder description = new StringBuilder();
+ StringBuilder date = new StringBuilder();
+ StringBuilder time = new StringBuilder();
+ boolean isDescription = true;
+ boolean isTime = false;
+ for (String string : inputArr) {
+ if (string.equals("/by")) {
+ isDescription = false;
+ } else if (isDescription) {
+ description.append(string).append(" ");
+ } else if (isTime) {
+ time.append(string);
+ } else {
+ date.append(string);
+ isTime = true;
+ }
+ }
+ if (date.length() == 0) {
+ return ui.missingDateReply();
+ } else if (time.length() == 0) {
+ return ui.missingTimeReply();
+ }
+ Deadline deadline = new Deadline(description.toString(), date.toString(), time.toString());
+ deadline.formatDate();
+ String formattedTime = deadline.formatTime(time.toString());
+ deadline.setTime(formattedTime);
+ if (taskList.hasTask(deadline)) {
+ return ui.detectDuplicateReply(deadline.toString());
+ }
+ taskList.addTask(deadline);
+ storage.writeToFile(taskList);
+ int numOfTasks = taskList.numOfTasks();
+ return ui.addTaskReply(deadline.toString(), String.valueOf(numOfTasks));
+ }
+
+ /**
+ * Checks if the input command is valid, if not, respond accordingly.
+ * Creates an Event and adds it to the task list.
+ * Saves any changes to the hard drive.
+ * @param command The event command followed its description, date and time.
+ * @return The newly added event task with the number of tasks in the task list.
+ */
+ public String processEvent(String command) {
+ String input = command.replace("event", "").strip();
+ if (input.length() == 0) {
+ return ui.missingDescriptionReply();
+ }
+ String[] inputArr = input.split(" ");
+ StringBuilder description = new StringBuilder();
+ StringBuilder date = new StringBuilder();
+ StringBuilder time = new StringBuilder();
+ boolean isDescription = true;
+ boolean isTime = false;
+ for (String string : inputArr) {
+ if (string.equals("/at")) {
+ isDescription = false;
+ } else if (isDescription) {
+ description.append(string).append(" ");
+ } else if (isTime) {
+ time.append(string);
+ } else {
+ date.append(string);
+ isTime = true;
+ }
+ }
+ if (date.length() == 0) {
+ return ui.missingDateReply();
+ } else if (time.length() == 0) {
+ return ui.missingTimeReply();
+ }
+ Event event = new Event(description.toString(), date.toString(), time.toString());
+ event.formatDate();
+ event.formatStartEndTime();
+ if (taskList.hasTask(event)) {
+ return ui.detectDuplicateReply(event.toString());
+ }
+ taskList.addTask(event);
+ storage.writeToFile(taskList);
+ int numOfTasks = taskList.numOfTasks();
+ return ui.addTaskReply(event.toString(), String.valueOf(numOfTasks));
+ }
+
+ /**
+ * Checks if the input command is valid, if not, respond accordingly.
+ * Marks the task at the given line number as done.
+ * Saves any changes to the hard drive.
+ * @param command The done command followed by the line number.
+ * @return The completed task.
+ */
+ public String processDone(String command) {
+ String input = command.replace("done", "").strip();
+ if (input.length() == 0) {
+ return ui.missingLineNumberReply();
+ }
+ int lineNumber = Integer.parseInt(input);
+ if (lineNumber > taskList.numOfTasks()) {
+ return ui.invalidLineReply();
+ }
+ int index = lineNumber - 1;
+ Task completedTask = taskList.markTaskAsDone(index);
+ storage.writeToFile(taskList);
+ return ui.markAsDoneReply(completedTask.toString());
+ }
+
+ /**
+ * Checks if the user inputted a line number to be deleted, if not, inform the user.
+ * Checks if the user wants to delete one or all tasks from the task list.
+ * Redirects to the appropriate process method.
+ * @param command The delete command followed by either the line number or all command.
+ * @return The relevant response from the redirected process method.
+ */
+ public String checkDelete(String command) {
+ String suffix = command.replace("delete", "").strip();
+ if (suffix.length() == 0) {
+ return ui.missingLineNumberReply();
+ }
+ if (suffix.startsWith("all")) {
+ return processDeleteAll();
+ }
+ return processDelete(suffix);
+ }
+
+ /**
+ * Checks if the line number to be deleted is valid, if not, inform the user.
+ * Deletes the task at the given line number.
+ * Saves any changes to the hard drive.
+ * @param suffix The line number in string.
+ * @return The deleted task with the number of tasks left in the task list.
+ */
+ public String processDelete(String suffix) {
+ int lineNumber = Integer.parseInt(suffix);
+ if (lineNumber > taskList.numOfTasks()) {
+ return ui.invalidLineReply();
+ }
+ int index = lineNumber - 1;
+ Task deletedTask = taskList.deleteTask(index);
+ int numOfTasks = taskList.numOfTasks();
+ storage.writeToFile(taskList);
+ return ui.deleteTaskReply(deletedTask.toString(), String.valueOf(numOfTasks));
+ }
+
+ /**
+ * Deletes all the tasks from the task list.
+ * Saves any changes to the hard drive.
+ * @return The reply informing the user that all tasks have been deleted.
+ */
+ public String processDeleteAll() {
+ taskList = new TaskList();
+ storage.writeToFile(taskList);
+ return ui.deleteAllReply();
+ }
+
+ /**
+ * Checks if the input command is valid, if not, respond accordingly.
+ * Searches through the task list.
+ * List out the tasks with descriptions containing the search word, if any.
+ * Gives the appropriate response based on the input command.
+ * @param command The find command followed by the search word.
+ * @return A list of tasks containing the search word in their descriptions, if any.
+ */
+ public String processFind(String command) {
+ String word = command.replace("find", "").strip();
+ if (word.length() == 0) {
+ return ui.missingSearchWordReply();
+ }
+ List matches = new ArrayList<>();
+ boolean isFound = false;
+ int matchNumber = 1;
+ for (int i = 0; i < taskList.numOfTasks(); i++) {
+ Task task = taskList.getTask(i);
+ String taskInString = task.toString();
+ if (taskInString.contains(word)) {
+ matches.add(matchNumber + ". " + taskInString);
+ isFound = true;
+ matchNumber++;
+ }
+ }
+ if (!isFound) {
+ return ui.wordNotFoundReply();
+ }
+ StringBuilder matchesInString = new StringBuilder();
+ for (String match : matches) {
+ matchesInString.append(match).append("\n");
+ }
+ return ui.findWordReply(matchesInString.toString());
+ }
+
+ /**
+ * Processes the input command and passes it on to the relevant processor, responds accordingly.
+ * @return The appropriate response based on the input command.
+ */
+ public String process() {
+ String response = "";
+ if (inputCommand.startsWith("start")) {
+ response = ui.greet();
+ } else if (inputCommand.startsWith("list")) {
+ response = processList();
+ } else if (inputCommand.startsWith("todo")) {
+ response = processTodo(inputCommand);
+ } else if (inputCommand.startsWith("deadline")) {
+ response = processDeadline(inputCommand);
+ } else if (inputCommand.startsWith("event")) {
+ response = processEvent(inputCommand);
+ } else if (inputCommand.startsWith("done")) {
+ response = processDone(inputCommand);
+ } else if (inputCommand.startsWith("delete")) {
+ response = checkDelete(inputCommand);
+ } else if (inputCommand.startsWith("find")) {
+ response = processFind(inputCommand);
+ } else if (inputCommand.startsWith("bye")) {
+ System.exit(0);
+ } else {
+ response = ui.invalidCommandReply();
+ }
+ assert response.length() > 0 : "the response cannot be empty";
+ return response;
+ }
+}
diff --git a/src/main/java/duke/Storage.java b/src/main/java/duke/Storage.java
new file mode 100644
index 0000000000..9832eb6c57
--- /dev/null
+++ b/src/main/java/duke/Storage.java
@@ -0,0 +1,141 @@
+package duke;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+public class Storage {
+ private final String filePath;
+ private TaskList taskList;
+
+ public Storage(String filePath) {
+ this.filePath = filePath;
+ }
+
+ public TaskList getTaskList() {
+ return taskList;
+ }
+
+ /**
+ * Loads the file containing the task list from the hard drive when Duke starts up.
+ * If the file or folder doesn't exist yet, create a file in the file path or file path first.
+ */
+ public void retrieveOrCreate() {
+ Path path = Paths.get(filePath);
+ if (!Files.exists(path)) {
+ try {
+ Files.createDirectories(path.getParent());
+ Files.createFile(path);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return;
+ }
+ taskList = readFromFile();
+ }
+
+ /**
+ * Saves the updated task list in the hard drive automatically whenever the task list changes.
+ */
+ public void writeToFile(TaskList taskList) {
+ StringBuilder output = new StringBuilder();
+ for (int i = 0; i < taskList.numOfTasks(); i++) {
+ output.append(taskList.getTask(i).toString()).append("\n");
+ }
+ try {
+ BufferedWriter bw = new BufferedWriter(new FileWriter(filePath));
+ bw.write(output.toString());
+ bw.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Converts the line from a string array to a Todo.
+ * @param dataArr The line in a string array.
+ * @return A Todo.
+ */
+ public Task convertToTodo(String[] dataArr) {
+ StringBuilder description = new StringBuilder();
+ for (int i = 2; i < dataArr.length; i++) {
+ description.append(dataArr[i]).append(" ");
+ }
+ return new Todo(description.toString());
+ }
+
+ /**
+ * Converts the line from a string array to either a Deadline or Event.
+ * @param dataArr The line in a string array.
+ * @param isDeadline A flag indicating if the line is a Deadline.
+ * @return A Deadline or Event depending on isDeadline.
+ */
+ public Task convertToDeadlineOrEvent(String[] dataArr, boolean isDeadline) {
+ int lastIndex = dataArr.length - 1;
+ String timeWithBracket = dataArr[lastIndex];
+ String[] timeWithBracketArr = timeWithBracket.split("");
+ int timeWithBracketLength = timeWithBracketArr.length;
+ int timeWithBracketLastIndex = timeWithBracketLength - 2;
+ StringBuilder time = new StringBuilder();
+ for (int i = 0; i <= timeWithBracketLastIndex; i++) {
+ time.append(timeWithBracketArr[i]);
+ }
+ String yearData = dataArr[lastIndex - 1];
+ String[] yearArr = yearData.split("");
+ StringBuilder year = new StringBuilder();
+ for (int i = 0; i < 4; i++) {
+ year.append(yearArr[i]);
+ }
+ String date = dataArr[lastIndex - 3] + " " + dataArr[lastIndex - 2] + " " + year;
+ int descriptionLastIndex = lastIndex - 5;
+ StringBuilder description = new StringBuilder();
+ for (int i = 2; i <= descriptionLastIndex; i++) {
+ description.append(dataArr[i]).append(" ");
+ }
+ if (isDeadline) {
+ return new Deadline(description.toString(), date, time.toString());
+ }
+ return new Event(description.toString(), date, time.toString());
+ }
+
+ /**
+ * Reads the whole file line by line.
+ * For each line, checks which type of Task it is.
+ * Passes the line to the relevant converter to convert into a Task.
+ * Adds the task to a list.
+ * After reading the entire file, return the list.
+ * @return The saved task list.
+ */
+ public TaskList readFromFile() {
+ TaskList taskList = new TaskList();
+ try {
+ BufferedReader br = new BufferedReader(new FileReader(filePath));
+ String input = br.readLine();
+ while (input != null) {
+ String[] inputArr = input.split(" ");
+ Task task;
+ if (input.startsWith("[T]")) {
+ task = convertToTodo(inputArr);
+ } else if (input.startsWith("[D]")) {
+ task = convertToDeadlineOrEvent(inputArr, true);
+ } else {
+ task = convertToDeadlineOrEvent(inputArr, false);
+ }
+ if (inputArr[1].equals("[/]")) {
+ task = task.markAsDone();
+ }
+ taskList.addTask(task);
+ input = br.readLine();
+ }
+ br.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return taskList;
+ }
+}
diff --git a/src/main/java/duke/Task.java b/src/main/java/duke/Task.java
new file mode 100644
index 0000000000..908c86c778
--- /dev/null
+++ b/src/main/java/duke/Task.java
@@ -0,0 +1,168 @@
+package duke;
+
+import java.time.format.DateTimeFormatter;
+import java.time.LocalDate;
+import java.util.ArrayList;
+import java.util.List;
+
+public class Task {
+ private final String description;
+ private String date;
+ private String time;
+ /**
+ * symbol represents the type of Task.
+ * T for Todo.
+ * D for Deadline.
+ * E for Event.
+ */
+ private final String symbol;
+ private final boolean isDone;
+
+ public Task(String description, String date, String time, String symbol, boolean done) {
+ this.description = description;
+ this.date = date;
+ this.time = time;
+ this.symbol = symbol;
+ isDone = done;
+ }
+
+ public String getDate() {
+ return date;
+ }
+
+ public String getTime() {
+ return time;
+ }
+
+ public void setTime(String time) {
+ this.time = time;
+ }
+
+ /**
+ * Changes the status of a task to done.
+ * @return The task with the status changed to done.
+ */
+ public Task markAsDone() {
+ return new Task(description, date, time, symbol, true);
+ }
+
+ /**
+ * Converts the date from DD/MM/YYYY format to D MMM YYYY format.
+ */
+ public void formatDate() {
+ String dateCopy = date;
+ StringBuilder year = new StringBuilder();
+ StringBuilder month = new StringBuilder();
+ StringBuilder day = new StringBuilder();
+ String[] dateArr = dateCopy.split("");
+ int slashCount = 0;
+ for (String string : dateArr) {
+ if (string.equals("/")) {
+ slashCount++;
+ } else if (slashCount == 2) {
+ year.append(string);
+ } else if (slashCount == 1) {
+ month.append(string);
+ } else {
+ day.append(string);
+ }
+ }
+ if (day.length() == 1) {
+ day.insert(0, "0");
+ }
+ if (month.length() == 1) {
+ month.insert(0, "0");
+ }
+ if (year.length() == 2) {
+ year.insert(0, "20");
+ }
+ String formattedDate = year + "-" + month + "-" + day;
+ LocalDate ld = LocalDate.parse(formattedDate);
+ date = ld.format(DateTimeFormatter.ofPattern("d MMM yyyy"));
+ }
+
+ /**
+ * Converts the hours from 24h to 12h format when the tenth digit of the hour is zero.
+ * @param onesHour The one digit of the hour.
+ * @return The formatted hour in a List.
+ */
+ public List formatOnesHour(int onesHour) {
+ List timeArr = new ArrayList<>();
+ if (onesHour == 0) {
+ timeArr.add("12:");
+ timeArr.add("am");
+ return timeArr;
+ }
+ String hour = String.valueOf(onesHour);
+ timeArr.add(hour);
+ timeArr.add("am");
+ return timeArr;
+ }
+
+ /**
+ * Converts the hours from 24h to 12h format.
+ * @param tensHour The tenth digit of the hour.
+ * @param onesHour The one digit of the hour.
+ * @return The formatted hour in a List.
+ */
+ public List formatTensHour(int tensHour, int onesHour) {
+ List timeArr = new ArrayList<>();
+ int hour = tensHour * 10 + onesHour;
+ if (hour >= 13) {
+ hour -= 12;
+ String hourString = String.valueOf(hour);
+ timeArr.add(hourString);
+ timeArr.add("pm");
+ return timeArr;
+ }
+ String hourString = String.valueOf(hour);
+ timeArr.add(hourString);
+ if (hour >= 12) {
+ timeArr.add("pm");
+ return timeArr;
+ }
+ timeArr.add("am");
+ return timeArr;
+ }
+
+ /**
+ * Converts the time from 24h to 12h format.
+ */
+ public String formatTime(String time) {
+ char[] timeArr = time.toCharArray();
+ int tensHour = timeArr[0] - '0';
+ int onesHour = timeArr[1] - '0';
+ int tensMin = timeArr[2] - '0';
+ int onesMin = timeArr[3] - '0';
+ List timeList;
+ if (tensHour == 0) {
+ timeList = formatOnesHour(onesHour);
+ } else {
+ timeList = formatTensHour(tensHour, onesHour);
+ }
+ String min = ":";
+ if (tensMin == 0) {
+ min += "0";
+ } else {
+ min += String.valueOf(tensMin);
+ }
+ min += String.valueOf(onesMin);
+ return timeList.get(0) + min + timeList.get(1);
+ }
+
+ @Override
+ public String toString() {
+ String output = "";
+ if (symbol.equals("[D]")) {
+ output += "(by: " + date + ", " + time + ")";
+ }
+ if (symbol.equals("[E]")) {
+ output += "(at: " + date + ", " + time + ")";
+ }
+ output = description + output;
+ if (isDone) {
+ return symbol + " [/] " + output;
+ }
+ return symbol + " [] " + output;
+ }
+}
diff --git a/src/main/java/duke/TaskList.java b/src/main/java/duke/TaskList.java
new file mode 100644
index 0000000000..abc16d0411
--- /dev/null
+++ b/src/main/java/duke/TaskList.java
@@ -0,0 +1,91 @@
+package duke;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Keeps track of all Tasks in a list.
+ */
+public class TaskList {
+ private final List taskList;
+
+ public TaskList() {
+ taskList = new ArrayList<>();
+ }
+
+ /**
+ * Get a specific task from the list.
+ * @param index The position of the task in the list.
+ * @return The task at the given index.
+ */
+ public Task getTask(int index) {
+ return taskList.get(index);
+ }
+
+ /**
+ * Add a task to the list.
+ * @param task The added task.
+ */
+ public void addTask(Task task) {
+ taskList.add(task);
+ }
+
+ /**
+ * Delete a specific task from the list.
+ * @param index The position of the task in the list.
+ * @return The removed task.
+ */
+ public Task deleteTask(int index) {
+ Task deletedTask = getTask(index);
+ taskList.remove(index);
+ return deletedTask;
+ }
+
+ /**
+ * Mark the task at the given index as done.
+ * @param index The position of a task in the list.
+ */
+ public Task markTaskAsDone(int index) {
+ Task completedTask = getTask(index).markAsDone();
+ taskList.set(index, completedTask);
+ return completedTask;
+ }
+
+ /**
+ * Get the number of tasks in the list.
+ * @return The number of tasks in the list.
+ */
+ public int numOfTasks() {
+ return taskList.size();
+ }
+
+ /**
+ * list down all tasks in the list.
+ * @return the list of all tasks.
+ */
+ public String listAllTasks() {
+ StringBuilder list = new StringBuilder();
+ int taskNumber = 1;
+ for (Task task : taskList) {
+ list.append(taskNumber).append(". ").append(task.toString()).append("\n");
+ taskNumber++;
+ }
+ return list.toString();
+ }
+
+ /**
+ * Checks if the task list has the given task.
+ * @param givenTask The given task.
+ * @return True if the task list has the given task, false otherwise.
+ */
+ public boolean hasTask(Task givenTask) {
+ String givenTaskString = givenTask.toString();
+ for (Task task : taskList) {
+ String taskString = task.toString();
+ if (taskString.equals(givenTaskString)) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/duke/Todo.java b/src/main/java/duke/Todo.java
new file mode 100644
index 0000000000..27eee375ba
--- /dev/null
+++ b/src/main/java/duke/Todo.java
@@ -0,0 +1,10 @@
+package duke;
+
+/**
+ * A type of Task.
+ */
+public class Todo extends Task {
+ public Todo(String description) {
+ super(description, "", "", "[T]", false);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/duke/Ui.java b/src/main/java/duke/Ui.java
new file mode 100644
index 0000000000..8bfb992a96
--- /dev/null
+++ b/src/main/java/duke/Ui.java
@@ -0,0 +1,141 @@
+package duke;
+
+/**
+ * Deals with the interactions with users.
+ */
+public class Ui {
+
+ /**
+ * Greets the user and showcases the DUKE logo.
+ */
+ public String greet() {
+ return "Hi! I'm DUKE, your task manager. What can I do for you?";
+ }
+
+ /**
+ * lists out all the tasks in the task list.
+ * @param list The task list.
+ * @return All the tasks in the task list.
+ */
+ public String provideList(String list) {
+ return "Here are the tasks in your list:\n" + list;
+ }
+
+ /**
+ * Informs the user that the task has been added and the number of tasks in the task list.
+ * @param task The added task.
+ * @param numOfTasks The number of tasks in the task list.
+ * @return The added task and number of tasks in the task list.
+ */
+ public String addTaskReply(String task, String numOfTasks) {
+ return "Got it. I've added this task:\n" + task + "\n" + "Now you have " + numOfTasks + " tasks in the list.";
+ }
+
+ /**
+ * Informs the user that the task has been marked as done.
+ * @param task The task marked as done.
+ * @return The completed task.
+ */
+ public String markAsDoneReply(String task) {
+ return "Nice! I've marked this task as done:\n" + task;
+ }
+
+ /**
+ * Informs the user that the task has been deleted and the number of tasks left in the task list.
+ * @param task The deleted task.
+ * @param numOfTasks The number of tasks left in the task list.
+ * @return The deleted task and number of tasks left in the task list.
+ */
+ public String deleteTaskReply(String task, String numOfTasks) {
+ return "Noted. I've removed this task:\n" + task + "\n" + "Now you have " + numOfTasks + " tasks in the list.";
+ }
+
+ /**
+ * Informs the user that all the task has been deleted from the list.
+ * @return The deletion of all tasks.
+ */
+ public String deleteAllReply() {
+ return "Noted. I've removed all the tasks from the list.";
+ }
+
+ /**
+ * lists out all the tasks with descriptions containing the search word from the task list.
+ * @param tasks The matching tasks.
+ * @return The matching tasks.
+ */
+ public String findWordReply(String tasks) {
+ return "Here are the matching tasks in your list:\n" + tasks;
+ }
+
+ /**
+ * Informs the user that there are no tasks with descriptions containing the search word from the task list.
+ * @return The response that there are no matching tasks.
+ */
+ public String wordNotFoundReply() {
+ return "Your list does not contain this word.";
+ }
+
+ /**
+ * Informs the user that they did not input a description.
+ * @return The warning of an empty description.
+ */
+ public String missingDescriptionReply() {
+ return "The description cannot be empty.";
+ }
+
+ /**
+ * Informs the user that they did not input a date.
+ * @return The warning of an empty date.
+ */
+ public String missingDateReply() {
+ return "The date cannot be empty.";
+ }
+
+ /**
+ * Informs the user that they did not input a time.
+ * @return The warning of an empty time.
+ */
+ public String missingTimeReply() {
+ return "The time cannot be empty.";
+ }
+
+ /**
+ * Informs the user that they did not input a line number.
+ * @return The warning of an empty line number.
+ */
+ public String missingLineNumberReply() {
+ return "The line number cannot be empty.";
+ }
+
+ /**
+ * Informs the user that they did not input a search word.
+ * @return The warning of an empty search word.
+ */
+ public String missingSearchWordReply() {
+ return "The word cannot be empty.";
+ }
+
+ /**
+ * Informs the user that they inputted an invalid line number.
+ * @return The warning of an invalid line number.
+ */
+ public String invalidLineReply() {
+ return "Invalid line number.";
+ }
+
+ /**
+ * Informs the user that they inputted an invalid command.
+ * @return The warning of an invalid command.
+ */
+ public String invalidCommandReply() {
+ return "Invalid command. Please try again.";
+ }
+
+ /**
+ * Informs the user that the task they are adding already exists in the task list.
+ * @return The warning that the task already exist.
+ */
+ public String detectDuplicateReply(String task) {
+ return "This task: \"" + task + "\" already exists in the list.";
+ }
+}
diff --git a/src/main/resources/images/DaDuke.png b/src/main/resources/images/DaDuke.png
new file mode 100644
index 0000000000..1c05056373
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..be0c2056e6
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..ede775d4f9
--- /dev/null
+++ b/src/main/resources/view/DialogBox.fxml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml
new file mode 100644
index 0000000000..702f29d63b
--- /dev/null
+++ b/src/main/resources/view/MainWindow.fxml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/java/TaskListTest.java b/src/test/java/TaskListTest.java
new file mode 100644
index 0000000000..7184271344
--- /dev/null
+++ b/src/test/java/TaskListTest.java
@@ -0,0 +1,22 @@
+import duke.Deadline;
+import duke.Event;
+import duke.TaskList;
+import duke.Todo;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+
+public class TaskListTest {
+ TaskList taskList = new TaskList();
+ Todo todo = new Todo("read book");
+ Deadline deadline = new Deadline("deadline return book", "7/2/2021", "1700");
+ Event event = new Event("event team meeting", "8/2/2021", "1400-1600");
+
+ @Test
+ public void numOfTask() {
+ taskList.addTask(todo);
+ taskList.addTask(deadline);
+ taskList.addTask(event);
+ assertEquals(3, taskList.numOfTasks());
+ }
+}
diff --git a/src/test/java/TaskTest.java b/src/test/java/TaskTest.java
new file mode 100644
index 0000000000..e402db099a
--- /dev/null
+++ b/src/test/java/TaskTest.java
@@ -0,0 +1,21 @@
+import duke.Task;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class TaskTest {
+ Task task = new Task("todo read book", "1/2/2021", "1400", "[T]", true);
+
+ @Test
+ public void testFormatDate() {
+ task.formatDate();
+ assertEquals("1 Feb 2021", task.getDate());
+ }
+
+ @Test
+ public void testFormatTime() {
+ String time = task.getTime();
+ String formattedTime = task.formatTime(time);
+ task.setTime(formattedTime);
+ assertEquals("2:00pm", task.getTime());
+ }
+}
\ No newline at end of file
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 657e74f6e7..3677277d6b 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -4,4 +4,34 @@ Hello from
| | | | | | | |/ / _ \
| |_| | |_| | < __/
|____/ \__,_|_|\_\___|
-
+Got it. I've added this task:
+[T][ ] read book
+Now you have 1 tasks in the list.
+Got it. I've added this task:
+[D][ ] return book (by: June 6th)
+Now you have 2 tasks in the list.
+Got it. I've added this task:
+[E][ ] project meeting (at: Aug 6th 2-4pm)
+Now you have 3 tasks in the list.
+Got it. I've added this task:
+[T][ ] join sports club
+Now you have 4 tasks in the list.
+Got it. I've added this task:
+[T][ ] borrow book
+Now you have 5 tasks in the list.
+Nice! I've marked this task as done:
+[T][X] read book
+Nice! I've marked this task as done:
+[D][X] return book (by: June 6th)
+Nice! I've marked this task as done:
+[T][X] join sports club
+Here are the tasks in your list:
+1.[T][X] read book
+2.[D][X] return book (by: June 6th)
+3.[E][ ] project meeting (at: Aug 6th 2-4pm)
+4.[T][X] join sports club
+5.[T][ ] borrow book
+Noted. I've removed this task:
+[E][ ] project meeting (at: Aug 6th 2-4pm)
+Now you have 4 tasks in the list.
+:( OOPS!!! I'm sorry, but I don't know what that means :-(
\ No newline at end of file
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index e69de29bb2..cf72cc787e 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -0,0 +1,11 @@
+todo read book
+deadline return book /by June 6th
+event project meeting /at: Aug 6th 2-4pm
+todo join sports club
+todo borrow book
+done 1
+done 2
+done 4
+list
+delete 3
+blah
\ No newline at end of file
diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat
index 0873744649..746406606b 100644
--- a/text-ui-test/runtest.bat
+++ b/text-ui-test/runtest.bat
@@ -1,21 +1,21 @@
-@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
+@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 \Users\galen\cs2103t\ip\src\main\java -Xlint:none -d ..\bin \Users\galen\cs2103t\ip\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
index c9ec870033..a624e7c0d1 100644
--- a/text-ui-test/runtest.sh
+++ b/text-ui-test/runtest.sh
@@ -13,7 +13,7 @@ then
fi
# compile the code into the bin folder, terminates if error occurred
-if ! javac -cp ../src/main/java -Xlint:none -d ../bin ../src/main/java/*.java
+if ! javac -cp /Users/galen/cs2103t/ip/src/main/java -Xlint:none -d ../bin /Users/galen/cs2103t/ip/src/main/java/*.java
then
echo "********** BUILD FAILURE **********"
exit 1