diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000000..040b81eb93
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,71 @@
+plugins {
+ id "com.github.johnrengelman.shadow" version "5.1.0"
+ id 'java'
+ id 'application'
+ id 'org.javamodularity.moduleplugin' version '1.8.12'
+ id 'org.openjfx.javafxplugin' version '0.0.13'
+ id 'org.beryx.jlink' version '2.25.0'
+}
+
+group 'com.example'
+version '1.0-SNAPSHOT'
+
+repositories {
+ mavenCentral()
+}
+
+ext {
+ junitVersion = '5.9.1'
+}
+
+application {
+ mainClassName = "duke.Launcher"
+}
+
+sourceCompatibility = '11'
+targetCompatibility = '11'
+
+tasks.withType(JavaCompile) {
+ options.encoding = 'UTF-8'
+}
+
+javafx {
+ version = '17.0.2'
+ modules = ['javafx.controls', 'javafx.fxml']
+}
+
+dependencies {
+ String javaFxVersion = '11'
+
+ implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'win'
+ implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'mac'
+ implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'linux'
+ implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'win'
+ implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'mac'
+ implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'linux'
+ implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'win'
+ implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'mac'
+ implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'linux'
+ implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'win'
+ implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'mac'
+ implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'linux'
+
+ testImplementation("org.junit.jupiter:junit-jupiter-api:${junitVersion}")
+ testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${junitVersion}")
+
+}
+
+test {
+ useJUnitPlatform()
+}
+
+jlink {
+ imageZip = project.file("${buildDir}/distributions/app-${javafx.platform.classifier}.zip")
+ options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
+ launcher {
+ name = 'app'
+ }
+}
+jlinkZip {
+ group = 'distribution'
+}
\ No newline at end of file
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
new file mode 100644
index 0000000000..e8ee76467b
--- /dev/null
+++ b/config/checkstyle/checkstyle.xml
@@ -0,0 +1,429 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml
new file mode 100644
index 0000000000..135ea49ee0
--- /dev/null
+++ b/config/checkstyle/suppressions.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/data/duke.txt b/data/duke.txt
new file mode 100644
index 0000000000..aab197bb08
--- /dev/null
+++ b/data/duke.txt
@@ -0,0 +1,3 @@
+T|0|read book
+D|1|go to perth|2023-01-01
+E|0|do tasks|2023-01-01|2023-01-02
\ No newline at end of file
diff --git a/docs/README.md b/docs/README.md
index 8077118ebe..7949ad9497 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -2,28 +2,173 @@
## Features
-### Feature-ABC
+### Feature - Manage your tasks
-Description of the feature.
+The Duke chatbot is able to keep track of all of the tasks in your task list and mark them as done or undone.
-### Feature-XYZ
+You can add or delete tasks as you require.
-Description of the feature.
+
+### Feature - Postpone deadlines
+
+You are able to change the dates of your deadlines should you need to postpone any.
+
+You do not need to delete an old deadline and add a new one to do so.
## Usage
-### `Keyword` - Describe action
+### `Bye` - Terminates session
-Describe the action and its outcome.
+Terminates the current Duke chatbot session.
Example of usage:
-`keyword (optional arguments)`
+`bye`
+
+Expected outcome:
+
+Returns the following goodbye message and closes the application.
+
+```
+Goodbye friend. Hope to see you again soon!
+```
+
+### `list` - Show task list
+Displays the current list of tasks.
+
+Example of usage:
+
+`list`
+
+Expected outcome:
+
+Returns the current list of tasks in the following format:
+```
+Here are the tasks in your list:
+1.[T][ ] task 1
+2.[D][ ] task 2 (by: 2022-01-01)
+3.[E][X] task 3 (at: 2022-02-02)
+
+```
+### `delete` - Remove task
+Removes a task from the task list.
+
+Example of usage:
+
+`delete 3`
+
+Expected outcome:
+
+Removes task 3 from the task list and returns the following message:
+
+```
+Noted. I've removed this task:
+[E][X] task 3 (at: 2022-02-02)
+Now you have 2 tasks in the list.
+```
+### `mark` - Mark task as done
+Marks a task in the task list as done.
+
+Example of usage:
+
+`mark 1`
+
+Expected outcome:
+
+Marks task 1 as done and returns the following message:
+
+```
+Nice! I've marked this task as done:
+[T][X] task 1
+```
+### `unmark` - Mark task as not done
+Marks a task in the task list as not done.
+
+Example of usage:
+
+`unmark 1`
+
+Expected outcome:
+
+Marks task 1 as not done and returns the following message:
+
+```
+Alright! I've marked this task as not done:
+[T][ ] task 1
+```
+### `find` - Find tasks
+Finds tasks in the task list that contain a given keyword.
+
+Example of usage:
+
+`find `
Expected outcome:
-Description of the outcome.
+Returns a list of tasks that contain the keyword in the following format:
+
+```
+Here are the matching tasks in your list:
+1.[T][ ] task containing keyword
+2.[D][ ] task 2 containing keyword (by: 2022-01-01)
+```
+### `todo` - Add todo task
+Adds a todo task to the task list.
+
+Example of usage:
+
+`todo `
+
+Expected outcome:
+
+Adds a todo task to the task list with the given description and returns the following message:
+
+```
+Got it. I've added this task:
+[T][ ]
+Now you have n tasks in the list.
+```
+### `deadline` - Add deadline task
+Adds a deadline task to the task list.
+
+Example of usage:
+
+`deadline /by `
+
+Expected outcome:
+
+Adds a deadline task to the task list with the given description and deadline date and returns the following message:
+
+```
+Got it. I've added this task:
+[D][ ] (by: )
+Now you have n tasks in the list.
+```
+### `event` - Add event task
+Adds an event task to the task list.
+
+Example of usage:
+
+`event /from /to `
+
+Expected outcome:
+
+Adds an event task to the task list with the given description and event date and returns the following message:
+
+```
+Got it. I've added this task:
+[E][ ] (from: to: )
+Now you have n tasks in the list.
+```
+
+### `Postpone` - Postpone a task
+Postpones a task to a new date and time. The task can be a deadline or an event.
+
+Example of usage:
+
+`postpone /to `
+Returns the following message upon successful postponement of the task.
```
-expected output
+Deadline has been changed!
```
diff --git a/docs/Ui.png b/docs/Ui.png
new file mode 100644
index 0000000000..db30c8d7aa
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..7454180f2a
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..ffed3a254e
--- /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-7.2-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000000..744e882ed5
--- /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
+ ;;
+ 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"
+ 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..ac1b06f938
--- /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/settings.gradle b/settings.gradle
new file mode 100644
index 0000000000..972cd8b6b1
--- /dev/null
+++ b/settings.gradle
@@ -0,0 +1,2 @@
+rootProject.name = 'ip'
+
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/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF
new file mode 100644
index 0000000000..6e864153e8
--- /dev/null
+++ b/src/main/java/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Main-Class: duke.Duke
+
diff --git a/src/main/java/duke/DialogBox.java b/src/main/java/duke/DialogBox.java
new file mode 100644
index 0000000000..d183f8252b
--- /dev/null
+++ b/src/main/java/duke/DialogBox.java
@@ -0,0 +1,61 @@
+package duke;
+
+import java.io.IOException;
+import java.util.Collections;
+
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
+import javafx.fxml.FXML;
+import javafx.fxml.FXMLLoader;
+import javafx.geometry.Pos;
+import javafx.scene.Node;
+import javafx.scene.control.Label;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.HBox;
+
+/**
+ * An example of a custom control using FXML.
+ * This control represents a dialog box consisting of an ImageView to represent the speaker's face and a label
+ * containing text from the speaker.
+ */
+public class DialogBox extends HBox {
+ @FXML
+ private Label dialog;
+ @FXML
+ private ImageView displayPicture;
+
+ private DialogBox(String text, Image img) {
+ try {
+ FXMLLoader fxmlLoader = new FXMLLoader(MainWindow.class.getResource("/view/DialogBox.fxml"));
+ fxmlLoader.setController(this);
+ fxmlLoader.setRoot(this);
+ fxmlLoader.load();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ dialog.setText(text);
+ displayPicture.setImage(img);
+ }
+
+ /**
+ * Flips the dialog box such that the ImageView is on the left and text on the right.
+ */
+ private void flip() {
+ ObservableList tmp = FXCollections.observableArrayList(this.getChildren());
+ Collections.reverse(tmp);
+ getChildren().setAll(tmp);
+ setAlignment(Pos.TOP_LEFT);
+ }
+
+ public static DialogBox getUserDialog(String text, Image img) {
+ return new DialogBox(text, img);
+ }
+
+ public static DialogBox getDukeDialog(String text, Image img) {
+ var db = new DialogBox(text, img);
+ db.flip();
+ return db;
+ }
+}
\ 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..c6d5b88148
--- /dev/null
+++ b/src/main/java/duke/Duke.java
@@ -0,0 +1,106 @@
+package duke;
+
+public class Duke {
+
+ private final String FILE_PATH = System.getProperty("user.dir") + "/data/duke.txt";
+ private final Ui ui;
+ private final Storage storage;
+ private final TaskList tasks;
+ private Parser parser;
+
+ /**
+ * Creates a Duke object that references storage from the desired file path
+ */
+ public Duke() {
+ this.ui = new Ui();
+ this.storage = new Storage(FILE_PATH);
+ this.tasks = new TaskList(storage.load());
+ }
+
+ /**
+ * Gets the response from the Duke bot
+ *
+ * @param textInput the input from the user
+ * @return the response from Duke
+ */
+ public String getResponse(String textInput) {
+ if (textInput.equals("hi")) {
+ return this.ui.welcomeUser();
+ }
+ String response;
+ this.parser = new Parser();
+ this.parser.parse(textInput);
+
+ if (this.parser.action.equals("bye")) {
+ response = this.ui.goodbyeUser();
+
+ } else if (this.parser.action.equals("list")) {
+ response = this.ui.listTasks(tasks);
+
+ } else if (this.parser.action.equals("delete")) {
+ response = this.tasks.delete(textInput);
+ this.storage.writeTxt(tasks);
+
+ } else if (this.parser.action.equals("mark")) {
+ response = this.tasks.mark(textInput);
+ this.storage.writeTxt(tasks);
+
+ } else if (this.parser.action.equals("unmark")) {
+ response = this.tasks.unmark(textInput);
+ this.storage.writeTxt(tasks);
+
+ } else if (this.parser.action.equals("find")) {
+ try {
+ String[] parts = textInput.split(" ", 2);
+ response = this.tasks.find(parts);
+ } catch (DukeException e) {
+ response = e.toString();
+ }
+
+ } else if (this.parser.action.equals("todo")) {
+ try {
+ String[] parts = textInput.split(" ", 2);
+ response = this.tasks.todo(parts);
+ this.storage.writeTxt(tasks);
+ } catch (DukeException e) {
+ response = e.toString();
+ }
+
+ } else if (this.parser.action.equals("deadline")) {
+ try {
+ String[] parts = textInput.split("/");
+ assert parts.length >= 2 : "Invalid input for deadline task";
+ response = this.tasks.deadline(parts);
+ this.storage.writeTxt(tasks);
+ } catch (AssertionError e) {
+ response = e.toString();
+ }
+
+ } else if (this.parser.action.equals("event")) {
+ try {
+ String[] parts = textInput.split("/");
+ assert parts.length >= 3 : "Invalid input for event task";
+ response = this.tasks.event(parts);
+ this.storage.writeTxt(tasks);
+ } catch (AssertionError e) {
+ response = e.toString();
+ }
+
+ } else if (this.parser.action.equals("postpone")) {
+ try {
+ String[] parts = textInput.split("/");
+ assert parts.length >= 2 : "Invalid input for event task";
+ response = this.tasks.postpone(parts);
+ this.storage.writeTxt(tasks);
+ } catch (DukeException e) {
+ response = e.toString();
+ }
+
+ } else {
+ response = "☹ OOPS!!! I'm sorry, but I don't know what that means :-(";
+ }
+
+ return response;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/duke/DukeException.java b/src/main/java/duke/DukeException.java
new file mode 100644
index 0000000000..181e951dee
--- /dev/null
+++ b/src/main/java/duke/DukeException.java
@@ -0,0 +1,16 @@
+package duke;
+
+/**
+ * An exception for any errors in the Duke chat operation
+ */
+public class DukeException extends Exception{
+
+ /**
+ * Creates an exception for the Duke chat
+ *
+ * @param e description of the exception to be thrown
+ */
+ public DukeException(String e) {
+ super(e);
+ }
+}
\ 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..5483e63637
--- /dev/null
+++ b/src/main/java/duke/Launcher.java
@@ -0,0 +1,12 @@
+package duke;
+
+import javafx.application.Application;
+
+/**
+ * A launcher class to workaround classpath issues.
+ */
+public class Launcher {
+ public static void main(String[] args) {
+ Application.launch(Main.class, args);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/duke/Main.java b/src/main/java/duke/Main.java
new file mode 100644
index 0000000000..71ed8cb9ef
--- /dev/null
+++ b/src/main/java/duke/Main.java
@@ -0,0 +1,32 @@
+package duke;
+
+import java.io.IOException;
+
+import javafx.application.Application;
+import javafx.application.Platform;
+import javafx.fxml.FXMLLoader;
+import javafx.scene.Scene;
+import javafx.scene.layout.AnchorPane;
+import javafx.stage.Stage;
+
+/**
+ * A GUI for Duke using FXML.
+ */
+public class Main extends Application {
+
+ private Duke duke = new Duke();
+
+ @Override
+ public void start(Stage stage) {
+ try {
+ FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("/view/MainWindow.fxml"));
+ AnchorPane ap = fxmlLoader.load();
+ Scene scene = new Scene(ap);
+ stage.setScene(scene);
+ fxmlLoader.getController().setDuke(duke);
+ stage.show();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/duke/MainWindow.java b/src/main/java/duke/MainWindow.java
new file mode 100644
index 0000000000..82b227f632
--- /dev/null
+++ b/src/main/java/duke/MainWindow.java
@@ -0,0 +1,62 @@
+package duke;
+
+import javafx.animation.PauseTransition;
+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 javafx.util.Duration;
+/**
+ * Controller for MainWindow. Provides the layout for the other controls.
+ */
+public class MainWindow extends AnchorPane {
+ @FXML
+ private ScrollPane scrollPane;
+ @FXML
+ private VBox dialogContainer;
+ @FXML
+ private TextField userInput;
+ @FXML
+ private Button sendButton;
+
+ private Duke duke;
+
+ private Image userImage = new Image(this.getClass().getResourceAsStream("/images/Walle.jpeg"));
+ private Image dukeImage = new Image(this.getClass().getResourceAsStream("/images/Eve.jpeg"));
+
+ @FXML
+ public void initialize() {
+ scrollPane.vvalueProperty().bind(dialogContainer.heightProperty());
+ }
+
+ public void setDuke(Duke d) {
+ duke = d;
+ dialogContainer.getChildren().addAll(
+ DialogBox.getDukeDialog(duke.getResponse("hi"), dukeImage)
+ );
+ }
+
+ /**
+ * 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 and closes when user says bye.
+ */
+ @FXML
+ private void handleUserInput() {
+ String input = userInput.getText();
+ String response = duke.getResponse(input);
+ dialogContainer.getChildren().addAll(
+ DialogBox.getUserDialog(input, userImage),
+ DialogBox.getDukeDialog(response, dukeImage)
+ );
+ userInput.clear();
+ if (input.equals("bye")) {
+ PauseTransition delay = new PauseTransition(Duration.seconds(3));
+ delay.setOnFinished(event -> Platform.exit());
+ delay.play();
+ }
+ }
+}
\ 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..bacf8309b1
--- /dev/null
+++ b/src/main/java/duke/Parser.java
@@ -0,0 +1,47 @@
+package duke;
+
+/**
+ * A parser that helps to process user inputs into actions to follow up
+ */
+public class Parser {
+ String action;
+
+ /**
+ * Parses the user's input to determine the next action to take
+ *
+ * @oaram textInput the input message from the user
+ */
+ public void parse(String textInput) {
+ if (textInput.equalsIgnoreCase("bye")) {
+ this.action = "bye";
+ } else if (textInput.equalsIgnoreCase("list")) {
+ this.action = "list";
+ } else if (textInput.length() >= 8 &&
+ textInput.substring(0, 6).equalsIgnoreCase("delete")) {
+ this.action = "delete";
+ } else if (textInput.length() >= 6 &&
+ textInput.substring(0, 4).equalsIgnoreCase("mark")) {
+ this.action = "mark";
+ } else if (textInput.length() >= 8 &&
+ textInput.substring(0, 6).equalsIgnoreCase("unmark")) {
+ this.action = "unmark";
+ } else if (textInput.length() >= 6 &&
+ textInput.substring(0, 4).equalsIgnoreCase("find")) {
+ this.action = "find";
+ } else if (textInput.length() >= 4 &&
+ textInput.substring(0, 4).equalsIgnoreCase("todo")) {
+ this.action = "todo";
+ } else if (textInput.length() >= 10 &&
+ textInput.substring(0, 8).equalsIgnoreCase("deadline")) {
+ this.action = "deadline";
+ } else if (textInput.length() >= 7 &&
+ textInput.substring(0, 5).equalsIgnoreCase("event")) {
+ this.action = "event";
+ } else if (textInput.length() >= 10 &&
+ textInput.substring(0, 8).equalsIgnoreCase("postpone")) {
+ this.action = "postpone";
+ } else {
+ this.action = "not found";
+ }
+ }
+}
diff --git a/src/main/java/duke/Storage.java b/src/main/java/duke/Storage.java
new file mode 100644
index 0000000000..a8af7ae442
--- /dev/null
+++ b/src/main/java/duke/Storage.java
@@ -0,0 +1,77 @@
+package duke;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * A storage object that stores the file location of the txt file to be used to log tasks
+ */
+public class Storage {
+ private final String FILE_PATH;
+
+ /**
+ * Creates a new Storage object
+ *
+ * @param filePath the txt file to be referenced as storage
+ */
+ public Storage(String filePath) {
+ this.FILE_PATH = filePath;
+ }
+
+ /**
+ * Loads the tasks as an ArrayList from a referenced Storage object's txt file
+ *
+ * @return ArrayList of the referenced Storage object
+ */
+ public ArrayList load() {
+ ArrayList taskList = new ArrayList<>();
+ try (BufferedReader reader = new BufferedReader(new FileReader(FILE_PATH))) {
+ String line;
+ while ((line = reader.readLine()) != null) {
+ String[] parts = line.split("\\|");
+ if (parts[0].strip().equalsIgnoreCase("T")) {
+ Task t = new Task.Todo(parts[2]);
+ taskList.add(t);
+ if (parts[1].strip().equalsIgnoreCase("1")) {
+ t.markDone();
+ }
+ } else if (parts[0].strip().equalsIgnoreCase("D")) {
+ Task t = new Task.Deadline(parts[2], parts[3]);
+ taskList.add(t);
+ if (parts[1].strip().equalsIgnoreCase("1")) {
+ t.markDone();
+ }
+ } else {
+ Task t = new Task.Event(parts[2], parts[3], parts[4]);
+ taskList.add(t);
+ if (parts[1].strip().equalsIgnoreCase("1")) {
+ t.markDone();
+ }
+ }
+ }
+ return taskList;
+ } catch (IOException e) {
+ System.out.println("An error occurred while reading the file: " + e.getMessage());
+ return new ArrayList<>();
+ }
+ }
+
+ /**
+ * Writes a TaskList into the Storage object's txt file
+ *
+ * @param list the TaskList to be written into the referenced Storage object's txt file
+ */
+ public void writeTxt(TaskList list) {
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(FILE_PATH))) {
+ String toWrite = list.toWrite();
+ writer.write(toWrite);
+ } catch (IOException e) {
+ System.out.println("An error occurred while writing to the file: " + e.getMessage());
+ }
+ }
+
+}
diff --git a/src/main/java/duke/Task.java b/src/main/java/duke/Task.java
new file mode 100644
index 0000000000..5c85732efc
--- /dev/null
+++ b/src/main/java/duke/Task.java
@@ -0,0 +1,207 @@
+package duke;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * Contains all information for tasks in the task list
+ */
+public class Task {
+ protected String description;
+ protected boolean isDone;
+
+ /**
+ * Creates a task object with a specific description
+ *
+ * @param description what the task is about
+ */
+ public Task(String description) {
+ this.description = description;
+ this.isDone = false;
+ }
+
+ /**
+ * Returns the txt formatted version of the referenced tasks
+ *
+ * @return txt formatted String of the referenced task
+ */
+ public String toData() {
+ return "";
+ }
+
+ public boolean postponeDeadline(String to) {
+ return false;
+ }
+
+ public static class Todo extends Task {
+
+ /**
+ * Creates to-do object of the given description
+ *
+ * @param description what the to-do object is about
+ */
+ public Todo(String description) {
+ super(description.strip());
+ }
+
+ /**
+ * Returns the txt formatted version of the referenced to-do task
+ *
+ * @return the txt formatted version of the referenced to-do task
+ */
+ @Override
+ public String toData() {
+ int isDoneData = 0;
+ if (this.isDone) {
+ isDoneData = 1;
+ }
+ return String.format("T|%d|%s", isDoneData, this.description);
+ }
+
+ /**
+ * Returns the String of the referenced to-do task
+ *
+ * @return the String of the referenced to-do task
+ */
+ @Override
+ public String toString() {
+ return "[T]" + super.toString();
+ }
+ }
+
+ public static class Deadline extends Task {
+
+ protected LocalDate by;
+
+ /**
+ * Creates deadline object of the given description and finishing date
+ *
+ * @param description the description of the task
+ * @param by the deadline that the class is to be completed
+ */
+ public Deadline(String description, String by) {
+ super(description.strip());
+ this.by = LocalDate.parse(by.strip());
+ }
+
+ /**
+ * Changes the current deadline to a later date
+ *
+ * @param to the date to postpone to
+ * @return boolean for whether the date was changed
+ */
+ @Override
+ public boolean postponeDeadline(String to) {
+ LocalDate postponeDate = LocalDate.parse(to);
+ if (postponeDate.isAfter(this.by)) {
+ this.by = postponeDate;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the txt formatted version of the referenced deadline task
+ *
+ * @return the txt formatted version of the referenced deadline task
+ */
+ @Override
+ public String toData() {
+ int isDoneData = 0;
+ if (this.isDone) {
+ isDoneData = 1;
+ }
+ return String.format("D|%d|%s|%s", isDoneData, this.description, this.by);
+ }
+
+ /**
+ * Returns the String of the referenced deadline task
+ *
+ * @return the String of the referenced deadline task
+ */
+ @Override
+ public String toString() {
+ String byFormatted = by.format(DateTimeFormatter.ofPattern("MMM d yyyy"));
+ return "[D]" + super.toString() + " (by: " + byFormatted + ")";
+ }
+ }
+
+ public static class Event extends Task {
+
+ protected LocalDate from;
+ protected LocalDate to;
+
+ /**
+ * Creates an event object of the given description and time period
+ *
+ * @param description the description of the task
+ * @param from the start of the event
+ * @param to the end of the event
+ */
+ public Event(String description, String from, String to) {
+ super(description.strip());
+ this.from = LocalDate.parse(from.strip());
+ this.to = LocalDate.parse(to.strip());
+
+ }
+
+ /**
+ * Returns the txt formatted version of the referenced event task
+ *
+ * @return the txt formatted version of the referenced event task
+ */
+ @Override
+ public String toData() {
+ int isDoneData = 0;
+ if (this.isDone) {
+ isDoneData = 1;
+ }
+ return String.format("E|%d|%s|%s|%s", isDoneData, this.description, this.from, this.to);
+ }
+
+ /**
+ * Returns the String of the referenced event task
+ *
+ * @return the String of the referenced event task
+ */
+ @Override
+ public String toString() {
+ String fromFormatted = from.format(DateTimeFormatter.ofPattern("MMM d yyyy"));
+ String toFormatted = to.format(DateTimeFormatter.ofPattern("MMM d yyyy"));
+ return "[E]" + super.toString() + " (from: " + fromFormatted + " to: " + toFormatted + ")";
+ }
+ }
+
+ /**
+ * Returns the status of the referenced task
+ *
+ * @return String representation of the status of the referenced task
+ */
+ public String getStatusIcon() {
+ return (isDone ? "X" : " ");
+ }
+
+ /**
+ * Marks the current task as done
+ */
+ public void markDone() {
+ this.isDone = true;
+ }
+
+ /**
+ * Marks the current task as undone
+ */
+ public void markUndone() {
+ this.isDone = false;
+ }
+
+ /**
+ * Returns the String of the referenced task
+ *
+ * @return the String of the referenced task
+ */
+ @Override
+ public String toString() {
+ return String.format("[%s] %s", this.getStatusIcon(), this.description);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/duke/TaskList.java b/src/main/java/duke/TaskList.java
new file mode 100644
index 0000000000..afc3d60554
--- /dev/null
+++ b/src/main/java/duke/TaskList.java
@@ -0,0 +1,186 @@
+package duke;
+
+//import javafx.application.Application;
+//import javafx.scene.Scene;
+//import javafx.scene.control.Label;
+//import javafx.stage.Stage;
+
+import java.time.LocalDate;
+import java.util.ArrayList;
+
+/**
+ * A task list that handles operations from the user to manage their tasks and interact with storage
+ */
+public class TaskList {
+ private ArrayList taskList;
+
+ /**
+ * Creates a new task list object to handle operations from the user
+ *
+ * @param taskList the initialised task list from the storage txt file
+ */
+ public TaskList(ArrayList taskList) {
+ this.taskList = taskList;
+ }
+
+ /**
+ * Takes in a user text input, processes it to delete a record, and returns the response message
+ *
+ * @param textInput the input message from the user
+ * @return the response message to be printed
+ */
+ public String delete(String textInput) {
+ int i = Integer.parseInt(textInput.substring(7));
+ Task t = taskList.get(i - 1);
+ taskList.remove(i - 1);
+ String removedText = String.format("Got it. I've removed this task: %s\n", t.toString());
+ String listSize = String.format("Now you have %d tasks in the list", taskList.size());
+ return removedText + listSize;
+ }
+
+ /**
+ * Takes in a user text input, processes it to mark a record as completed, and returns the response message
+ *
+ * @param textInput the input message from the user
+ * @return the response message to be printed
+ */
+ public String mark(String textInput) {
+ int i = Integer.parseInt(textInput.substring(5));
+ Task currTask = taskList.get(i - 1);
+ currTask.markDone();
+ return "Nice! I've marked this task as done\n" + currTask;
+ }
+
+ /**
+ * Takes in a user text input, processes it to mark a record as uncompleted, and returns the response message
+ *
+ * @param textInput the input message from the user
+ * @return the response message to be printed
+ */
+ public String unmark(String textInput) {
+ int i = Integer.parseInt(textInput.substring(7));
+ Task currTask = taskList.get(i - 1);
+ currTask.markUndone();
+ return "OK, I've marked this task as not done yet:\n" + currTask;
+ }
+
+ /**
+ * Takes in a user text input, processes it to find matching records, and returns the response message
+ *
+ * @param parts the input message from the user
+ * @return the response message to be printed
+ * @throws DukeException if no find keyword is given
+ */
+ public String find(String... parts) throws DukeException {
+ if (parts.length == 1 || parts[1].equals("")) {
+ throw new DukeException("☹ OOPS!!! The description of find command cannot be empty.");
+ }
+ String keyword = "(.*)" + parts[1] + "(.*)";
+ String result = "Here are the matching tasks in your list:\n";
+ boolean found = false;
+ int index = 1;
+ for (int i = 0; i < taskList.size(); i++) {
+ String description = taskList.get(i).toString();
+ if (description.matches(keyword)) {
+ found = true;
+ String output = String.format("%d. %s", index, description + "\n");
+ result += output;
+ index++;
+ }
+ }
+ return found ? result.trim() : "Sorry, there are no matching tasks :-(";
+ }
+
+ /**
+ * Takes in a user text input, processes it add a to-do task, and returns the response message
+ *
+ * @param parts the input message from the user
+ * @return the response message to be printed
+ * @throws DukeException if the text input is invalid
+ */
+ public String todo(String... parts) throws DukeException {
+ if (parts.length == 1 || parts[1].equals("")) {
+ throw new DukeException("☹ OOPS!!! The description of a todo cannot be empty.");
+ }
+ Task t = new Task.Todo(parts[1].trim());
+ taskList.add(t);
+ return String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t, taskList.size());
+ }
+
+ /**
+ * Takes in a user text input, processes it add a deadline task, and returns the response message
+ *
+ * @param parts the input message from the user
+ * @return the response message to be printed
+ */
+ public String deadline(String... parts) {
+ Task t = new Task.Deadline(parts[0].substring(9), parts[1].substring(3));
+ taskList.add(t);
+ return String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t, taskList.size());
+ }
+
+ /**
+ * Takes in a user text input, processes it add an event task, and returns the response message
+ *
+ * @param parts the input message from the user
+ * @return the response message to be printed
+ */
+ public String event(String... parts) {
+ Task t = new Task.Event(parts[0].substring(6), parts[1].substring(5), parts[2].substring(3));
+ taskList.add(t);
+ return String.format("Got it. I've added this task:\n%s\nNow you have %d tasks in the list", t, taskList.size());
+ }
+
+ public String postpone(String... parts) throws DukeException {
+ String keyword = "(.*)" + parts[0].substring(9).trim() + "(.*)";
+ boolean found = false;
+ String result = "";
+ for (int i = 0; i < taskList.size(); i++) {
+ Task t = taskList.get(i);
+ if (t.toString().matches(keyword)) {
+ found = true;
+ boolean isChanged = t.postponeDeadline(parts[1].substring(3).trim());
+ if (isChanged) {
+ result = "Deadline has been changed!";
+ } else {
+ result = "Invalid postpone date! Must be after the current deadline.";
+ }
+ }
+ }
+ if (!found) {
+ result = "No such deadline!";
+ }
+ return result;
+ }
+
+ /**
+ * Processes the current TaskList object into a string formatted for txt storage
+ *
+ * @return the referenced TaskList object as a string formatted for txt storage
+ */
+ public String toWrite() {
+ int length = this.taskList.size();
+ String result = "";
+ for (int i = 0; i < length; i++) {
+ String item = taskList.get(i).toData();
+ result += item + "\n";
+ }
+ return result.trim();
+ }
+
+ /**
+ * Returns the String representation of the referenced TaskList
+ *
+ * @return the String representation of the TaskList
+ */
+ @Override
+ public String toString() {
+ String result = "";
+ for (int i = 0; i < taskList.size(); i++) {
+ String description = taskList.get(i).toString();
+ String output = String.format("%d. %s", i + 1, description + "\n");
+ result += output;
+ }
+ return result.trim();
+ }
+}
diff --git a/src/main/java/duke/Ui.java b/src/main/java/duke/Ui.java
new file mode 100644
index 0000000000..dce5d5bad7
--- /dev/null
+++ b/src/main/java/duke/Ui.java
@@ -0,0 +1,37 @@
+package duke;
+
+/**
+ * Handles interactions with the user
+ */
+public class Ui {
+ private final String WELCOME_MESSAGE = "Hey Buddy, I'm Duke\nWhat can I do for you?";
+ private final String GOODBYE_MESSAGE = "Goodbye friend. Hope to see you again soon!";
+
+ /**
+ * Returns the welcome message to the user upon starting
+ *
+ * @return the welcome message
+ */
+ public String welcomeUser() {
+ return WELCOME_MESSAGE;
+ }
+
+ /**
+ * Returns the goodbye message to the user upon termination
+ *
+ * @return the goodbye message
+ */
+ public String goodbyeUser() {
+ return GOODBYE_MESSAGE;
+ }
+
+ /**
+ * Returns all the tasks inside a TaskList object
+ *
+ * @param taskList the TaskList object to be listed to the interface
+ * @return the string representation of the TaskList object
+ */
+ public String listTasks(TaskList taskList) {
+ return taskList.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/css/style.css b/src/main/resources/css/style.css
new file mode 100644
index 0000000000..726734aece
--- /dev/null
+++ b/src/main/resources/css/style.css
@@ -0,0 +1,15 @@
+.message {
+ -fx-background-color: #007AFF;
+ -fx-background-radius: 10;
+ -fx-padding: 10;
+ -fx-text-fill: white;
+ -fx-font-family: "monospace";
+}
+
+.user-message {
+ -fx-background-color: #FFCC00;
+}
+
+.bot-message {
+ -fx-background-color: #007AFF;
+}
diff --git a/src/main/resources/images/Eve.jpeg b/src/main/resources/images/Eve.jpeg
new file mode 100644
index 0000000000..f71d041c3e
Binary files /dev/null and b/src/main/resources/images/Eve.jpeg differ
diff --git a/src/main/resources/images/Walle.jpeg b/src/main/resources/images/Walle.jpeg
new file mode 100644
index 0000000000..144603ec2c
Binary files /dev/null and b/src/main/resources/images/Walle.jpeg differ
diff --git a/src/main/resources/view/DialogBox.fxml b/src/main/resources/view/DialogBox.fxml
new file mode 100644
index 0000000000..4829e9cf77
--- /dev/null
+++ b/src/main/resources/view/DialogBox.fxml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml
new file mode 100644
index 0000000000..832f84382e
--- /dev/null
+++ b/src/main/resources/view/MainWindow.fxml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/java/duke/ParserTest.java b/src/test/java/duke/ParserTest.java
new file mode 100644
index 0000000000..7d2139301e
--- /dev/null
+++ b/src/test/java/duke/ParserTest.java
@@ -0,0 +1,31 @@
+package duke;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class ParserTest {
+ @Test
+ public void parseTodoTest(){
+ String textInput = "todo read book";
+ Parser p = new Parser();
+ p.parse(textInput);
+ assertEquals(p.action, "todo");
+ }
+
+ @Test
+ public void parseDeadlineTest(){
+ String textInput = "deadline return book /by 2023-01-01";
+ Parser p = new Parser();
+ p.parse(textInput);
+ assertEquals(p.action, "deadline");
+ }
+
+ @Test
+ public void parseEventTest(){
+ String textInput = "event career fair /from 2023-01-01 /to 2023-01-02";
+ Parser p = new Parser();
+ p.parse(textInput);
+ assertEquals(p.action, "event");
+ }
+}
diff --git a/src/test/java/duke/TaskTest.java b/src/test/java/duke/TaskTest.java
new file mode 100644
index 0000000000..83084bc5c6
--- /dev/null
+++ b/src/test/java/duke/TaskTest.java
@@ -0,0 +1,14 @@
+package duke;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class TaskTest {
+ @Test
+ public void toStringTest(){
+ Task t1 = new Task("read book");
+ String result = "[ ] read book";
+ assertEquals(t1.toString(), result);
+ }
+}
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 657e74f6e7..47ec9d13eb 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -1,7 +1,3 @@
-Hello from
- ____ _
-| _ \ _ _| | _____
-| | | | | | | |/ / _ \
-| |_| | |_| | < __/
-|____/ \__,_|_|\_\___|
-
+Hello I'm Duke
+What can I do for you?
+☹ 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..5ab2f8a432 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -0,0 +1 @@
+Hello
\ No newline at end of file
diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh
index c9ec870033..30a4d732db 100644
--- a/text-ui-test/runtest.sh
+++ b/text-ui-test/runtest.sh
@@ -13,14 +13,14 @@ 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/shane/Documents/NUS Y2S2/CS2103/ip/src/main/src/main/java -Xlint:none -d /Users/shane/Documents/NUS Y2S2/CS2103/ip/src/main/bin /Users/shane/Documents/NUS Y2S2/CS2103/ip/src/main/java/*.java
then
echo "********** BUILD FAILURE **********"
exit 1
fi
# run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT
-java -classpath ../bin Duke < input.txt > ACTUAL.TXT
+java -classpath /Users/shane/Documents/NUS Y2S2/CS2103/ip/src/main/bin Duke < input.txt > ACTUAL.TXT
# convert to UNIX format
cp EXPECTED.TXT EXPECTED-UNIX.TXT