diff --git a/build.gradle b/build.gradle
new file mode 100644
index 0000000000..001c9e0351
--- /dev/null
+++ b/build.gradle
@@ -0,0 +1,62 @@
+plugins {
+ id 'java'
+ id 'application'
+ id 'com.github.johnrengelman.shadow' version '7.1.2'
+ id 'checkstyle'
+}
+
+checkstyle {
+ toolVersion = '10.2'
+}
+
+repositories {
+ mavenCentral()
+}
+
+dependencies {
+ 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'
+ 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'
+}
+
+test {
+ useJUnitPlatform()
+
+ testLogging {
+ events "passed", "skipped", "failed"
+
+ showExceptions true
+ exceptionFormat "full"
+ showCauses true
+ showStackTraces true
+ showStandardStreams = false
+ }
+}
+
+application {
+ mainClass.set("mysutong.Launcher")
+}
+
+shadowJar {
+ archiveFileName = "mysutong.jar"
+ archiveBaseName = "mysutong"
+ archiveClassifier = null
+}
+
+run{
+ standardInput = System.in
+ enableAssertions = true
+}
\ No newline at end of file
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
new file mode 100644
index 0000000000..eb761a9b9a
--- /dev/null
+++ b/config/checkstyle/checkstyle.xml
@@ -0,0 +1,434 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml
new file mode 100644
index 0000000000..39efb6e4ac
--- /dev/null
+++ b/config/checkstyle/suppressions.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
diff --git a/data/duke.txt b/data/duke.txt
new file mode 100644
index 0000000000..894b296745
--- /dev/null
+++ b/data/duke.txt
@@ -0,0 +1,2 @@
+T | 0 | borrow book
+D | 0 | return book | 2019-12-02T18:00
diff --git a/data/tasks.txt b/data/tasks.txt
new file mode 100644
index 0000000000..2c67cd0bcc
--- /dev/null
+++ b/data/tasks.txt
@@ -0,0 +1,3 @@
+T | 0 | CS2103T IP | 2
+D | 0 | CS2100 Assignment 1 | 24/9/2024 2359 | 3
+T | 0 | 功课 | 3
diff --git a/docs/README.md b/docs/README.md
index 47b9f984f7..8b408ffee5 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,30 +1,178 @@
-# Duke User Guide
+# MySutong User Guide
-// Update the title above to match the actual product name
+![img.png](Ui.png)
-// Product screenshot goes here
+Welcome to **MySutong**! MySutong is a personal chatbot that helps you keep track of your daily tasks. You can add
+different types of tasks, mark them as done, or tag them for easy reference. Sammy can also help you manage deadlines
+and events.
+---
+## Quick start
-// Product intro goes here
+1. Ensure you have Java 17 or above installed in your computer. You can install it from [here](https://www.oracle.com/java/technologies/downloads/#jdk17-windows)
+2. Download the latest `.jar` file from [here](https://github.com/yu-sutong/ip/releases)
+3. Copy the file to the folder you want to use as the *home folder* of your task list.
+4. Open a command terminal, `cd` into the folder you put the jar file in, and type `java -jar mysutong.jar` then press `enter` to run the application.
+5. Type your command in the text field at the bottom and press `Enter` or "Send" to execute it.
+## Features
-## Adding deadlines
+## 1. Add a Task: `todo`
+Adds a simple task to your task list.
-// Describe the action and its outcome.
+Format: todo `TASK_DESCRIPTION`
-// Give examples of usage
+Example:
+```
+todo CS2103T IP
+```
+
+Parameter:
+- TASKDESCRIPTION is compulsory and must be a non-empty string
+---
+## 2. Adding a Task with a Deadline: `deadline`
+
+Adds a task with a deadline to your task list.
+
+Format: `deadline TASK_DESCRIPTION /by DATE`
+
+Example:
+```
+deadline submit CS2103T IP /by 23/9/2024 2359
+```
+
+Parameter:
+- TASK_DESCRIPTION and DATE are compulsory and must be a non-empty string.
+- DATE must be in the form of dd/mm/yyyy where dd and mm can be a single or double digits.
+---
+## 3. Adding an Event: `event`
+
+Adds an event with a start and end date/time to your task list.
+
+Format: `event TASK_DESCRIPTION /from DATE /to DATE`
+
+Example:
+```
+event project meeting /from 23/9/2024 14:00 /to 23/9/2024 16:00
+```
+
+Parameter:
+- TASK_DESCRIPTION and DATE are compulsory and must be a non-empty string.
+- DATE must be in the form of dd/mm/yyyy where dd and mm can be a single or double digits.
+---
+## 4. Listing All Tasks: `list`
+
+Displays all the tasks in your task list.
+
+Format: `list`
+
+Example:
+```
+list
+```
+---
+## 5. Deleting a Task: `delete`
+
+Deletes a task from your task list.
+
+Format: `delete INDEX`
+- `INDEX` refers to the position of the task in the list, starting from 1.
+
+Example:
+```
+delete 2
+```
+This deletes the 2nd task in your list.
+
+Parameter:
+- INDEX must be a positive integer and less than or equal to the total number of tasks in your list.
+- INDEX starts from 1 (the first task on the list).
+---
+## 6. Marking a Task as Done: `mark`
+
+Marks a task as done.
+
+Format: `mark INDEX`
+
+Example:
+```
+mark 2
+```
+This marks the 2nd task in your list as done.
+
+Parameter:
+- INDEX must be a positive integer and less than or equal to the total number of tasks in your list.
+- INDEX starts from 1 (the first task on the list).
+---
+## 7. Unmarking a Task: `unmark`
-Example: `keyword (optional arguments)`
+Unmarks a task, making it incomplete again.
-// A description of the expected outcome goes here
+Format: `unmark INDEX`
+Example:
```
-expected output
+unmark 2
```
+This unmarks the 2nd task, making it incomplete.
-## Feature ABC
+Parameter:
+- INDEX must be a positive integer and less than or equal to the total number of tasks in your list.
+- INDEX starts from 1 (the first task on the list).
+---
+## 8. Find matching tasks: `find`
-// Feature details
+Find matching tasks in your list based on the keyword.
+Format: `find KEYWORD`
+
+Example:
+```
+find assignment
+```
-## Feature XYZ
+Parameter:
+- KEYWORD must be a non-empty string.
+---
+## 9. Giving your task a priority: `priority`
+
+Give your task (based on the INDEX) a priority tag (based on PRIORITY_NO.
+When PRIORITY_NO = 1, the tag is "High".
+When PRIORITY_NO = 2, the tag is "Medium".
+When PRIORITY_NO = 3, the tag is "Low".
+The default tag for each task if "Low".
+
+Format: `priority INDEX PRIORITY_NO`
+
+Example:
+```
+priority 2 1
+```
+
+Parameter:
+- INDEX must be a positive integer and less than or equal to the total number of tasks in your list.
+- INDEX of the task starts from 1.
+- PRIORITY_NO must be a integer from 1 to 3.
+## 10. Exiting the Program: `bye`
+
+Exits the chatbot.
+
+Format: `bye`
+
+Example:
+```
+bye
+```
+---
-// Feature details
\ No newline at end of file
+## Command Summary
+| Action | Format, Examples |
+|--------------------------------|-------------------------------------------------------------------------------------------------------------------------------|
+| **Add a Task** | `todo TASK_DESCRIPTION`
Example: `todo read a book` |
+| **Add a Task with a Deadline** | `deadline TASK_DESCRIPTION /by DATE`
Example: `deadline submit assignment /by 2024-09-30` |
+| **Add an Event** | `event TASK_DESCRIPTION /from DATE /to DATE`
Example: `event project meeting /from 2024-09-21 14:00 /to 2024-09-21 16:00` |
+| **List Tasks** | `list`
Example: `list` |
+| **Delete a Task** | `delete INDEX`
Example: `delete 3` |
+| **Mark a Task** | `mark INDEX`
Example: `mark 2` |
+| **Unmark a Task** | `unmark INDEX`
Example: `unmark 2` |
+| **Finding matching tasks** | `find KEYWORD`
Example: `find assignment` |
+| **Giving task a priority** | `priority INDEX PRIORITY_NO`
Example: `priority 2 1` |
+| **Exit** | `bye`
Example: `bye` |
diff --git a/docs/Ui.png b/docs/Ui.png
new file mode 100644
index 0000000000..0c407523e9
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/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/mysutong/Deadline.java b/src/main/java/mysutong/Deadline.java
new file mode 100644
index 0000000000..e61ca9534f
--- /dev/null
+++ b/src/main/java/mysutong/Deadline.java
@@ -0,0 +1,65 @@
+package mysutong;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * Represents a deadline task with a specific date and time by which the task must be completed.
+ * Extends {@link Task}.
+ */
+public class Deadline extends Task {
+ /**
+ * The date and time by which the task must be completed.
+ */
+ private LocalDateTime by;
+
+ /**
+ * Constructs a new Deadline with the default priority (low).
+ *
+ * @param description The description of the deadline task.
+ * @param by The date and time by which the deadline task must be completed.
+ */
+ public Deadline(String description, LocalDateTime by) {
+ super(description);
+ this.by = by;
+ }
+
+ /**
+ * Constructs a new Deadline with a specific priority.
+ *
+ * @param description The description of the deadline task.
+ * @param by The date and time by which the deadline task must be completed.
+ * @param priority The priority level (1 for high, 2 for medium, 3 for low).
+ */
+ public Deadline(String description, LocalDateTime by, int priority) {
+ super(description);
+ this.by = by;
+ setPriority(priority); // Set the priority using the method from the superclass.
+ }
+
+ /**
+ * Returns a string representation of the deadline, including its description,
+ * its due date formatted as "MMM d yyyy h:mma", and the priority.
+ *
+ * @return A string representation of the deadline.
+ */
+ @Override
+ public String toString() {
+ return "[D]" + super.toString() + " (by: " + by.format(DateTimeFormatter.ofPattern("MMM d yyyy h:mma")) + ")";
+ }
+
+ /**
+ * Returns a string suitable for file storage, representing the deadline task with its completion status,
+ * description, due date formatted as "d/M/yyyy HHmm", and priority.
+ *
+ * @return A formatted string suitable for file storage.
+ */
+ @Override
+ public String toFileString() {
+ return String.format("D | %d | %s | %s | %d",
+ (isDone ? 1 : 0),
+ description,
+ by.format(DateTimeFormatter.ofPattern("d/M/yyyy HHmm")),
+ getPriority());
+ }
+}
diff --git a/src/main/java/mysutong/DialogBox.java b/src/main/java/mysutong/DialogBox.java
new file mode 100644
index 0000000000..7844c0db16
--- /dev/null
+++ b/src/main/java/mysutong/DialogBox.java
@@ -0,0 +1,85 @@
+package mysutong;
+
+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;
+
+/**
+ * Represents a dialog box consisting of an ImageView to represent the speaker's face
+ * and a label containing text from the speaker.
+ * This class manages the layout of dialog boxes for both the user and Duke in the GUI.
+ */
+public class DialogBox extends HBox {
+ @FXML
+ private Label dialog; // The label containing the dialog text.
+ @FXML
+ private ImageView displayPicture; // The ImageView displaying the speaker's image.
+
+ /**
+ * Constructs a DialogBox with the specified text and image.
+ * This loads the FXML file and sets the text and image for the dialog box.
+ *
+ * @param text The text to display in the dialog box.
+ * @param img The image to display next to the dialog.
+ */
+ 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 is on the right.
+ * This is used for differentiating the dialog box of Duke (flipped) from the user's dialog box (normal).
+ */
+ private void flip() {
+ ObservableList tmp = FXCollections.observableArrayList(this.getChildren());
+ Collections.reverse(tmp);
+ getChildren().setAll(tmp);
+ setAlignment(Pos.TOP_LEFT); // Align the flipped dialog box to the top left.
+ }
+
+ /**
+ * Creates a dialog box for the user's input.
+ * The user's dialog box is not flipped (ImageView on the right, text on the left).
+ *
+ * @param text The text entered by the user.
+ * @param img The image representing the user.
+ * @return A DialogBox representing the user's input.
+ */
+ public static DialogBox getUserDialog(String text, Image img) {
+ return new DialogBox(text, img);
+ }
+
+ /**
+ * Creates a dialog box for Duke's response.
+ * Duke's dialog box is flipped (ImageView on the left, text on the right).
+ *
+ * @param text The text of Duke's response.
+ * @param img The image representing Duke.
+ * @return A DialogBox representing Duke's response, with the ImageView flipped to the left.
+ */
+ public static DialogBox getDukeDialog(String text, Image img) {
+ var db = new DialogBox(text, img);
+ db.flip();
+ return db;
+ }
+}
diff --git a/src/main/java/mysutong/Event.java b/src/main/java/mysutong/Event.java
new file mode 100644
index 0000000000..2b955c2245
--- /dev/null
+++ b/src/main/java/mysutong/Event.java
@@ -0,0 +1,76 @@
+package mysutong;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * Represents an event task with specific start and end dates and times.
+ * Extends {@link Task}.
+ */
+public class Event extends Task {
+ /**
+ * The starting date and time of the event.
+ */
+ private LocalDateTime from;
+
+ /**
+ * The ending date and time of the event.
+ */
+ private LocalDateTime to;
+
+ /**
+ * Constructs a new Event with the default priority (low).
+ *
+ * @param description The description of the event task.
+ * @param from The starting date and time of the event.
+ * @param to The ending date and time of the event.
+ */
+ public Event(String description, LocalDateTime from, LocalDateTime to) {
+ super(description);
+ this.from = from;
+ this.to = to;
+ }
+
+ /**
+ * Constructs a new Event with a specific priority.
+ *
+ * @param description The description of the event task.
+ * @param from The starting date and time of the event.
+ * @param to The ending date and time of the event.
+ * @param priority The priority level (1 for high, 2 for medium, 3 for low).
+ */
+ public Event(String description, LocalDateTime from, LocalDateTime to, int priority) {
+ super(description);
+ this.from = from;
+ this.to = to;
+ setPriority(priority); // Set the priority using the method from the superclass.
+ }
+
+ /**
+ * Returns a string representation of the event, including its description, priority,
+ * start and end dates formatted as "MMM d yyyy h:mma".
+ *
+ * @return A string representation of the event.
+ */
+ @Override
+ public String toString() {
+ return "[E]" + super.toString() + " (from: " + from.format(DateTimeFormatter.ofPattern("MMM d yyyy h:mma"))
+ + " to: " + to.format(DateTimeFormatter.ofPattern("MMM d yyyy h:mma")) + ")";
+ }
+
+ /**
+ * Returns a string suitable for file storage, representing the event task with its completion status,
+ * description, start and end dates formatted as "d/M/yyyy HHmm", and priority.
+ *
+ * @return A formatted string suitable for file storage.
+ */
+ @Override
+ public String toFileString() {
+ return String.format("E | %d | %s | %s | %s | %d",
+ (isDone ? 1 : 0),
+ description,
+ from.format(DateTimeFormatter.ofPattern("d/M/yyyy HHmm")),
+ to.format(DateTimeFormatter.ofPattern("d/M/yyyy HHmm")),
+ getPriority());
+ }
+}
diff --git a/src/main/java/mysutong/InvalidTaskNumberException.java b/src/main/java/mysutong/InvalidTaskNumberException.java
new file mode 100644
index 0000000000..1e4cfdbbea
--- /dev/null
+++ b/src/main/java/mysutong/InvalidTaskNumberException.java
@@ -0,0 +1,17 @@
+package mysutong;
+
+/**
+ * Exception thrown when an invalid task number is used in operations that require a valid task index.
+ * Extends {@link SutongException}.
+ */
+class InvalidTaskNumberException extends SutongException {
+
+ /**
+ * Constructs a new InvalidTaskNumberException with the specified detail message.
+ *
+ * @param message the detail message, providing more information about the exception context.
+ */
+ public InvalidTaskNumberException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/mysutong/Launcher.java b/src/main/java/mysutong/Launcher.java
new file mode 100644
index 0000000000..02dee82478
--- /dev/null
+++ b/src/main/java/mysutong/Launcher.java
@@ -0,0 +1,25 @@
+package mysutong;
+
+import javafx.application.Application;
+
+/**
+ * A launcher class to workaround classpath issues.
+ *
+ * This class serves as an entry point to launch the JavaFX application.
+ * It exists primarily to address classpath issues that might occur when launching
+ * the application directly from certain environments (like IDEs or build tools).
+ * The `main` method calls `Application.launch()`, which internally starts the
+ * JavaFX application lifecycle.
+ */
+public class Launcher {
+
+ /**
+ * The main method that serves as the entry point for the Java application.
+ * It launches the JavaFX application by calling {@link Application#launch(Class, String...)}.
+ *
+ * @param args The command-line arguments passed to the application.
+ */
+ public static void main(String[] args) {
+ Application.launch(Main.class, args);
+ }
+}
diff --git a/src/main/java/mysutong/Main.java b/src/main/java/mysutong/Main.java
new file mode 100644
index 0000000000..42e858f44f
--- /dev/null
+++ b/src/main/java/mysutong/Main.java
@@ -0,0 +1,47 @@
+package mysutong;
+
+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 MySutong using FXML.
+ *
+ * This class is the entry point for the JavaFX application.
+ * It extends {@link javafx.application.Application} and sets up the main window
+ * for the GUI using FXML.
+ */
+public class Main extends Application {
+
+ private MySutong mysutong = new MySutong("data/tasks.txt");
+
+ /**
+ * Starts the JavaFX application.
+ * This method is called when the JavaFX application is launched.
+ * It loads the FXML layout for the main window, sets up the scene,
+ * and displays the GUI.
+ *
+ * @param stage The primary stage for this application, onto which
+ * the application scene can be set.
+ */
+ @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);
+
+ // Inject the MySutong instance into the controller
+ fxmlLoader.getController().setMySutong(mysutong);
+ stage.setTitle("MySutong");
+ stage.show();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/src/main/java/mysutong/MainWindow.java b/src/main/java/mysutong/MainWindow.java
new file mode 100644
index 0000000000..fabde36d93
--- /dev/null
+++ b/src/main/java/mysutong/MainWindow.java
@@ -0,0 +1,68 @@
+package mysutong;
+
+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;
+
+/**
+ * Controller for the main GUI.
+ * This class is responsible for managing user interactions in the JavaFX GUI,
+ * such as handling user input and displaying responses from MySutong.
+ */
+public class MainWindow extends AnchorPane {
+ @FXML
+ private ScrollPane scrollPane; // ScrollPane to display the conversation between the user and MySutong.
+ @FXML
+ private VBox dialogContainer; // VBox to hold dialog boxes.
+ @FXML
+ private TextField userInput; // TextField for the user to type input.
+ @FXML
+ private Button sendButton; // Button to submit the user input.
+
+ private MySutong mysutong; // Instance of MySutong to process user commands.
+
+ private Image userImage = new Image(this.getClass().getResourceAsStream("/images/DaUser.png"));
+ private Image dukeImage = new Image(this.getClass().getResourceAsStream("/images/DaDuke.png"));
+ /**
+ * Initializes the controller.
+ * This method binds the ScrollPane's scroll value to the height of the dialog container,
+ * ensuring that the latest dialog is always visible when the user interacts with the GUI.
+ */
+ @FXML
+ public void initialize() {
+ scrollPane.vvalueProperty().bind(dialogContainer.heightProperty());
+ dialogContainer.getChildren().addAll(DialogBox.getDukeDialog("Hello there." , dukeImage));
+ }
+
+ /**
+ * Injects the MySutong instance into this controller.
+ * This method is used to pass the MySutong object from the main application into the controller
+ * so that the controller can delegate user input processing to MySutong.
+ *
+ * @param m The MySutong instance to be used by this controller.
+ */
+ public void setMySutong(MySutong m) {
+ mysutong = m;
+ }
+
+ /**
+ * Handles user input by creating dialog boxes for both the user input and MySutong's response.
+ * This method is triggered when the user submits a command. It processes the command, gets the response from
+ * MySutong, and displays both the input and response as dialog boxes in the dialog container. The user's input
+ * field is then cleared.
+ */
+ @FXML
+ private void handleUserInput() {
+ String input = userInput.getText();
+ String response = mysutong.getResponse(input);
+ dialogContainer.getChildren().addAll(
+ DialogBox.getUserDialog(input, userImage),
+ DialogBox.getDukeDialog(response, dukeImage)
+ );
+ userInput.clear();
+ }
+}
diff --git a/src/main/java/mysutong/MySutong.java b/src/main/java/mysutong/MySutong.java
new file mode 100644
index 0000000000..a5ed92524f
--- /dev/null
+++ b/src/main/java/mysutong/MySutong.java
@@ -0,0 +1,86 @@
+package mysutong;
+
+import java.io.IOException;
+
+/**
+ * Main class for the MySutong application, which manages tasks.
+ * This class is responsible for initializing the application, loading existing tasks from storage,
+ * and handling user interactions through a command loop or a GUI.
+ */
+public class MySutong {
+ private Storage storage;
+ private TaskList tasks;
+ private Ui ui;
+
+ /**
+ * Constructs a new instance of MySutong with a specified file path for storage.
+ * Initializes the user interface, storage, and task list. If there is an error loading the tasks from storage,
+ * an empty task list will be initialized, and an error will be shown in the UI.
+ *
+ * @param filePath the path to the file where tasks are stored.
+ */
+ public MySutong(String filePath) {
+ ui = new Ui();
+ storage = new Storage(filePath);
+ try {
+ tasks = new TaskList(storage.load());
+ } catch (IOException e) {
+ ui.showLoadingError();
+ tasks = new TaskList(); // Initialize with an empty list if loading fails
+ ui.showError("Failed to load tasks from file: " + e.getMessage());
+ } catch (Exception e) {
+ ui.showError("An unexpected error occurred: " + e.getMessage());
+ tasks = new TaskList(); // Safeguard: Initialize an empty list on any other exceptions
+ }
+ }
+
+ /**
+ * Runs the main loop of the application.
+ * Continuously reads user commands from the CLI, delegates execution of the commands to the {@link Parser},
+ * and displays the output through the {@link Ui}. This loop continues until the application is terminated.
+ * It handles any exceptions that may occur during command execution and displays them via the UI.
+ */
+ public void run() {
+ ui.showWelcome();
+ Parser parser = new Parser();
+ while (true) {
+ try {
+ String fullCommand = ui.readCommand();
+ parser.executeCommand(fullCommand, tasks, ui, storage);
+ } catch (Exception e) {
+ ui.showError("An unexpected error occurred during command execution: " + e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Gets a response from MySutong for the given user input.
+ * This method is used in the GUI to process user input, delegate the command to the {@link Parser},
+ * and return the output as a string. It captures any errors that occur and returns them as part of the response.
+ *
+ * @param input The user input/command to be processed.
+ * @return The response from MySutong after executing the given command.
+ */
+ public String getResponse(String input) {
+ Parser parser = new Parser();
+ try {
+ // Create a custom Ui to capture the output as a string
+ Ui responseUi = new Ui();
+ parser.executeCommand(input, tasks, responseUi, storage);
+ return responseUi.getResponse(); // Get the captured output from Ui
+ } catch (Exception e) {
+ return "An error occurred: " + e.getMessage();
+ }
+ }
+
+ /**
+ * The entry point of the MySutong application.
+ * Initializes and runs the application with a predefined path for task storage.
+ * This method starts the CLI version of MySutong.
+ *
+ * @param args command-line arguments (not used).
+ */
+ public static void main(String[] args) {
+ new MySutong("data/tasks.txt").run();
+ }
+}
diff --git a/src/main/java/mysutong/NoDescriptionException.java b/src/main/java/mysutong/NoDescriptionException.java
new file mode 100644
index 0000000000..4285a59bb3
--- /dev/null
+++ b/src/main/java/mysutong/NoDescriptionException.java
@@ -0,0 +1,17 @@
+package mysutong;
+
+/**
+ * Exception thrown when a required description is missing for a task or operation.
+ * Extends {@link SutongException}.
+ */
+class NoDescriptionException extends SutongException {
+
+ /**
+ * Constructs a new NoDescriptionException with the specified detail message.
+ *
+ * @param message the detail message, providing more information about why the exception was thrown.
+ */
+ public NoDescriptionException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/mysutong/Parser.java b/src/main/java/mysutong/Parser.java
new file mode 100644
index 0000000000..4b8f6f990e
--- /dev/null
+++ b/src/main/java/mysutong/Parser.java
@@ -0,0 +1,28 @@
+package mysutong;
+
+/**
+ * The {@code Parser} class interprets and executes user commands within the MySutong application.
+ * It processes the input commands and delegates execution to the {@code TaskList} for task-specific operations.
+ */
+public class Parser {
+
+ /**
+ * Executes a user command by parsing it and delegating it to the {@code TaskList} to handle.
+ *
+ * @param fullCommand the raw input command from the user.
+ * @param tasks the current task list to operate on.
+ * @param ui the UI handler to provide feedback to the user.
+ * @param storage the storage handler to save/load tasks from persistent storage.
+ */
+ public void executeCommand(String fullCommand, TaskList tasks, Ui ui, Storage storage) {
+ String[] inputs = fullCommand.split(" ", 2);
+ assert (inputs.length > 0);
+ String command = inputs[0];
+
+ try {
+ tasks.handleCommand(command, inputs.length > 1 ? inputs[1].trim() : "", ui, storage);
+ } catch (Exception e) {
+ ui.showError(e.getMessage());
+ }
+ }
+}
diff --git a/src/main/java/mysutong/Storage.java b/src/main/java/mysutong/Storage.java
new file mode 100644
index 0000000000..6a5d861e88
--- /dev/null
+++ b/src/main/java/mysutong/Storage.java
@@ -0,0 +1,123 @@
+package mysutong;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+
+/**
+ * Handles file-based storage operations for the MySutong application, including loading and saving tasks.
+ * Now supports saving and loading task priority.
+ */
+public class Storage {
+ private final String filePath;
+
+ /**
+ * Constructs a new Storage instance with the specified file path.
+ *
+ * @param filePath the path to the file where tasks are stored and retrieved.
+ */
+ public Storage(String filePath) {
+ this.filePath = filePath;
+ }
+
+ /**
+ * Loads tasks from the file specified by {@code filePath}.
+ * Creates the file and its directories if they do not already exist.
+ * Parses the file to reconstruct task objects based on their saved format.
+ *
+ * @return a list of {@link Task} objects loaded from the file.
+ * @throws IOException if an I/O error occurs when opening or creating the file.
+ */
+ public List load() throws IOException {
+ File file = new File(filePath);
+ if (!file.exists()) {
+ File parentDir = file.getParentFile();
+ if (parentDir != null && !parentDir.exists()) {
+ parentDir.mkdirs();
+ }
+ file.createNewFile();
+ return new ArrayList<>(); // Return an empty list if file is newly created.
+ }
+
+ Scanner scanner = new Scanner(file);
+ ArrayList tasks = new ArrayList<>();
+
+ while (scanner.hasNextLine()) {
+ String[] parts = scanner.nextLine().split(" \\| ");
+ String taskType = parts[0];
+ boolean isDone = parts[1].equals("1");
+ String description = parts[2];
+ int priority = Integer.parseInt(parts[parts.length - 1]); // Priority is the last part
+
+ Task task = parseTask(parts, taskType, description, isDone, priority);
+ tasks.add(task);
+ }
+ scanner.close();
+ return tasks;
+ }
+
+ /**
+ * Saves the current state of tasks to the file specified by {@code filePath}.
+ * Ensures that the directory structure for the file exists, creating it if necessary.
+ *
+ * @param tasks the {@link TaskList} containing tasks to be saved.
+ * @throws IOException if an I/O error occurs when writing to the file.
+ */
+ public void save(TaskList tasks) throws IOException {
+ File file = new File(filePath);
+ File parentDir = file.getParentFile();
+ if (parentDir != null && !parentDir.exists()) {
+ parentDir.mkdirs();
+ }
+
+ BufferedWriter writer = new BufferedWriter(new FileWriter(filePath));
+ for (Task task : tasks.getTasks()) {
+ writer.write(task.toFileString());
+ writer.newLine();
+ }
+ writer.close();
+ }
+
+ /**
+ * Helper method to parse task data from loaded strings and create task objects.
+ * Now includes priority when creating task objects.
+ *
+ * @param parts the array of string parts from a split line of task data.
+ * @param taskType the type of the task ('T', 'D', 'E').
+ * @param description the description of the task.
+ * @param isDone the completion status of the task.
+ * @param priority the priority of the task (1 for high, 2 for medium, 3 for low).
+ * @return the constructed Task object.
+ * @throws IllegalStateException if the task type is unknown.
+ */
+ private Task parseTask(String[] parts, String taskType, String description, boolean isDone, int priority) {
+ Task task;
+ switch (taskType) {
+ case "T":
+ task = new Todo(description);
+ break;
+ case "D":
+ LocalDateTime deadlineDate = LocalDateTime.parse(parts[3], DateTimeFormatter.ofPattern("d/M/yyyy HHmm"));
+ task = new Deadline(description, deadlineDate);
+ break;
+ case "E":
+ LocalDateTime eventStart = LocalDateTime.parse(parts[3], DateTimeFormatter.ofPattern("d/M/yyyy HHmm"));
+ LocalDateTime eventEnd = LocalDateTime.parse(parts[4], DateTimeFormatter.ofPattern("d/M/yyyy HHmm"));
+ task = new Event(description, eventStart, eventEnd);
+ break;
+ default:
+ throw new IllegalStateException("Unknown task type: " + taskType);
+ }
+ if (isDone) {
+ task.markAsDone();
+ }
+ task.setPriority(priority); // Set the priority from file
+ return task;
+ }
+}
diff --git a/src/main/java/mysutong/SutongException.java b/src/main/java/mysutong/SutongException.java
new file mode 100644
index 0000000000..232cd235ee
--- /dev/null
+++ b/src/main/java/mysutong/SutongException.java
@@ -0,0 +1,17 @@
+package mysutong;
+
+/**
+ * Custom exception class for the MySutong application, used to handle application-specific errors.
+ * Extends {@link Exception}.
+ */
+class SutongException extends Exception {
+
+ /**
+ * Constructs a new SutongException with the specified detail message.
+ *
+ * @param message the detail message, providing more information about why the exception was thrown.
+ */
+ public SutongException(String message) {
+ super(message);
+ }
+}
diff --git a/src/main/java/mysutong/Task.java b/src/main/java/mysutong/Task.java
new file mode 100644
index 0000000000..669c21a767
--- /dev/null
+++ b/src/main/java/mysutong/Task.java
@@ -0,0 +1,111 @@
+package mysutong;
+
+/**
+ * Represents a general task in the MySutong application.
+ * This class provides the base structure and functionalities for task objects,
+ * including support for priorities (1 for high, 2 for medium, and 3 for low).
+ */
+public class Task {
+ protected String description; // Description of the task.
+ protected boolean isDone; // Status of the task, whether it is completed or not.
+ protected int priority; // Priority of the task (1 = high, 2 = medium, 3 = low).
+
+ /**
+ * Constructs a new Task with a specific description.
+ *
+ * @param description The description of the task.
+ */
+ public Task(String description) {
+ this.description = description;
+ this.isDone = false; // By default, the task is not completed.
+ this.priority = 3; // Default priority is low (3).
+ }
+
+ /**
+ * Returns the completion status of the task.
+ *
+ * @return true if the task is completed, otherwise false.
+ */
+ public boolean isDone() {
+ return isDone;
+ }
+
+ /**
+ * Returns a status icon indicating whether the task is completed.
+ * 'X' represents completed, and a space represents incomplete.
+ *
+ * @return a string representing the completion status icon.
+ */
+ public String getStatusIcon() {
+ return (isDone ? "X" : " "); // 'X' for done, ' ' for not done.
+ }
+
+ /**
+ * Marks the task as completed.
+ */
+ public void markAsDone() {
+ isDone = true;
+ }
+
+ /**
+ * Marks the task as not completed.
+ */
+ public void unmark() {
+ isDone = false;
+ }
+
+ /**
+ * Sets the priority of the task.
+ *
+ * @param priority The priority level (1 for high, 2 for medium, 3 for low).
+ */
+ public void setPriority(int priority) {
+ if (priority < 1 || priority > 3) {
+ throw new IllegalArgumentException("Priority must be 1 (high), 2 (medium), or 3 (low).");
+ }
+ this.priority = priority;
+ }
+
+ /**
+ * Gets the priority of the task.
+ *
+ * @return the priority level of the task (1 for high, 2 for medium, 3 for low).
+ */
+ public int getPriority() {
+ return priority;
+ }
+
+ /**
+ * Returns a string representation of the priority level.
+ *
+ * @return a string representing the priority of the task.
+ */
+ public String getPriorityString() {
+ switch (priority) {
+ case 1: return "High";
+ case 2: return "Medium";
+ case 3: return "Low";
+ default: return "Unknown";
+ }
+ }
+
+ /**
+ * Returns a string representation suitable for file storage.
+ * This method includes the priority of the task in the storage format.
+ *
+ * @return a formatted string representing the task for file storage.
+ */
+ public String toFileString() {
+ return String.format("%s | %d | %s | %d", this.getClass().getSimpleName().charAt(0), (isDone ? 1 : 0), description, priority);
+ }
+
+ /**
+ * Returns a string representation of the task, including its status, description, and priority.
+ *
+ * @return a string representation of the task.
+ */
+ @Override
+ public String toString() {
+ return "[" + getStatusIcon() + "] " + description + " (Priority: " + getPriorityString() + ")";
+ }
+}
diff --git a/src/main/java/mysutong/TaskList.java b/src/main/java/mysutong/TaskList.java
new file mode 100644
index 0000000000..5ed36a76b8
--- /dev/null
+++ b/src/main/java/mysutong/TaskList.java
@@ -0,0 +1,297 @@
+package mysutong;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a list of tasks in the MySutong application. This class provides methods
+ * to manage tasks such as adding, removing, and retrieving tasks based on their index.
+ * It also supports searching for tasks based on a keyword found in the task's description.
+ * Additionally, it now handles commands like add, mark, unmark, delete, and set priority.
+ */
+public class TaskList {
+ private final List tasks; // The list of tasks, stored as a generic List interface.
+
+ /**
+ * Constructs a new TaskList using an existing list of tasks.
+ * This allows for initializing the TaskList with a predefined list,
+ * enabling flexibility in the type of List used.
+ *
+ * @param tasks A List of {@link Task} objects to initialize the TaskList.
+ */
+ public TaskList(List tasks) {
+ this.tasks = tasks;
+ }
+
+ /**
+ * Default constructor that initializes the TaskList with an empty ArrayList.
+ * This is useful when no initial tasks are provided, and tasks need to be added dynamically.
+ */
+ public TaskList() {
+ this.tasks = new ArrayList<>();
+ }
+
+ /**
+ * Returns the list of tasks.
+ *
+ * @return A list of {@link Task} objects.
+ */
+ public List getTasks() {
+ return tasks;
+ }
+
+ /**
+ * Retrieves a task from the list based on its index.
+ *
+ * @param index The index of the task to retrieve.
+ * @return The {@link Task} object at the specified index.
+ * @throws IndexOutOfBoundsException if the index is out of range (index < 0 || index >= size()).
+ */
+ public Task getTask(int index) {
+ if (index < 0 || index >= tasks.size()) {
+ throw new IndexOutOfBoundsException("Task index out of range.");
+ }
+ return tasks.get(index);
+ }
+
+ /**
+ * Adds a new task to the task list.
+ *
+ * @param task The {@link Task} object to add to the list.
+ */
+ public void addTask(Task task) {
+ tasks.add(task);
+ }
+
+ /**
+ * Removes a task from the task list based on its index.
+ *
+ * @param index The index of the task to be removed.
+ * @throws IndexOutOfBoundsException if the index is out of range (index < 0 || index >= size()).
+ */
+ public void removeTask(int index) {
+ if (index < 0 || index >= tasks.size()) {
+ throw new IndexOutOfBoundsException("Task index out of range.");
+ }
+ tasks.remove(index);
+ }
+
+ /**
+ * Searches for tasks that contain the specified keyword in their description.
+ *
+ * @param keyword The keyword to search for within the task descriptions.
+ * @return A list of {@link Task} objects that contain the keyword in their description.
+ */
+ public List findTasksByKeyword(String keyword) {
+ List foundTasks = new ArrayList<>();
+ for (Task task : tasks) {
+ if (task.description.toLowerCase().contains(keyword.toLowerCase())) {
+ foundTasks.add(task);
+ }
+ }
+ return foundTasks;
+ }
+
+ /**
+ * Handles the execution of commands by delegating appropriate actions for each command.
+ *
+ * @param command The user command to be processed.
+ * @param arguments The arguments provided with the command (if any).
+ * @param ui The UI handler for displaying feedback to the user.
+ * @param storage The storage handler to save tasks after any changes.
+ */
+ public void handleCommand(String command, String arguments, Ui ui, Storage storage) throws Exception {
+ switch (command) {
+ case "bye":
+ ui.showGoodbye();
+ System.exit(0);
+ break;
+
+ case "list":
+ ui.showTaskList(this);
+ break;
+
+ case "mark":
+ markTaskAsDone(arguments, ui, storage);
+ break;
+
+ case "unmark":
+ unmarkTask(arguments, ui, storage);
+ break;
+
+ case "todo":
+ addTodoTask(arguments, ui, storage);
+ break;
+
+ case "deadline":
+ addDeadlineTask(arguments, ui, storage);
+ break;
+
+ case "event":
+ addEventTask(arguments, ui, storage);
+ break;
+
+ case "delete":
+ deleteTask(arguments, ui, storage);
+ break;
+
+ case "priority":
+ setPriority(arguments, ui, storage);
+ break;
+
+ case "find":
+ findTasks(arguments, ui);
+ break;
+
+ default:
+ throw new UnknownCommandException("I'm sorry, but I don't know what that means.");
+ }
+ }
+
+ // Helper methods to handle different task operations:
+
+ private void markTaskAsDone(String argument, Ui ui, Storage storage) throws Exception {
+ int index = parseTaskIndex(argument);
+ Task task = getTask(index);
+ task.markAsDone();
+ ui.showLine();
+ ui.showMessage("Nice! I've marked this task as done:");
+ ui.showMessage(task.toString());
+ ui.showLine();
+ storage.save(this);
+ }
+
+ private void unmarkTask(String argument, Ui ui, Storage storage) throws Exception {
+ int index = parseTaskIndex(argument);
+ Task task = getTask(index);
+ task.unmark();
+ ui.showLine();
+ ui.showMessage("OK, I've marked this task as not done yet:");
+ ui.showMessage(task.toString());
+ ui.showLine();
+ storage.save(this);
+ }
+
+ private void addTodoTask(String argument, Ui ui, Storage storage) throws Exception {
+ if (argument.isEmpty()) {
+ throw new NoDescriptionException("Description cannot be empty for todo.");
+ }
+ Task todo = new Todo(argument);
+ addTask(todo);
+ ui.showLine();
+ ui.showMessage("Got it. I've added this task:");
+ ui.showMessage(todo.toString());
+ ui.showLine();
+ storage.save(this);
+ }
+
+ private void addDeadlineTask(String argument, Ui ui, Storage storage) throws Exception {
+ if (!argument.contains(" /by ")) {
+ throw new NoDescriptionException("Deadline command must include '/by' followed by a date/time.");
+ }
+ String[] details = argument.split(" /by ", 2);
+ Task deadline = new Deadline(details[0].trim(),
+ LocalDateTime.parse(details[1].trim(),
+ DateTimeFormatter.ofPattern("d/M/yyyy HHmm")));
+ addTask(deadline);
+ ui.showLine();
+ ui.showMessage("Got it. I've added this task:");
+ ui.showMessage(deadline.toString());
+ ui.showLine();
+ storage.save(this);
+ }
+
+ private void addEventTask(String argument, Ui ui, Storage storage) throws Exception {
+ // Ensure the argument contains both "/from" and "/to"
+ if (!argument.contains(" /from ") || !argument.contains(" /to ")) {
+ throw new NoDescriptionException(
+ "Event command must include '/from' and '/to' followed by their respective times.");
+ }
+
+ try {
+ // Split the argument to extract the description, from date, and to date
+ String[] details = argument.split(" /from | /to ", 3);
+
+ // Validate that three parts are extracted (description, from, and to)
+ if (details.length != 3) {
+ throw new NoDescriptionException(
+ "Please provide a valid description, from date, and to date for the event.");
+ }
+
+ // Parse the from and to dates
+ LocalDateTime fromDate = LocalDateTime.parse(details[1].trim(),
+ DateTimeFormatter.ofPattern("d/M/yyyy HHmm"));
+ LocalDateTime toDate = LocalDateTime.parse(details[2].trim(),
+ DateTimeFormatter.ofPattern("d/M/yyyy HHmm"));
+
+ // Create a new Event and add it to the task list
+ Task event = new Event(details[0].trim(), fromDate, toDate);
+ addTask(event);
+
+ // Provide feedback to the user
+ ui.showLine();
+ ui.showMessage("Got it. I've added this task:");
+ ui.showMessage(event.toString());
+ ui.showLine();
+
+ // Save the updated task list to storage
+ storage.save(this);
+
+ } catch (ArrayIndexOutOfBoundsException e) {
+ throw new NoDescriptionException(
+ "Please provide valid dates for both /from and /to in the format 'd/M/yyyy HHmm'.");
+ } catch (Exception e) {
+ throw new NoDescriptionException(
+ "There was an error parsing the event dates. Ensure you use the format 'd/M/yyyy HHmm'.");
+ }
+ }
+
+ private void deleteTask(String argument, Ui ui, Storage storage) throws Exception {
+ int index = parseTaskIndex(argument);
+ Task removedTask = getTask(index);
+ removeTask(index);
+ ui.showLine();
+ ui.showMessage("Noted. I've removed this task:");
+ ui.showMessage(removedTask.toString());
+ ui.showLine();
+ storage.save(this);
+ }
+
+ private void setPriority(String argument, Ui ui, Storage storage) throws Exception {
+ String[] details = argument.split(" ");
+ if (details.length != 2) {
+ throw new IllegalArgumentException("Invalid priority command format. Use: priority ");
+ }
+ int index = parseTaskIndex(details[0]);
+ int priority = Integer.parseInt(details[1]);
+ Task task = getTask(index);
+ task.setPriority(priority);
+ ui.showLine();
+ ui.showMessage("Task priority updated:");
+ ui.showMessage(task.toString());
+ ui.showLine();
+ storage.save(this);
+ }
+
+ private void findTasks(String keyword, Ui ui) {
+ List foundTasks = findTasksByKeyword(keyword);
+ ui.showSearchResults(foundTasks);
+ }
+
+ private int parseTaskIndex(String argument) throws Exception {
+ if (argument.isEmpty()) {
+ throw new InvalidTaskNumberException("No task index provided.");
+ }
+ try {
+ int index = Integer.parseInt(argument) - 1;
+ if (index < 0 || index >= tasks.size()) {
+ throw new InvalidTaskNumberException("Task index out of range.");
+ }
+ return index;
+ } catch (NumberFormatException e) {
+ throw new InvalidTaskNumberException("Please provide a valid task number.");
+ }
+ }
+}
diff --git a/src/main/java/mysutong/Todo.java b/src/main/java/mysutong/Todo.java
new file mode 100644
index 0000000000..328aa3b9c2
--- /dev/null
+++ b/src/main/java/mysutong/Todo.java
@@ -0,0 +1,52 @@
+package mysutong;
+
+/**
+ * Represents a todo task in the MySutong application.
+ * A todo task is a simple task with a description, completion status, and priority.
+ * Extends {@link Task}.
+ */
+class Todo extends Task {
+
+ /**
+ * Constructs a new Todo instance with the specified description.
+ * The task is initialized with a default priority of "low" (priority 3).
+ *
+ * @param description the description of the todo task.
+ */
+ public Todo(String description) {
+ super(description); // Call to the superclass (Task) constructor.
+ }
+
+ /**
+ * Constructs a new Todo instance with the specified description and priority.
+ *
+ * @param description the description of the todo task.
+ * @param priority the priority level (1 for high, 2 for medium, 3 for low).
+ */
+ public Todo(String description, int priority) {
+ super(description); // Call to the superclass (Task) constructor.
+ setPriority(priority); // Set the priority using the method from the superclass.
+ }
+
+ /**
+ * Returns a string representation of the todo task, which includes the task type
+ * prefixed by "[T]" and the status, description, and priority from the superclass.
+ *
+ * @return a string representation of the todo task.
+ */
+ @Override
+ public String toString() {
+ return "[T]" + super.toString(); // Include the task type in the toString output.
+ }
+
+ /**
+ * Returns a string representation suitable for file storage.
+ * Includes the task type, status, description, and priority for this todo task.
+ *
+ * @return a formatted string representing the todo task for file storage.
+ */
+ @Override
+ public String toFileString() {
+ return "T | " + (isDone ? "1" : "0") + " | " + description + " | " + getPriority();
+ }
+}
diff --git a/src/main/java/mysutong/Ui.java b/src/main/java/mysutong/Ui.java
new file mode 100644
index 0000000000..d5b7394074
--- /dev/null
+++ b/src/main/java/mysutong/Ui.java
@@ -0,0 +1,129 @@
+package mysutong;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+
+/**
+ * Handles the user interface for the MySutong application.
+ * This class manages all user interactions and display functionalities.
+ */
+public class Ui {
+ private final Scanner scanner = new Scanner(System.in); // Scanner to read user input.
+ private List responses; // List to store responses for later retrieval.
+
+ /**
+ * Constructs a new Ui instance and initializes the response list.
+ */
+ public Ui() {
+ responses = new ArrayList<>();
+ }
+
+ /**
+ * Displays a welcome message to the user at the start of the application.
+ */
+ public void showWelcome() {
+ String horizontalLine = "";
+ responses.add(horizontalLine);
+ responses.add("Hello! I'm mysutong.MySutong");
+ responses.add("What can I do for you?");
+ responses.add(horizontalLine);
+ }
+
+ /**
+ * Adds a horizontal line for separating sections of output.
+ */
+ public void showLine() {
+ responses.add("");
+ }
+
+ /**
+ * Adds an error message to the responses when there is a problem loading tasks from the file.
+ */
+ public void showLoadingError() {
+ responses.add("Error loading tasks from file.");
+ }
+
+ /**
+ * Reads a command from the user input (still needed for CLI functionality).
+ *
+ * @return the command entered by the user.
+ */
+ public String readCommand() {
+ return scanner.nextLine();
+ }
+
+ /**
+ * Adds a goodbye message to the responses when the user exits the application.
+ */
+ public void showGoodbye() {
+ responses.add("Bye. Hope to see you again soon!");
+ }
+
+ /**
+ * Adds the list of tasks currently in the TaskList to the responses.
+ *
+ * @param tasks the TaskList containing the tasks to be displayed.
+ */
+ public void showTaskList(TaskList tasks) {
+ showLine();
+ responses.add("Here are the tasks in your list:");
+ for (int i = 0; i < tasks.getTasks().size(); i++) {
+ responses.add((i + 1) + ". " + tasks.getTasks().get(i));
+ }
+ showLine();
+ }
+
+ /**
+ * Adds the search results to the responses.
+ *
+ * @param tasks the list of tasks that match the search criteria.
+ */
+ public void showSearchResults(List tasks) {
+ showLine();
+ if (tasks.isEmpty()) {
+ responses.add("No matching tasks found.");
+ } else {
+ responses.add("Here are the matching tasks in your list:");
+ for (int i = 0; i < tasks.size(); i++) {
+ responses.add((i + 1) + ". " + tasks.get(i));
+ }
+ }
+ showLine();
+ }
+
+ /**
+ * Adds a message to the responses.
+ *
+ * @param message the message to be added.
+ */
+ public void showMessage(String message) {
+ responses.add(message);
+ }
+
+ /**
+ * Adds an error message to the responses.
+ *
+ * @param message the error message to be added.
+ */
+ public void showError(String message) {
+ responses.add("Oh no. " + message);
+ }
+
+ /**
+ * Returns all the responses as a single concatenated string.
+ *
+ * @return the concatenated response string.
+ */
+ public String getResponse() {
+ return String.join("\n", responses);
+ }
+
+ /**
+ * Clears the current responses list.
+ * This is useful if you want to start fresh for a new response session.
+ */
+ public void clearResponses() {
+ responses.clear();
+ }
+}
diff --git a/src/main/java/mysutong/UnknownCommandException.java b/src/main/java/mysutong/UnknownCommandException.java
new file mode 100644
index 0000000000..74c2417357
--- /dev/null
+++ b/src/main/java/mysutong/UnknownCommandException.java
@@ -0,0 +1,17 @@
+package mysutong;
+
+/**
+ * Exception thrown when the MySutong application encounters an unrecognized command.
+ * Extends {@link SutongException} to handle application-specific exceptions related to command processing.
+ */
+class UnknownCommandException extends SutongException {
+
+ /**
+ * Constructs a new UnknownCommandException with the specified detail message.
+ *
+ * @param message the detail message, providing more information about why the exception was thrown.
+ */
+ public UnknownCommandException(String message) {
+ super(message); // Pass the message up to the superclass constructor.
+ }
+}
diff --git a/src/main/resources/images/DaDuke.png b/src/main/resources/images/DaDuke.png
new file mode 100644
index 0000000000..d893658717
Binary files /dev/null and b/src/main/resources/images/DaDuke.png differ
diff --git a/src/main/resources/images/DaUser.png b/src/main/resources/images/DaUser.png
new file mode 100644
index 0000000000..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..fe672c90ea
--- /dev/null
+++ b/src/main/resources/view/DialogBox.fxml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml
new file mode 100644
index 0000000000..7f741bbf61
--- /dev/null
+++ b/src/main/resources/view/MainWindow.fxml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/test/java/mysutong/EventTest.java b/src/test/java/mysutong/EventTest.java
new file mode 100644
index 0000000000..bb7d8b4351
--- /dev/null
+++ b/src/test/java/mysutong/EventTest.java
@@ -0,0 +1,32 @@
+package mysutong;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.time.LocalDateTime;
+
+import org.junit.jupiter.api.Test;
+
+public class EventTest {
+ @Test
+ public void testToString() {
+ LocalDateTime from = LocalDateTime.of(2023, 9, 10, 14, 0);
+ LocalDateTime to = LocalDateTime.of(2023, 9, 10, 16, 0);
+ Event event = new Event("Team Meeting", from, to);
+ String expected = "[E][ ] Team Meeting (from: Sep 10 2023 2:00pm to: Sep 10 2023 4:00pm)";
+ assertEquals(expected, event.toString());
+ }
+
+ @Test
+ public void testMarkAsDone() {
+ LocalDateTime from = LocalDateTime.of(2023, 9, 10, 14, 0);
+ LocalDateTime to = LocalDateTime.of(2023, 9, 10, 16, 0);
+ Event event = new Event("Project Presentation", from, to);
+ assertFalse(event.isDone());
+ event.markAsDone();
+ assertTrue(event.isDone());
+ String expected = "[E][X] Project Presentation (from: Sep 10 2023 2:00pm to: Sep 10 2023 4:00pm)";
+ assertEquals(expected, event.toString());
+ }
+}
diff --git a/src/test/java/mysutong/TodoTest.java b/src/test/java/mysutong/TodoTest.java
new file mode 100644
index 0000000000..9a245d11f6
--- /dev/null
+++ b/src/test/java/mysutong/TodoTest.java
@@ -0,0 +1,42 @@
+package mysutong;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+public class TodoTest {
+
+ @Test
+ public void testToString_whenNotDone() {
+ // Create a new Todo task
+ Todo todo = new Todo("Read a book");
+
+ // Expected output when the task is not done
+ String expected = "[T][ ] Read a book";
+
+ // Assert that the toString method produces the expected output
+ assertEquals(expected, todo.toString());
+ }
+
+ @Test
+ public void testMarkAsDone() {
+ // Create a new Todo task
+ Todo todo = new Todo("Complete assignment");
+
+ // Initially, the task should not be done
+ assertFalse(todo.isDone());
+
+ // Mark the task as done
+ todo.markAsDone();
+
+ // Assert that the task is marked as done
+ assertTrue(todo.isDone());
+
+ // Check that toString reflects the done status
+ String expected = "[T][X] Complete assignment";
+ assertEquals(expected, todo.toString());
+ }
+}
+
diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT
index 657e74f6e7..618a86bc42 100644
--- a/text-ui-test/EXPECTED.TXT
+++ b/text-ui-test/EXPECTED.TXT
@@ -1,7 +1,36 @@
-Hello from
- ____ _
-| _ \ _ _| | _____
-| | | | | | | |/ / _ \
-| |_| | |_| | < __/
-|____/ \__,_|_|\_\___|
-
+____________________________________________________________
+Hello! I'm mysutong.MySutong
+What can I do for you?
+____________________________________________________________
+____________________________________________________________
+Got it. I've added this task:
+[T][ ] study
+Now you have 1 tasks in the list.
+____________________________________________________________
+____________________________________________________________
+Got it. I've added this task:
+[D][ ] call friend (by: Sunday)
+Now you have 2 tasks in the list.
+____________________________________________________________
+____________________________________________________________
+Got it. I've added this task:
+[E][ ] meeting (from: Mon 2pm to: 4pm)
+Now you have 3 tasks in the list.
+____________________________________________________________
+____________________________________________________________
+Here are the tasks in your list:
+1. [T][ ] study
+2. [D][ ] call friend (by: Sunday)
+3. [E][ ] meeting (from: Mon 2pm to: 4pm)
+____________________________________________________________
+____________________________________________________________
+Nice! I've marked this task as done:
+[T][X] study
+____________________________________________________________
+____________________________________________________________
+OK, I've marked this task as not done yet:
+[D][ ] call friend (by: Sunday)
+____________________________________________________________
+____________________________________________________________
+Bye. Hope to see you again soon!
+____________________________________________________________
diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt
index e69de29bb2..66680b72e3 100644
--- a/text-ui-test/input.txt
+++ b/text-ui-test/input.txt
@@ -0,0 +1,7 @@
+todo study
+deadline call friend /by Sunday
+event meeting /from Mon 2pm /to 4pm
+list
+mark 1
+unmark 2
+bye
\ No newline at end of file
diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh
old mode 100644
new mode 100755
index c9ec870033..d61064b87e
--- 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 MySutong < input.txt > ACTUAL.TXT
# convert to UNIX format
cp EXPECTED.TXT EXPECTED-UNIX.TXT