diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000000..f9e3ea8d87
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,58 @@
+plugins {
+ id 'java'
+ id 'application'
+ id 'com.github.johnrengelman.shadow' version '7.1.2'
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ String javaFxVersion = '17.0.7'
+
+ 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.10.0'
+ testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.10.0'
+}
+
+test {
+ useJUnitPlatform()
+
+ testLogging {
+ events "passed", "skipped", "failed"
+
+ showExceptions true
+ exceptionFormat "full"
+ showCauses true
+ showStackTraces true
+ showStandardStreams = false
+ }
+}
+
+application {
+ mainClass.set("jelly.Launcher")
+}
+
+shadowJar {
+ archiveBaseName = "jelly"
+ archiveClassifier = null
+ dependsOn("distZip", "distTar")
+ archiveFileName ="jelly.jar"
+}
+
+run{
+ standardInput = System.in
+}
diff --git a/config/checkstyle.xml b/config/checkstyle.xml
new file mode 100644
index 0000000000..eb761a9b9a
--- /dev/null
+++ b/config/checkstyle.xml
@@ -0,0 +1,434 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config/suppressions.xml b/config/suppressions.xml
new file mode 100644
index 0000000000..39efb6e4ac
--- /dev/null
+++ b/config/suppressions.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
diff --git a/docs/README.md b/docs/README.md
index 8077118ebe..cb71086e6b 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,29 +1,164 @@
-# User Guide
+# Jelly User Guide
-## Features
+## Features
+- Add a todo task: `todo`
+- Add a deadline task: `deadline`
+- Add an event task: `event`
+- List all tasks: `list`
+- Find a task using a keyword: `find`
+- Mark a task as done: `mark`
+- Mark a task as not done: `unmark`
+- Delete a task: `delete`
+- Change the priority of a task: `priority`
+- Exit the chat bot: `bye`
-### Feature-ABC
+## Usage
-Description of the feature.
+### Add a todo task: `todo`
-### Feature-XYZ
+Adds a todo task to the list.
-Description of the feature.
+Format: `todo {DESCRIPTION}`
-## Usage
+Example of usage:
+`todo math homework`
+
+Expected outcome:
+```
+Ok! I've added this task:
+[T] [ ] math homework (HIGH)
+Now you have {x} tasks in the list.
+```
+
+### Add a deadline task: `deadline`
+
+Adds a deadline task to the list.
+
+Format: `deadline {DESCRIPTION} /by dd/MM/yyyy HHmm`
+
+Example of usage:
+`deadline Finish homework /by 24/09/2023 1900`
+
+Expected outcome:
+```
+Ok! I've added this task:
+[D] [ ] Finish homework (by: Sep 24 2023 19:00) (HIGH)
+Now you have {x} tasks in the list.
+```
+
+### Add an event task: `event`
+
+Adds an event task to the list.
+
+Format: `event {DESCRIPTION} /from dd/MM/yyyy HHmm /to dd/MM/yyyy HHmm`
+
+Example of usage:
+`event Party /from 24/09/2023 1900 /to 24/09/2023 2300`
+
+Expected outcome:
+```
+Ok! I've added this task:
+[E] [ ] Party (from: Sep 24 2023 19:00 to: Sep 24 2023 23:00) (HIGH)
+Now you have {x} tasks in the list.
+```
+
+### List all tasks: `list`
+
+Displays all tasks in the list.
+
+Format: `list`
+
+Example of usage:
+`list`
+
+Expected outcome:
+```
+Here are the tasks in your list:
+1.[T] [ ] math homework (HIGH)
+2.[D] [ ] Finish homework (by: Sep 24 2023 19:00) (HIGH)
+3.[D] [ ] Finish homework (by: Sep 24 2023 19:00) (HIGH)
+```
+
+### Find a task using a keyword: `find`
+
+Displays all tasks in the list.
-### `Keyword` - Describe action
+Format: `find {keyword}`
-Describe the action and its outcome.
+Example of usage:
+`find math`
-Example of usage:
+Expected outcome:
+```
+Here are the tasks in your list:
+1.[T] [ ] math homework (HIGH)
+````
+
+### Mark a task as done: `mark`
+
+Marks a task in the list as done.
+
+Format: `mark {index}`
+
+Example of usage:
+`mark 1`
+
+Expected outcome:
+```
+Good job! I've marked this task as done :)
+```
+
+### Mark a task as not done: `unmark`
+
+Marks a task in the list as not done.
+
+Format: `unmark {index}`
+
+Example of usage:
+`unmark 1`
+
+Expected outcome:
+```
+Bad job! I've marked this task as not done :(
+```
+
+### Delete a task: `delete`
+
+Deletes the specified task from the list.
-`keyword (optional arguments)`
+Format: `delete {index}`
+
+Example of usage:
+`delete 1`
Expected outcome:
+```
+Okay, I've removed this task:
+[T] [ ] math homework (HIGH)
+Now you have 2 tasks in the list.
+```
+
+### Change the priority of a task: `priority`
-Description of the outcome.
+Changes the priority of a task to high(1), medium(2), or low(3).
+Note: Priority of a task is (HIGH) as default.
+
+Format: `priority {index} {priority}`
+
+Example of usage:
+`priority 1 3`
+
+Expected outcome:
```
-expected output
+I've changed the priority of this task to: 3
```
+
+### Exit the chat bot: `bye`
+
+Saves the current list and exits out of the chat bot.
+
+Format: `bye`
+
+Example of usage:
+`bye`
diff --git a/docs/Ui.png b/docs/Ui.png
new file mode 100644
index 0000000000..5ae4eebcfd
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..033e24c4cd
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..66c01cfeba
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.2-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000000..fcb6fca147
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,248 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original 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 POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ 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
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# 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"'
+
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000000..6689b85bee
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,92 @@
+@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=.
+@rem This is normally unused
+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% equ 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% equ 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!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/jelly.txt b/jelly.txt
new file mode 100644
index 0000000000..302346e87f
--- /dev/null
+++ b/jelly.txt
@@ -0,0 +1,2 @@
+T | 0 | this | (HIGH)
+D | 0 | do that | 12/02/1920 1900 | (HIGH)
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/jelly/DialogBox.java b/src/main/java/jelly/DialogBox.java
new file mode 100644
index 0000000000..11f1f83d01
--- /dev/null
+++ b/src/main/java/jelly/DialogBox.java
@@ -0,0 +1,61 @@
+package jelly;
+
+import java.io.IOException;
+import java.util.Collections;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.geometry.Pos;
+import javafx.scene.Node;
+import javafx.scene.control.Label;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.HBox;
+
+/**
+ * An example of a custom control using FXML.
+ * This control represents a dialog box consisting of an ImageView to represent the speaker's face and a label
+ * containing text from the speaker.
+ */
+public class DialogBox extends HBox {
+ @FXML
+ private Label dialog;
+ @FXML
+ private ImageView displayPicture;
+
+ private DialogBox(String text, Image img) {
+ try {
+ FXMLLoader fxmlLoader = new FXMLLoader(MainWindow.class.getResource("/view/DialogBox.fxml"));
+ fxmlLoader.setController(this);
+ fxmlLoader.setRoot(this);
+ fxmlLoader.load();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ dialog.setText(text);
+ displayPicture.setImage(img);
+ }
+
+ /**
+ * Flips the dialog box such that the ImageView is on the left and text on the right.
+ */
+ private void flip() {
+ ObservableList tmp = FXCollections.observableArrayList(this.getChildren());
+ Collections.reverse(tmp);
+ getChildren().setAll(tmp);
+ setAlignment(Pos.TOP_LEFT);
+ }
+
+ public static DialogBox getUserDialog(String text, Image img) {
+ return new DialogBox(text, img);
+ }
+
+ public static DialogBox getJellyDialog(String text, Image img) {
+ var db = new DialogBox(text, img);
+ db.flip();
+ return db;
+ }
+}
diff --git a/src/main/java/jelly/Jelly.java b/src/main/java/jelly/Jelly.java
new file mode 100644
index 0000000000..7dbaf35e8a
--- /dev/null
+++ b/src/main/java/jelly/Jelly.java
@@ -0,0 +1,77 @@
+package jelly;
+
+import jelly.commands.Command;
+import jelly.exceptions.JellyException;
+import jelly.main.Parser;
+import jelly.main.Storage;
+import jelly.main.TaskList;
+import jelly.main.Ui;
+
+/**
+ * The main class which is responsible in running the Jelly chatbot.
+ */
+public class Jelly {
+ private static final String FILE_PATH = "./taskData/jelly.txt";
+ private TaskList taskList;
+ private final Ui ui;
+ private final Storage storage;
+
+ /**
+ * Constructor for an instance of Jelly.
+ *
+ * @param filePath The file path used when saving or starting up the bot. Contains a list of tasks(if any).
+ * @throws Exception If there are any errors while starting up Jelly.
+ */
+ public Jelly(String filePath) {
+ this.storage = new Storage(filePath);
+ this.ui = new Ui();
+ try {
+ this.taskList = new TaskList(storage.startUp());
+ } catch (JellyException e) {
+ this.taskList = new TaskList();
+ System.out.println(e.getMessage());
+ }
+ }
+ public Jelly() {
+ this(FILE_PATH);
+ }
+
+ /**
+ * The main initialiser for the Jelly Chat Bot.
+ *
+ * @param args
+ * @throws JellyException if there are any issues starting up the ChatBot.
+ */
+ public static void main(String[] args) throws JellyException {
+ Jelly jelly = new Jelly(FILE_PATH);
+ jelly.run();
+ }
+ /**
+ * Runs the commands given to the Jelly Chat bot.
+ */
+ private void run() {
+
+ boolean isRunning = true;
+
+ while (isRunning) {
+ String command = ui.commandMe();
+ try {
+ Command c = Parser.parse(command);
+ c.execute(taskList, ui, storage);
+ isRunning = c.isRunning();
+ } catch (JellyException e) {
+ System.out.println(e.getMessage());
+ }
+ }
+ }
+
+ public String getResponse(String input) {
+ String response;
+ try {
+ response = Parser.parse(input).execute(taskList, ui, storage);
+ } catch (JellyException e) {
+ return e.getMessage();
+ }
+ return response;
+ }
+}
diff --git a/src/main/java/jelly/Launcher.java b/src/main/java/jelly/Launcher.java
new file mode 100644
index 0000000000..dd8032800b
--- /dev/null
+++ b/src/main/java/jelly/Launcher.java
@@ -0,0 +1,12 @@
+package jelly;
+
+import javafx.application.Application;
+
+/**
+ * Launcher class to workaround classpath issues.
+ */
+public class Launcher {
+ public static void main(String[] args) {
+ Application.launch(Main.class, args);
+ }
+}
diff --git a/src/main/java/jelly/Main.java b/src/main/java/jelly/Main.java
new file mode 100644
index 0000000000..a471772485
--- /dev/null
+++ b/src/main/java/jelly/Main.java
@@ -0,0 +1,31 @@
+package jelly;
+
+import java.io.IOException;
+
+import javafx.application.Application;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Scene;
+import javafx.scene.layout.AnchorPane;
+import javafx.stage.Stage;
+
+/**
+ * A GUI for Jelly using FXML.
+ */
+public class Main extends Application {
+
+ private Jelly jelly = new Jelly("./jelly.txt");
+
+ @Override
+ public void start(Stage stage) {
+ try {
+ FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("/view/MainWindow.fxml"));
+ AnchorPane ap = fxmlLoader.load();
+ Scene scene = new Scene(ap);
+ stage.setScene(scene);
+ fxmlLoader.getController().setJelly(jelly);
+ stage.show();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/jelly/MainWindow.java b/src/main/java/jelly/MainWindow.java
new file mode 100644
index 0000000000..25891c102a
--- /dev/null
+++ b/src/main/java/jelly/MainWindow.java
@@ -0,0 +1,62 @@
+package jelly;
+
+import javafx.application.Platform;
+import javafx.fxml.FXML;
+import javafx.scene.control.Button;
+import javafx.scene.control.ScrollPane;
+import javafx.scene.control.TextField;
+import javafx.scene.image.Image;
+import javafx.scene.layout.AnchorPane;
+import javafx.scene.layout.VBox;
+import jelly.main.Ui;
+/**
+ * Controller for MainWindow. Provides the layout for the other controls.
+ */
+public class MainWindow extends AnchorPane {
+ @FXML
+ private ScrollPane scrollPane;
+ @FXML
+ private VBox dialogContainer;
+ @FXML
+ private TextField userInput;
+ @FXML
+ private Button sendButton;
+
+ private Jelly jelly;
+
+ private Image userImage = new Image(this.getClass().getResourceAsStream("/images/DaUser.png"));
+ private Image jellyImage = new Image(this.getClass().getResourceAsStream("/images/DaJelly.png"));
+
+ /**
+ * Creates a new Ui to display the startup message,
+ */
+ @FXML
+ public void initialize() {
+ Ui helloUi = new Ui();
+ scrollPane.vvalueProperty().bind(dialogContainer.heightProperty());
+ dialogContainer.getChildren().addAll(DialogBox.getJellyDialog(helloUi.showWelcomeMessage(), jellyImage));
+ }
+
+ public void setJelly(Jelly j) {
+ jelly = j;
+ }
+
+ /**
+ * Creates two dialog boxes, one echoing user input and the other containing Duke's reply and then appends them to
+ * the dialog container. Clears the user input after processing.
+ */
+ @FXML
+ private void handleUserInput() {
+ String input = userInput.getText();
+ String response = jelly.getResponse(input);
+ dialogContainer.getChildren().addAll(
+ DialogBox.getUserDialog(input, userImage),
+ DialogBox.getJellyDialog(response, jellyImage)
+ );
+
+ if (input.equals("bye")) {
+ Platform.exit();
+ }
+ userInput.clear();
+ }
+}
diff --git a/src/main/java/jelly/commands/ByeCommand.java b/src/main/java/jelly/commands/ByeCommand.java
new file mode 100644
index 0000000000..6994bb6eab
--- /dev/null
+++ b/src/main/java/jelly/commands/ByeCommand.java
@@ -0,0 +1,20 @@
+package jelly.commands;
+
+import jelly.main.Storage;
+import jelly.main.TaskList;
+import jelly.main.Ui;
+
+/**
+ * Stops running the jelly Chat Bot.
+ */
+public class ByeCommand extends Command {
+
+ @Override
+ public String execute(TaskList taskList, Ui ui, Storage storage) {
+ return ui.showByeMessage();
+ }
+
+ public boolean isRunning() {
+ return false;
+ }
+}
diff --git a/src/main/java/jelly/commands/Command.java b/src/main/java/jelly/commands/Command.java
new file mode 100644
index 0000000000..8405a52b04
--- /dev/null
+++ b/src/main/java/jelly/commands/Command.java
@@ -0,0 +1,15 @@
+package jelly.commands;
+
+import jelly.main.Storage;
+import jelly.main.TaskList;
+import jelly.main.Ui;
+
+/**
+ * Represents a command that can be executed.
+ */
+public abstract class Command {
+ public boolean isRunning() {
+ return true;
+ }
+ public abstract String execute(TaskList taskList, Ui ui, Storage storage);
+}
diff --git a/src/main/java/jelly/commands/DeadlineCommand.java b/src/main/java/jelly/commands/DeadlineCommand.java
new file mode 100644
index 0000000000..9d9e4aa636
--- /dev/null
+++ b/src/main/java/jelly/commands/DeadlineCommand.java
@@ -0,0 +1,30 @@
+package jelly.commands;
+
+import jelly.main.Storage;
+import jelly.main.TaskList;
+import jelly.main.Ui;
+import jelly.task.Deadline;
+
+/**
+ * Responsible for the logic regarding deadline tasks.
+ */
+public class DeadlineCommand extends Command {
+ private String description;
+ private String byWhen;
+
+ /**
+ * @param description The details of the task.
+ * @param byWhen The deadline of the task.
+ */
+ public DeadlineCommand(String description, String byWhen) {
+ this.description = description;
+ this.byWhen = byWhen;
+ }
+ @Override
+ public String execute(TaskList taskList, Ui ui, Storage storage) {
+ Deadline deadlineTask = new Deadline(description, byWhen);
+ taskList.add(deadlineTask);
+ storage.saveAndExit(taskList);
+ return ui.showTaskAdded(deadlineTask, taskList.size());
+ }
+}
diff --git a/src/main/java/jelly/commands/DeleteCommand.java b/src/main/java/jelly/commands/DeleteCommand.java
new file mode 100644
index 0000000000..eb0c9a8457
--- /dev/null
+++ b/src/main/java/jelly/commands/DeleteCommand.java
@@ -0,0 +1,30 @@
+package jelly.commands;
+
+import jelly.main.Storage;
+import jelly.main.TaskList;
+import jelly.main.Ui;
+import jelly.task.Task;
+
+/**
+ * Deletes a task from the list.
+ */
+public class DeleteCommand extends Command {
+
+ private final int INDEX;
+
+ public DeleteCommand(int index) {
+ INDEX = index;
+ }
+
+ @Override
+ public String execute(TaskList taskList, Ui ui, Storage storage) {
+ assert INDEX > 0 : "Index should be positive.";
+ if (INDEX <= 0 || INDEX > taskList.size()) {
+ return ("Invalid input");
+ }
+ Task t = taskList.get(INDEX - 1);
+ taskList.delete(INDEX - 1);
+ storage.saveAndExit(taskList);
+ return ui.showTaskDeleted(t, taskList.size());
+ }
+}
diff --git a/src/main/java/jelly/commands/EventCommand.java b/src/main/java/jelly/commands/EventCommand.java
new file mode 100644
index 0000000000..854bbdadae
--- /dev/null
+++ b/src/main/java/jelly/commands/EventCommand.java
@@ -0,0 +1,37 @@
+package jelly.commands;
+
+import jelly.main.Storage;
+import jelly.main.TaskList;
+import jelly.main.Ui;
+import jelly.task.Event;
+
+/**
+ * Responsible for the logic regarding event tasks.
+ */
+public class EventCommand extends Command {
+
+ private String description;
+
+ private String fromWhen;
+
+ private String toWhen;
+
+ /**
+ * @param description The details of the event.
+ * @param fromWhen The start date/time of the event.
+ * @param toWhen The end date/time of the event.
+ */
+ public EventCommand(String description, String fromWhen, String toWhen) {
+ this.description = description;
+ this.fromWhen = fromWhen;
+ this.toWhen = toWhen;
+ }
+
+ @Override
+ public String execute(TaskList taskList, Ui ui, Storage storage) {
+ Event eventTask = new Event(description, fromWhen, toWhen);
+ taskList.add(eventTask);
+ storage.saveAndExit(taskList);
+ return ui.showTaskAdded(eventTask, taskList.size());
+ }
+}
diff --git a/src/main/java/jelly/commands/FindCommand.java b/src/main/java/jelly/commands/FindCommand.java
new file mode 100644
index 0000000000..64dd8361e9
--- /dev/null
+++ b/src/main/java/jelly/commands/FindCommand.java
@@ -0,0 +1,30 @@
+package jelly.commands;
+
+import java.util.ArrayList;
+
+import jelly.main.Storage;
+import jelly.main.TaskList;
+import jelly.main.Ui;
+import jelly.task.Task;
+
+/**
+ * Finds the tasks that contain the specified keyword.
+ */
+public class FindCommand extends Command {
+ private String keyword;
+
+ /**
+ * Constructor for FindCommand.
+ *
+ * @param keyword The specified keyword to search for in the task list.
+ */
+ public FindCommand(String keyword) {
+ this.keyword = keyword;
+ }
+
+ @Override
+ public String execute(TaskList taskList, Ui ui, Storage storage) {
+ ArrayList matchingTasks = taskList.find(keyword);
+ return ui.printList(matchingTasks);
+ }
+}
diff --git a/src/main/java/jelly/commands/ListCommand.java b/src/main/java/jelly/commands/ListCommand.java
new file mode 100644
index 0000000000..d5a20712ca
--- /dev/null
+++ b/src/main/java/jelly/commands/ListCommand.java
@@ -0,0 +1,15 @@
+package jelly.commands;
+
+import jelly.main.Storage;
+import jelly.main.TaskList;
+import jelly.main.Ui;
+
+/**
+ * Lists out all the tasks in the data.
+ */
+public class ListCommand extends Command {
+ @Override
+ public String execute(TaskList taskList, Ui ui, Storage storage) {
+ return ui.printList(taskList.getTasks());
+ }
+}
diff --git a/src/main/java/jelly/commands/MarkCommand.java b/src/main/java/jelly/commands/MarkCommand.java
new file mode 100644
index 0000000000..7443951eb7
--- /dev/null
+++ b/src/main/java/jelly/commands/MarkCommand.java
@@ -0,0 +1,30 @@
+package jelly.commands;
+
+import jelly.main.Storage;
+import jelly.main.TaskList;
+import jelly.main.Ui;
+
+/**
+ * Marks a task as done.
+ */
+public class MarkCommand extends Command {
+ private final int INDEX;
+ public MarkCommand(int index) {
+ INDEX = index;
+ }
+
+ @Override
+ public String execute(TaskList taskList, Ui ui, Storage storage) {
+ assert INDEX > 0 : "Index should be positive.";
+ if (INDEX <= 0 || INDEX > taskList.size()) {
+ return ("Invalid input");
+ }
+ if (taskList.get(INDEX - 1).getTaskStatus().equals("X")) {
+ return ("Uh, it appears that you've finished this task o.o");
+ } else {
+ taskList.get(INDEX - 1).markAsDone();
+ storage.saveAndExit(taskList);
+ return ("Good job! I've marked this task as done :)");
+ }
+ }
+}
diff --git a/src/main/java/jelly/commands/PriorityCommand.java b/src/main/java/jelly/commands/PriorityCommand.java
new file mode 100644
index 0000000000..26af2869ac
--- /dev/null
+++ b/src/main/java/jelly/commands/PriorityCommand.java
@@ -0,0 +1,38 @@
+package jelly.commands;
+
+import jelly.main.Storage;
+import jelly.main.TaskList;
+import jelly.main.Ui;
+
+/**
+ * Marks a task as low (3), medium(2), or high priority(1). Default priority of a task is high.
+ */
+public class PriorityCommand extends Command {
+ private final int INDEX;
+ private final int PRIORITY;
+
+ /**
+ * Constructor for a priority command.
+ * @param index Index of the task to change priority.
+ * @param priority Priority that is to be given to the task.
+ */
+ public PriorityCommand(int index, int priority) {
+ INDEX = index;
+ PRIORITY = priority;
+ }
+
+ @Override
+ public String execute(TaskList taskList, Ui ui, Storage storage) {
+ assert INDEX > 0 : "Index should be positive.";
+ assert PRIORITY > 0 && PRIORITY <= 3 : "Priority should be between 1 and 3 inclusive.";
+ if (INDEX <= 0 || INDEX > taskList.size()) {
+ return ("Invalid input");
+ }
+ if (PRIORITY < 1 || PRIORITY > 3) {
+ return ("Invalid input, please input 1, 2 or 3.");
+ }
+ taskList.get(INDEX - 1).changePriority(PRIORITY);
+ storage.saveAndExit(taskList);
+ return ("I've changed the priority of this task to: " + PRIORITY);
+ }
+}
diff --git a/src/main/java/jelly/commands/ToDoCommand.java b/src/main/java/jelly/commands/ToDoCommand.java
new file mode 100644
index 0000000000..1867d477cf
--- /dev/null
+++ b/src/main/java/jelly/commands/ToDoCommand.java
@@ -0,0 +1,26 @@
+package jelly.commands;
+
+import jelly.main.Storage;
+import jelly.main.TaskList;
+import jelly.main.Ui;
+import jelly.task.Todo;
+
+/**
+ * Responsible for logic regarding todo tasks.
+ */
+public class ToDoCommand extends Command {
+ private String description;
+
+ public ToDoCommand(String description) {
+ this.description = description;
+ }
+
+ @Override
+ public String execute(TaskList taskList, Ui ui, Storage storage) {
+ Todo todoTask = new Todo(description);
+ todoTask.changePriority(1);
+ taskList.add(todoTask);
+ storage.saveAndExit(taskList);
+ return ui.showTaskAdded(todoTask, taskList.size());
+ }
+}
diff --git a/src/main/java/jelly/commands/UnmarkCommand.java b/src/main/java/jelly/commands/UnmarkCommand.java
new file mode 100644
index 0000000000..44e2e76dd7
--- /dev/null
+++ b/src/main/java/jelly/commands/UnmarkCommand.java
@@ -0,0 +1,32 @@
+package jelly.commands;
+
+import jelly.main.Storage;
+import jelly.main.TaskList;
+import jelly.main.Ui;
+
+/**
+ * Marks a task as not done.
+ */
+public class UnmarkCommand extends Command {
+
+ private final int INDEX;
+
+ public UnmarkCommand(int index) {
+ INDEX = index;
+ }
+
+ @Override
+ public String execute(TaskList taskList, Ui ui, Storage storage) {
+ assert INDEX > 0 : "Index should be positive.";
+ if (INDEX <= 0 || INDEX > taskList.size()) {
+ return ("Invalid input");
+ }
+ if (taskList.get(INDEX - 1).getTaskStatus().equals(" ")) {
+ return ("Yo,you can't unmark something you haven't done yet o.o");
+ } else {
+ taskList.get(INDEX - 1).markAsUndone();
+ storage.saveAndExit(taskList);
+ return ("Bad job! I've marked this task as not done :(");
+ }
+ }
+}
diff --git a/src/main/java/jelly/exceptions/JellyBlankMessageException.java b/src/main/java/jelly/exceptions/JellyBlankMessageException.java
new file mode 100644
index 0000000000..1a79e2474f
--- /dev/null
+++ b/src/main/java/jelly/exceptions/JellyBlankMessageException.java
@@ -0,0 +1,10 @@
+package jelly.exceptions;
+
+/**
+ * This class handles the case where the task description is empty.
+ */
+public class JellyBlankMessageException extends JellyException {
+ public JellyBlankMessageException(String message) {
+ super("Oops! " + message + " cannot be an empty task...");
+ }
+}
diff --git a/src/main/java/jelly/exceptions/JellyException.java b/src/main/java/jelly/exceptions/JellyException.java
new file mode 100644
index 0000000000..c8b702536e
--- /dev/null
+++ b/src/main/java/jelly/exceptions/JellyException.java
@@ -0,0 +1,10 @@
+package jelly.exceptions;
+
+/**
+ * This is the main class that handles exceptions in the Jelly chatbot.
+ */
+public class JellyException extends Exception {
+ public JellyException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/jelly/exceptions/JellyUnknownCommandException.java b/src/main/java/jelly/exceptions/JellyUnknownCommandException.java
new file mode 100644
index 0000000000..5846b373f2
--- /dev/null
+++ b/src/main/java/jelly/exceptions/JellyUnknownCommandException.java
@@ -0,0 +1,10 @@
+package jelly.exceptions;
+
+/**
+ * Handles the case where the user inputs a command that is unsupported by Jelly chatbot.
+ */
+public class JellyUnknownCommandException extends JellyException {
+ public JellyUnknownCommandException() {
+ super("Oops! I really don't know what you're saying :(");
+ }
+}
diff --git a/src/main/java/jelly/main/Parser.java b/src/main/java/jelly/main/Parser.java
new file mode 100644
index 0000000000..7f9da5b5f6
--- /dev/null
+++ b/src/main/java/jelly/main/Parser.java
@@ -0,0 +1,142 @@
+package jelly.main;
+
+import jelly.commands.ByeCommand;
+import jelly.commands.Command;
+import jelly.commands.DeadlineCommand;
+import jelly.commands.DeleteCommand;
+import jelly.commands.EventCommand;
+import jelly.commands.FindCommand;
+import jelly.commands.ListCommand;
+import jelly.commands.MarkCommand;
+import jelly.commands.PriorityCommand;
+import jelly.commands.ToDoCommand;
+import jelly.commands.UnmarkCommand;
+import jelly.exceptions.JellyBlankMessageException;
+import jelly.exceptions.JellyException;
+import jelly.exceptions.JellyUnknownCommandException;
+
+/**
+ * Responsible for parsing commands from the user, creates a Command object.
+ */
+public class Parser {
+
+ /**
+ * Parses the command inputted.
+ *
+ * @param command The user's input etc. list, bye.
+ * @return An instance of Command that matches the user's input.
+ * @throws JellyException If the input is invalid.
+ */
+ public static Command parse(String command) throws JellyException {
+ assert command != null : "Command cannot be empty";
+ try {
+ String[] stringArray = command.split(" ");
+ if (stringArray[0].equals("bye")) {
+ return new ByeCommand();
+ }
+ if (stringArray[0].equals("list")) {
+ return new ListCommand();
+ } else if (stringArray[0].startsWith("mark")) {
+ if (stringArray.length == 1) {
+ throw new JellyBlankMessageException("mark");
+ }
+ return new MarkCommand(Integer.parseInt(stringArray[1]));
+ } else if (stringArray[0].equals("unmark")) {
+ if (stringArray.length == 1) {
+ throw new JellyBlankMessageException("unmark");
+ }
+ return new UnmarkCommand(Integer.parseInt(stringArray[1]));
+ } else if (stringArray[0].equals("find")) {
+ if (stringArray.length == 1) {
+ throw new JellyBlankMessageException("find");
+ }
+ return new FindCommand(stringArray[1]);
+ } else if (stringArray[0].equals("priority")) {
+ if (stringArray.length == 1) {
+ throw new JellyBlankMessageException("priority");
+ }
+ return new PriorityCommand(Integer.parseInt(stringArray[1]), Integer.parseInt(stringArray[2]));
+ } else if (stringArray[0].equals("todo")) {
+ String toDoString = "";
+ if (stringArray.length == 1) {
+ throw new JellyBlankMessageException("todo");
+ }
+ for (int i = 1; i < stringArray.length; i++) {
+ if (stringArray[i] != null) {
+ toDoString += stringArray[i] + " ";
+ } else {
+ toDoString = toDoString.trim();
+ break;
+ }
+ }
+ return new ToDoCommand(toDoString);
+ } else if (stringArray[0].equals("deadline")) {
+ if (stringArray.length == 1) {
+ throw new JellyBlankMessageException("deadline");
+ }
+
+ String deadlineString = "";
+ String byWhen = "";
+
+ for (int i = 1; i < stringArray.length; i++) {
+ if (stringArray[i] != null) {
+ if (stringArray[i].equals("/by")) {
+ for (int j = i + 1; j < stringArray.length; j++) {
+ byWhen += stringArray[j] + " ";
+ }
+ byWhen = byWhen.trim();
+ break;
+ }
+ deadlineString += stringArray[i] + " ";
+ } else {
+ deadlineString = deadlineString.trim();
+ break;
+ }
+ }
+ return new DeadlineCommand(deadlineString, byWhen);
+ } else if (stringArray[0].equals("event")) {
+ if (stringArray.length == 1) {
+ throw new JellyBlankMessageException("event");
+ }
+
+ String eventString = "";
+ String fromWhen = "";
+ String toWhen = "";
+ //checking if the string contains /from and /to
+ for (int i = 1; i < stringArray.length; i++) {
+ if (stringArray[i] != null) {
+ if (stringArray[i].equals("/from")) {
+ for (int j = i + 1; j < stringArray.length; j++) {
+ if (stringArray[j].equals("/to")) {
+ for (int k = j + 1; k < stringArray.length; k++) {
+ toWhen += stringArray[k] + " ";
+ }
+ toWhen = toWhen.trim();
+ break;
+ }
+ fromWhen += stringArray[j] + " ";
+ }
+ fromWhen = fromWhen.trim();
+ break;
+ }
+ eventString += stringArray[i] + " ";
+ } else {
+ eventString = eventString.trim();
+ break;
+ }
+ }
+ return new EventCommand(eventString, fromWhen, toWhen);
+ } else if (stringArray[0].equals("delete")) {
+ if (stringArray.length == 1) {
+ throw new JellyBlankMessageException("delete");
+ }
+ return new DeleteCommand(Integer.parseInt(stringArray[1]));
+ } else {
+ throw new JellyUnknownCommandException();
+ }
+ } catch (JellyException e) {
+ System.out.println(e.getMessage());
+ }
+ throw new JellyUnknownCommandException();
+ }
+}
diff --git a/src/main/java/jelly/main/Storage.java b/src/main/java/jelly/main/Storage.java
new file mode 100644
index 0000000000..b774024048
--- /dev/null
+++ b/src/main/java/jelly/main/Storage.java
@@ -0,0 +1,112 @@
+package jelly.main;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Scanner;
+
+import jelly.exceptions.JellyException;
+import jelly.task.Deadline;
+import jelly.task.Event;
+import jelly.task.Task;
+import jelly.task.Todo;
+
+/**
+ * Stores and loads tasked based on the specified file path.
+ */
+public class Storage {
+
+ private String filePath;
+
+ /**
+ * Constructor for Storage, based on the specified file path.
+ *
+ * @param filePath The file path used when saving or starting up the bot. Contains a list of tasks(if any).
+ */
+ public Storage(String filePath) {
+ this.filePath = filePath;
+ }
+
+ /**
+ * Starts up the Jelly Bot by loading the tasks from the specified file path.
+ *
+ * @return An ArrayList with all the tasks from the file.
+ * @throws JellyException If there is an error while loading up the file.
+ */
+ public ArrayList startUp() throws JellyException {
+ ArrayList storage = new ArrayList<>();
+ try {
+ File data = new File(filePath);
+
+ if (!data.exists()) {
+ data.getParentFile().mkdirs();
+ return storage;
+ }
+ Scanner sc = new Scanner(data);
+
+ while (sc.hasNextLine()) {
+ String str = sc.nextLine();
+ String[] taskDetails = str.split(" \\| ");
+ Task task = new Task("");
+ if (taskDetails[0].equals("T")) {
+ task = new Todo(taskDetails[2]);
+ if (taskDetails[3].equals("(HIGH)")) {
+ task.changePriority(1);
+ } else if (taskDetails[3].equals("(MEDIUM)")) {
+ task.changePriority(2);
+ } else {
+ task.changePriority(3);
+ }
+ } else if (taskDetails[0].equals("D")) {
+ task = new Deadline(taskDetails[2], taskDetails[3]);
+ if (taskDetails[4].equals("(HIGH)")) {
+ task.changePriority(1);
+ } else if (taskDetails[4].equals("(MEDIUM)")) {
+ task.changePriority(2);
+ } else {
+ task.changePriority(3);
+ }
+ } else if (taskDetails[0].equals("E")) {
+ String[] eventDetails = taskDetails[3].split(" to ");
+ task = new Event(taskDetails[2], eventDetails[0], eventDetails[1]);
+ if (taskDetails[4].equals("(HIGH)")) {
+ task.changePriority(1);
+ } else if (taskDetails[4].equals("(MEDIUM)")) {
+ task.changePriority(2);
+ } else {
+ task.changePriority(3);
+ }
+ } else {
+ System.out.println("Unknown task in file");
+ }
+ if (taskDetails[1].equals("1")) {
+ task.markAsDone();
+ } else {
+ task.markAsUndone();
+ }
+ storage.add(task);
+ }
+ return storage;
+ } catch (IOException e) {
+ throw new JellyException("Error: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Saves all task data into the file.
+ *
+ * @param taskList
+ */
+ public void saveAndExit(TaskList taskList) {
+ try {
+ FileWriter fileWriter = new FileWriter(filePath);
+ for (int i = 0; i < taskList.size(); i++) {
+ fileWriter.write(taskList.get(i).writeToFile() + "\n");
+ }
+ fileWriter.close();
+ } catch (IOException e) {
+ System.out.println("Could not save tasks: " + e.getMessage());
+ }
+ }
+}
diff --git a/src/main/java/jelly/main/TaskList.java b/src/main/java/jelly/main/TaskList.java
new file mode 100644
index 0000000000..1116221699
--- /dev/null
+++ b/src/main/java/jelly/main/TaskList.java
@@ -0,0 +1,109 @@
+package jelly.main;
+
+import java.util.ArrayList;
+
+import jelly.task.Task;
+
+/**
+ * Contains all the commands regarding the list of tasks.
+ */
+public class TaskList {
+
+ private ArrayList taskList;
+
+ /**
+ * Constructor for a new empty tasklist.
+ */
+ public TaskList() {
+ this.taskList = new ArrayList<>();
+ }
+
+ /**
+ * Constructor for a tasklist with existing tasks.
+ *
+ * @param taskList
+ */
+ public TaskList(ArrayList taskList) {
+ this.taskList = taskList;
+ }
+
+ /**
+ * Gets the total number of tasks in the list.
+ *
+ * @return The number of tasks in the list.
+ */
+ public int size() {
+ return taskList.size();
+ }
+
+ /**
+ * Adds a specified task into the list.
+ *
+ * @param task The task to be added into the list.
+ */
+ public void add(Task task) {
+ taskList.add(task);
+ }
+
+ /**
+ * Removes the task at the specified index in the list.
+ *
+ * @param index The index of the task to be removed.
+ */
+ public void delete(int index) {
+ taskList.remove(index);
+ }
+
+ /**
+ * Retrieves the task at the specified index in the list.
+ *
+ * @param index The index of the task to be retrieved.
+ * @return The task that was retrieved.
+ */
+ public Task get(int index) {
+ return taskList.get(index);
+ }
+
+ /**
+ * Getter for the list of tasks.
+ * @return The list of tasks.
+ */
+ public ArrayList getTasks() {
+ return taskList;
+ }
+
+ /**
+ * Marks a task at the specified index of the list, as done.
+ *
+ * @param index The index of the task to be marked as done.
+ */
+ public void markAsDone(int index) {
+ taskList.get(index).markAsDone();
+ }
+
+ /**
+ * Marks a task at the specified index of the list, as not done.
+ *
+ * @param index The index of the task to be marked as not done.
+ */
+ public void markAsUndone(int index) {
+ taskList.get(index).markAsUndone();
+ }
+
+ /**
+ * Filters the list of tasks to correspond to tasks that match the keyword.
+ *
+ * @param keyword The keyword to search for.
+ * @return The arraylist of tasks that contains the keyword specified.
+ */
+ public ArrayList find(String keyword) {
+ ArrayList matchingTasks = new ArrayList<>();
+
+ for (int i = 0; i < taskList.size(); i++) {
+ if (taskList.get(i).getDescription().contains(keyword)) {
+ matchingTasks.add(taskList.get(i));
+ }
+ }
+ return matchingTasks;
+ }
+}
diff --git a/src/main/java/jelly/main/Ui.java b/src/main/java/jelly/main/Ui.java
new file mode 100644
index 0000000000..f9f1934f62
--- /dev/null
+++ b/src/main/java/jelly/main/Ui.java
@@ -0,0 +1,84 @@
+package jelly.main;
+
+import java.util.ArrayList;
+import java.util.Scanner;
+
+import jelly.task.Task;
+
+/**
+ * Responsible for the interface of the Jelly Chat Bot.
+ */
+public class Ui {
+ private final Scanner sc;
+ /**
+ * Constructor for Ui, takes in user input from the keyboard.
+ */
+ public Ui() {
+ sc = new Scanner(System.in);
+ }
+ /**
+ * Prints out a welcome message when the Chat Bot is booted up.
+ */
+ public String showWelcomeMessage() {
+ return ("Hello! I'm Jelly\n"
+ + "What can I do for you?");
+ }
+ /**
+ * Reads the command inputted by the user.
+ *
+ * @return A string of the command inputted.
+ */
+ public String commandMe() {
+ return sc.nextLine();
+ }
+
+ /**
+ * If there is an error, display it to the user.
+ *
+ * @param message The error message.
+ */
+ public String displayErrorMessage(String message) {
+ return (message + "\n");
+ }
+
+ /**
+ * Displays the list of tasks in the storage.
+ *
+ * @param storage The tasklist that is in the storage.
+ */
+ public String printList(ArrayList storage) {
+ String listOfTasks = "Here are the tasks in your list:\n";
+ for (int i = 0; i < storage.size(); i++) {
+ listOfTasks = listOfTasks.concat((i + 1) + "." + storage.get(i).toString() + "\n");
+ }
+ return listOfTasks;
+ }
+ /**
+ * Displays a completion message after successfully adding a task to the list.
+ *
+ * @param addedTask The task that was added.
+ * @param noOfTasks The total number of tasks in the list after adding.
+ */
+ public String showTaskAdded(Task addedTask, int noOfTasks) {
+ return ("Ok! I've added this task: \n" + addedTask.toString() + "\n"
+ + "Now you have " + noOfTasks + " tasks in the list.");
+ }
+
+ /**
+ * Displays a completion message after successfully deleting a task from the list.
+ *
+ * @param deletedTask The task that was deleted.
+ * @param noOfTasks The total number of tasks in the list after deletion.
+ */
+ public String showTaskDeleted(Task deletedTask, int noOfTasks) {
+ return ("Okay, I've removed this task: \n" + deletedTask + "\n"
+ + "Now you have " + noOfTasks + " tasks in the list.");
+ }
+
+ /**
+ * Displays a final message to the user before the Chat Bot shuts down.
+ */
+ public String showByeMessage() {
+ return ("Bye mate! Have a nice day :]");
+ }
+}
diff --git a/src/main/java/jelly/task/Deadline.java b/src/main/java/jelly/task/Deadline.java
new file mode 100644
index 0000000000..d10eae082d
--- /dev/null
+++ b/src/main/java/jelly/task/Deadline.java
@@ -0,0 +1,98 @@
+package jelly.task;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Corresponds to a task with a deadline(date or date and time).
+ */
+public class Deadline extends Task {
+
+ protected String by;
+
+ protected LocalDate deadlineDate;
+
+ protected LocalDateTime deadLineDateAndTime;
+
+ /**
+ * Constructor for a deadline task.
+ *
+ * @param description The description of the task.
+ * @param by When the task is due by.
+ */
+ public Deadline(String description, String by) {
+ super(description);
+ this.deadlineDate = parseDate(by);
+ this.deadLineDateAndTime = parseDateTime(by);
+ this.by = by;
+ }
+
+ @Override
+ public String toString() {
+ if (deadlineDate != null) {
+ String outputDate = deadlineDate.format(DateTimeFormatter.ofPattern("MMM dd yyyy"));
+ return "[D]" + super.toString() + "(by: " + outputDate + ")" + " " + getPriority();
+ } else if (deadLineDateAndTime != null) {
+ String outputDateTime = deadLineDateAndTime.format(DateTimeFormatter.ofPattern("MMM dd yyyy HH:mm"));
+ return "[D]" + super.toString() + "(by: " + outputDateTime + ")" + " " + getPriority();
+ } else {
+ return "[D]" + super.toString() + "(by: " + by + ")" + " " + getPriority();
+ }
+ }
+ @Override
+ public String writeToFile() {
+ String printedStuff = "D | " + (getIsDone() ? "1" : "0") + " | " + getDescription() + " | ";
+ return printedStuff + this.by + " | " + getPriority();
+ }
+
+ /**
+ * Parses the date inputted that corresponds to the formats accepted.
+ *
+ * @param date The due date of the task.
+ * @return The parsed date, or null if the date is in a format that is not accepted.
+ */
+ protected LocalDate parseDate(String date) {
+
+ List formats = new ArrayList<>();
+ formats.add(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+ formats.add(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
+ formats.add(DateTimeFormatter.ofPattern("d/M/yyyy"));
+
+ for (int i = 0; i < formats.size(); i++) {
+ try {
+ return LocalDate.parse(date, formats.get(i));
+ } catch (DateTimeParseException e) {
+ continue;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Parses the date and time inputted that corresponds to the formats accepted.
+ *
+ * @param dateTime The due date and time of the task.
+ * @return The parsed date and time, or null if incorrect format.
+ */
+ protected LocalDateTime parseDateTime(String dateTime) {
+
+ List formats = new ArrayList<>();
+ formats.add(DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm"));
+ formats.add(DateTimeFormatter.ofPattern("dd/MM/yyyy HHmm"));
+ formats.add(DateTimeFormatter.ofPattern("d/MM/yyyy HHmm"));
+ formats.add(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm"));
+
+ for (int i = 0; i < formats.size(); i++) {
+ try {
+ return LocalDateTime.parse(dateTime, formats.get(i));
+ } catch (DateTimeParseException e) {
+ continue;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/jelly/task/Event.java b/src/main/java/jelly/task/Event.java
new file mode 100644
index 0000000000..7f96fcf861
--- /dev/null
+++ b/src/main/java/jelly/task/Event.java
@@ -0,0 +1,112 @@
+package jelly.task;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Corresponds to a task that occurs from a specified time to a specified time.
+ */
+public class Event extends Task {
+
+ protected String from;
+ protected String to;
+
+ protected LocalDate fromDate;
+ protected LocalDate toDate;
+
+ protected LocalDateTime fromDateTime;
+ protected LocalDateTime toDateTime;
+
+ /**
+ * Constructor for an event task.
+ *
+ * @param description The description of the task.
+ * @param from The date/date and time which the task begins.
+ * @param to The date/date and time which the task ends.
+ */
+ public Event(String description, String from, String to) {
+ super(description);
+ this.fromDate = parseDate(from);
+ this.toDate = parseDate(to);
+ this.fromDateTime = parseDateTime(from);
+ this.toDateTime = parseDateTime(to);
+ this.from = from;
+ this.to = to;
+ }
+
+ @Override
+ public String toString() {
+
+ String fromWhen = from;
+ String toWhen = to;
+
+ if (fromDate != null) {
+ fromWhen = fromDate.format(DateTimeFormatter.ofPattern("MMM dd yyyy"));
+ } else if (fromDateTime != null) {
+ fromWhen = fromDateTime.format(DateTimeFormatter.ofPattern("MMM dd yyyy HH:mm"));
+ }
+ if (toDate != null) {
+ toWhen = toDate.format(DateTimeFormatter.ofPattern("MMM dd yyyy"));
+ } else if (toDateTime != null) {
+ toWhen = toDateTime.format(DateTimeFormatter.ofPattern("MMM dd yyyy HH:mm"));
+ }
+ return "[E]" + super.toString() + "(from: " + fromWhen + " to: " + toWhen + ")" + " " + getPriority();
+ }
+
+ @Override
+ public String writeToFile() {
+ return "E | " + (getIsDone() ? "1" : "0") + " | " + getDescription() + " | "
+ + from + " to " + to + " | " + getPriority();
+ }
+
+ /**
+ * Parses the date given for the task.
+ *
+ * @param date The start date of the task.
+ * @return The parsed date, or null if incorrect format.
+ */
+ protected LocalDate parseDate(String date) {
+
+ List formats = new ArrayList<>();
+ formats.add(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+ formats.add(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
+ formats.add(DateTimeFormatter.ofPattern("d/M/yyyy"));
+
+ for (int i = 0; i < formats.size(); i++) {
+ try {
+ return LocalDate.parse(date, formats.get(i));
+ } catch (DateTimeParseException e) {
+ continue;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Parses the date and time given for the task.
+ *
+ * @param dateTime The start date and time of the task.
+ * @return The parsed date and time, or null if incorrect format.
+ */
+ protected LocalDateTime parseDateTime(String dateTime) {
+
+ List formats = new ArrayList<>();
+ formats.add(DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm"));
+ formats.add(DateTimeFormatter.ofPattern("dd/MM/yyyy HHmm"));
+ formats.add(DateTimeFormatter.ofPattern("d/MM/yyyy HHmm"));
+ formats.add(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm"));
+
+ for (int i = 0; i < formats.size(); i++) {
+ try {
+ return LocalDateTime.parse(dateTime, formats.get(i));
+ } catch (DateTimeParseException e) {
+ continue;
+ }
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/jelly/task/Task.java b/src/main/java/jelly/task/Task.java
new file mode 100644
index 0000000000..270c65b85a
--- /dev/null
+++ b/src/main/java/jelly/task/Task.java
@@ -0,0 +1,89 @@
+package jelly.task;
+
+/**
+ * Corresponds to a task.
+ */
+public class Task {
+
+ protected boolean isDone;
+ protected String description;
+ protected int priority = 1;
+
+ /**
+ * Constructor for a task, with description and completion status.
+ *
+ * @param description The description of the task, etc. "Do math homework".
+ */
+ public Task(String description) {
+ assert description != null : "Task description should not be null.";
+ this.description = description;
+ this.isDone = false;
+ }
+
+ /**
+ * Getter for whether a task is done or not.
+ * @return A string "X" if done, empty space " " if not done.
+ */
+ public String getTaskStatus() {
+ return (isDone ? "X" : " ");
+ }
+
+ /**
+ * Getter for task description.
+ * @return A string of the task description.
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Getter for whether task is done or not.
+ * @return A boolean, true if task is done, false if not.
+ */
+ public boolean getIsDone() {
+ return isDone;
+ }
+
+ /**
+ * Marks a task as done, changing isDone boolean to true.
+ */
+ public void markAsDone() {
+ this.isDone = true;
+ }
+
+ /**
+ * Marks a task as not done, changing isDone boolean to false.
+ */
+ public void markAsUndone() {
+ this.isDone = false;
+ }
+
+ /**
+ * Changes the priority of a task.
+ * @param priority The priority of the task; 1 is high, 2 is medium, 3 is low.
+ */
+ public void changePriority(int priority) {
+ this.priority = priority;
+ }
+ public String getPriority() {
+ if (priority == 1) {
+ return "(HIGH)";
+ } else if (priority == 2) {
+ return "(MEDIUM)";
+ } else {
+ return "(LOW)";
+ }
+ }
+ @Override
+ public String toString() {
+ return "[" + getTaskStatus() + "] " + description;
+ }
+
+ /**
+ * Should not happen, as tasks should be either one of these: todo, deadline or event.
+ * @return Error message.
+ */
+ public String writeToFile() {
+ return "Error";
+ }
+}
diff --git a/src/main/java/jelly/task/Todo.java b/src/main/java/jelly/task/Todo.java
new file mode 100644
index 0000000000..495a76c09d
--- /dev/null
+++ b/src/main/java/jelly/task/Todo.java
@@ -0,0 +1,30 @@
+package jelly.task;
+
+/**
+ * Corresponds to a task without any time specified.
+ */
+public class Todo extends Task {
+
+ /**
+ * Constructor for a to do task.
+ *
+ * @param description The description of the task.
+ */
+ public Todo(String description) {
+ super(description);
+ }
+
+ /**
+ * String representation of to do task.
+ *
+ * @return A string with label [T] for to do, and the toString of Task.
+ */
+ public String toString() {
+ return "[T]" + super.toString() + getPriority();
+ }
+
+ @Override
+ public String writeToFile() {
+ return "T | " + (getIsDone() ? "1" : "0") + " | " + getDescription() + " | " + getPriority();
+ }
+}
diff --git a/src/main/resources/images/DaJelly.png b/src/main/resources/images/DaJelly.png
new file mode 100644
index 0000000000..d893658717
Binary files /dev/null and b/src/main/resources/images/DaJelly.png differ
diff --git a/src/main/resources/images/DaUser.png b/src/main/resources/images/DaUser.png
new file mode 100644
index 0000000000..3c82f45461
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..59d16ac91a
--- /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..2ac6dc1c1f
--- /dev/null
+++ b/src/main/resources/view/MainWindow.fxml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/META-INF/MANIFEST.MF b/src/test/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..37e2133f41
--- /dev/null
+++ b/src/test/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: jelly.Jelly
+
diff --git a/src/test/java/jelly/main/StorageTest.java b/src/test/java/jelly/main/StorageTest.java
new file mode 100644
index 0000000000..e3024aa8c3
--- /dev/null
+++ b/src/test/java/jelly/main/StorageTest.java
@@ -0,0 +1,44 @@
+package jelly.main;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+
+import org.junit.jupiter.api.Test;
+
+import jelly.exceptions.JellyException;
+import jelly.task.Deadline;
+import jelly.task.Task;
+import jelly.task.Todo;
+
+
+public class StorageTest {
+ @Test
+ public void startUpTest() throws IOException, JellyException {
+ File tempTasks = File.createTempFile("tempTasks", ".txt");
+
+ String filePath = tempTasks.getAbsolutePath();
+ Storage storage = new Storage(filePath);
+
+ ArrayList taskList = new ArrayList<>();
+ taskList.add(new Todo("Do that"));
+ taskList.get(0).markAsDone();
+ taskList.add(new Deadline("Do this thing", "18/12/2020 1900"));
+
+ TaskList savedList = new TaskList(taskList);
+ storage.saveAndExit(savedList);
+
+ ArrayList loadedList = storage.startUp();
+ tempTasks.deleteOnExit();
+
+ for (int i = 0; i < taskList.size(); i++) {
+ assertEquals(taskList.get(i).getDescription(),
+ loadedList.get(i).getDescription());
+ assertEquals(taskList.get(i).getIsDone(),
+ loadedList.get(i).getIsDone());
+ }
+ }
+
+}
diff --git a/src/test/java/jelly/main/TaskListTest.java b/src/test/java/jelly/main/TaskListTest.java
new file mode 100644
index 0000000000..8a40e1a7ce
--- /dev/null
+++ b/src/test/java/jelly/main/TaskListTest.java
@@ -0,0 +1,29 @@
+package jelly.main;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+import jelly.task.Task;
+import jelly.task.Todo;
+
+public class TaskListTest {
+ @Test
+ public void markTest() {
+ TaskList taskList = new TaskList();
+ Task todo = new Todo("Do this");
+ taskList.add(todo);
+ taskList.markAsDone(0);
+ assertTrue(todo.getIsDone());
+ }
+ @Test
+ public void unmarkTest() {
+ TaskList taskList = new TaskList();
+ Task todo = new Todo("Do this");
+ todo.markAsDone();
+ taskList.add(todo);
+ taskList.markAsUndone(0);
+ assertFalse(todo.getIsDone());
+ }
+}
diff --git a/src/test/java/jelly/task/ToDoTest.java b/src/test/java/jelly/task/ToDoTest.java
new file mode 100644
index 0000000000..959f1b0268
--- /dev/null
+++ b/src/test/java/jelly/task/ToDoTest.java
@@ -0,0 +1,17 @@
+package jelly.task;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+public class ToDoTest {
+ @Test
+ public void dummyTest() {
+ assertEquals(2, 2);
+ }
+
+ @Test
+ public void anotherDummyTest() {
+ assertEquals(4, 4);
+ }
+}
diff --git a/taskData/jelly.txt b/taskData/jelly.txt
new file mode 100644
index 0000000000..ad9428b69b
--- /dev/null
+++ b/taskData/jelly.txt
@@ -0,0 +1 @@
+T | 0 | that | (LOW)
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 657e74f6e7..10e85fdd8b 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -1,7 +1,9 @@
-Hello from
- ____ _
-| _ \ _ _| | _____
-| | | | | | | |/ / _ \
-| |_| | |_| | < __/
-|____/ \__,_|_|\_\___|
-
+Ok! I've added this task:
+[T][ ] read book
+Now you have 1 tasks in the list.
+Ok! I've added this task:
+[D][ ] read a novel (by: 12pm tonight)
+Now you have 2 tasks in the list.
+Ok! I've added this task:
+[E][ ] attend a party (from: 2pm today to: 6.30pm tonight)
+Now you have 3 tasks in the list.
\ No newline at end of file
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index e69de29bb2..28f72bc966 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -0,0 +1,3 @@
+todo read book
+deadline read a novel /by 12pm tonight
+event attend a party /from 2pm today /to 6.30pm tonight
diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh
old mode 100644
new mode 100755
index c9ec870033..f3c5b11673
--- a/text-ui-test/runtest.sh
+++ b/text-ui-test/runtest.sh
@@ -20,7 +20,7 @@ then
fi
# run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT
-java -classpath ../bin Duke < input.txt > ACTUAL.TXT
+java -classpath ../bin Jelly < input.txt > ACTUAL.TXT
# convert to UNIX format
cp EXPECTED.TXT EXPECTED-UNIX.TXT