diff --git a/.gitignore b/.gitignore index f69985ef1f..d3c85fa02b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ /.idea/ /out/ /*.iml +out/artifacts/ip_jar # Gradle build files /.gradle/ diff --git a/README.md b/README.md index 8715d4d915..0f2208ab64 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Duke project template +# duke.Duke project template This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it. @@ -13,7 +13,7 @@ Prerequisites: JDK 11, update Intellij to the most recent version. 1. If there are any further prompts, accept the defaults. 1. Configure the project to use **JDK 11** (not other versions) as explained in [here](https://www.jetbrains.com/help/idea/sdk.html#set-up-jdk).
In the same dialog, set the **Project language level** field to the `SDK default` option. -3. After that, locate the `src/main/java/Duke.java` file, right-click it, and choose `Run Duke.main()` (if the code editor is showing compile errors, try restarting the IDE). If the setup is correct, you should see something like the below as the output: +3. After that, locate the `src/main/java/duke.Duke.java` file, right-click it, and choose `Run duke.Duke.main()` (if the code editor is showing compile errors, try restarting the IDE). If the setup is correct, you should see something like the below as the output: ``` Hello from ____ _ diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000000..e3a3b682ee --- /dev/null +++ b/build.gradle @@ -0,0 +1,62 @@ +plugins { + id 'java' + id 'application' + id 'checkstyle' + id 'com.github.johnrengelman.shadow' version '5.1.0' +} + +repositories { + mavenCentral() +} + +dependencies { + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0' + testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.0' + + 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' +} + +test { + useJUnitPlatform() + + testLogging { + events "passed", "skipped", "failed" + + showExceptions true + exceptionFormat "full" + showCauses true + showStackTraces true + showStandardStreams = false + } +} + +application { + mainClassName = "duke.Launcher" +} + +shadowJar { + archiveBaseName = "duke" + archiveClassifier = null +} + +checkstyle { + toolVersion = '8.29' +} + +run { + standardInput = System.in + enableAssertions = true +} diff --git a/docs/README.md b/docs/README.md index 8077118ebe..c33a7dc818 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,29 +1,278 @@ # User Guide +Duke is a personal assistant chatbot that will help you keep track of various things. +It is optimized for use via a Command Line Interface (CLI) while still having the benefits of a Graphical +User Interface (GUI). + +![Image of Duke](https://github.com/pranav-ganesh/ip/blob/master/docs/Ui.png?raw=true) + ## Features -### Feature-ABC +1) Add tasks with deadline +2) Add todos +3) Add events +4) Edit tasks +5) View the task list +6) Mark tasks as done +7) Delete tasks +8) Find tasks by keyword +9) Clone tasks + +### Storage file + +Store the task list in a local file. -Description of the feature. +### Add, Edit, View, Delete, Find -### Feature-XYZ +Add, Edit, View, Delete, Clone and Find tasks. -Description of the feature. +### Mark as done + +Mark tasks as done once the task is completed. ## Usage -### `Keyword` - Describe action +### Adding a todo: `todo ` -Describe the action and its outcome. +Adds a task of type todo to the task list. Example of usage: -`keyword (optional arguments)` +`todo purchase laptop` + +Expected outcome: + +The task is added to the task list. + +``` +Got it. I've added this task: +[T][] purchase laptop +Now you have 1 task(s) in the list. +``` + +### Adding a deadline: `deadline /by ` + +Adds a task of type deadline to the task list. + +Example of usage: + +`deadline CS2103T iP/by 2021-09-20 2359` Expected outcome: -Description of the outcome. +The task is added to the task list. ``` -expected output +Got it. I've added this task: +[D][] CS2103T iP (by: Sep 20 2021, 11 PM) +Now you have 2 task(s) in the list. ``` + +### Adding an event: `event /at ` + +Adds a task of type event to the task list. + +Example of usage: + +`event concert/at 2021-09-25 1800` + +Expected outcome: + +The task is added to the task list. + +``` +Got it. I've added this task: +[E][] concert (at: Sep 25 2021, 6 PM) +Now you have 3 task(s) in the list. +``` + +### Viewing the task list: `list` + +View the current task list. + +Example of usage: + +`list` + +Expected outcome: + +The task list is printed on the screen. + +``` +1. [T][] purchase laptop +2. [D][] CS2103T iP (by: Sep 20 2021, 11 PM) +3. [E][] concert (at: Sep 25 2021, 6 PM) +``` + +### Finding tasks with a keyword: `find ` + +Finds task(s) in the task list that contain the keyword. + +Example of usage: + +`find laptop` + +Expected outcome: + +Tasks containing the keyword 'laptop' in their description will be displayed. + +``` +Here are the matching task(s) in your list: +1. [T][] purchase laptop +``` + +### Marking tasks as done: `done ` + +Marks task as complete. The task index refers to number this task is associated +to in the task list. + +Example of usage: + +`done 1` + +Expected outcome: + +The first task in the task list is marked as done. [X] denotes that the task is done. + +``` +Nice! I've marked this task as done: +[T][X] purchase laptop +``` + +### Deleting tasks: `delete ` + +Deletes task in the task list. The task index refers to the number this task is associated +to in the task list. + +Example of usage: + +`delete 1` + +Expected outcome: + +The first task in the task list is deleted. + +``` +Noted. I've removed this task: +[T][X] purchase laptop +Now you have 2 tasks in the list. +``` + +### Cloning tasks: `clone ` + +Clones task in the task list and adds it to the task list. The task index refers to the number +this task is associated to in the task list. + +Example of usage: + +`clone 1` + +Expected outcome: + +The first task in the task list is cloned and added to the task list. + +``` +Task 1 from the task list has been cloned! Here is +the latest task list: +1. [D][] CS2103T iP (by: Sep 20 2021, 11 PM) +2. [E][] concert (at: Sep 25 2021, 6 PM) +3. [D][] CS2103T iP (by: Sep 20 2021, 11 PM) +``` + +### Editing tasks: `edit /task ` + +Replaces the task in the specified task index with the new task. The new task command can be a +deadline, event or todo. The task index refers to the number this task is associated to in the task list. + +Example of usage: + +`edit 1/task event football match/at 2021-12-03 1900` + +Expected outcome: + +The first task in the task list is updated with the new task. + +``` +Task 1 in the task list has been updated! Here is +your latest list: +1. [E][] football match (by: Dec 3 2021, 7 PM) +2. [E][] concert (at: Sep 25 2021, 6 PM) +3. [D][] CS2103T iP (by: Sep 20 2021, 11 PM) +``` + +### Editing task descriptions: `edit /description ` + +Replaces the task description of the task in the specified task index with the new description. +The task index refers to the number this task is associated to in the task list. + +Example of usage: + +`edit 1/description badminton match` + +Expected outcome: + +The first task in the task list is updated with the new task. + +``` +The description of Task 1 in the task list has been +updated! Here is your latest list: +1. [E][] badminton match (by: Dec 3 2021, 7 PM) +2. [E][] concert (at: Sep 25 2021, 6 PM) +3. [D][] CS2103T iP (by: Sep 20 2021, 11 PM) +``` + +### Editing task date and time: `edit /datetime ` + +Replaces the date and time of the task in the specified task index with the new date and time. +The task in the specified task index has to be a deadline or event task since todos don't have a date and time. +The task index refers to the number this task is associated to in the task list. + +Example of usage: + +`edit 1/datetime 2022-01-01 2000` + +Expected outcome: + +The first task in the task list is updated with the new task. + +``` +The DateTime of Task 1 in the task list has been +updated! Here is your latest list: +1. [E][] badminton match (by: Jan 1 2022, 8 PM) +2. [E][] concert (at: Sep 25 2021, 6 PM) +3. [D][] CS2103T iP (by: Sep 20 2021, 11 PM) +``` + +### Exiting the application: `bye` + +Terminates and closes the application window. + +Example of usage: + +`bye` + +Expected outcome: + +The application displays the message 'Bye. Have a great day!' and then exits. The application window closes. + +``` +Bye. Have a great day! +``` + +## Command summary + +Command | Format | Example +------------ | ------------- | ------------- +todo | ```todo ``` | ```todo homework``` +event | ```event /at ``` | ```event concert/at 2021-03-04 1900``` +deadline | ```deadline /by ``` | ```deadline assignment/by 2021-09-20 2359``` +list | ```list``` | ```list``` +done | ```done ``` | ```done 2``` +delete | ```delete ``` | ```delete 2``` +find | ```find ``` | ```find assignment``` +edit task | ```edit /task ``` | ```edit 2/task deadline worksheet/by 2021-10-10 1000``` +edit description | ```edit /description ``` | ```edit 1/description CS2103T iP``` +edit date and/or time | ```edit /datetime ``` | ```edit 3/datetime 2022-03-08 2300``` +clone | ```clone ``` | ```clone 1``` +bye | ```bye``` | ```bye``` + \ No newline at end of file diff --git a/docs/Ui.png b/docs/Ui.png new file mode 100644 index 0000000000..c15e5c62da Binary files /dev/null and b/docs/Ui.png differ diff --git a/duke.txt b/duke.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..f3d88b1c2f Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..b7c8c5dbf5 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000000..2fe81a7d95 --- /dev/null +++ b/gradlew @@ -0,0 +1,183 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000000..62bd9b9cce --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,103 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/src/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..c43e121bbd --- /dev/null +++ b/src/main/java/duke/DialogBox.java @@ -0,0 +1,62 @@ +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); + dialog.setMinWidth(265); + 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..00fc45ae49 --- /dev/null +++ b/src/main/java/duke/Duke.java @@ -0,0 +1,52 @@ +package duke; + +import duke.exception.DukeException; +import duke.task.TaskList; +import duke.command.Command; + +public class Duke { + private Storage storage; + private TaskList taskList; + private Ui ui; + + public Duke() { + taskList = new TaskList(); + storage = new Storage("./duke.txt"); + storage.loadTaskListData(taskList); + ui = new Ui(taskList, storage); + } + + public void runCLI() throws DukeException { + this.ui.showWelcome(); + Ui.showLine(); + + boolean isExit = false; + while (!isExit) { + String command = ui.getCommand(); + Parser parser = new Parser(command); + if (parser.isExit()) { + break; + } + Command c = parser.parse(); + c.execute(taskList, storage); + isExit = parser.isExit(); + } + } + + public static void main(String[] args) throws DukeException { + new Duke().runCLI(); + } + + public String getResponse(String input) throws DukeException { + Parser parser = new Parser(input); + if (parser.isExit()) { + assert (input.equals("bye") || input.equals("")): "input should be either bye or an empty string"; + String response = Ui.sayBye(); + return response; + } + + Command c = parser.parse(); + String response = c.execute(this.taskList, this.storage); + return response; + } +} diff --git a/src/main/java/duke/Launcher.java b/src/main/java/duke/Launcher.java new file mode 100644 index 0000000000..e4ef6b4628 --- /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); + } +} diff --git a/src/main/java/duke/Main.java b/src/main/java/duke/Main.java new file mode 100644 index 0000000000..588fa7369a --- /dev/null +++ b/src/main/java/duke/Main.java @@ -0,0 +1,34 @@ +package duke; + +import java.io.IOException; + +import duke.task.TaskList; +import javafx.application.Application; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.scene.image.Image; +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..dca39418a4 --- /dev/null +++ b/src/main/java/duke/MainWindow.java @@ -0,0 +1,87 @@ +package duke; + +import duke.exception.DukeException; +import duke.task.TaskList; + +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.application.Platform; + +import java.util.Timer; +import java.util.TimerTask; + +/** + * 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/anonymous.png")); + private Image dukeImage = new Image(this.getClass().getResourceAsStream("/images/duke_img.png")); + + @FXML + public void initialize() { + scrollPane.vvalueProperty().bind(dialogContainer.heightProperty()); + + TaskList taskList = new TaskList(); + Storage storage = new Storage("./duke.txt"); + storage.loadTaskListData(taskList); + + Ui ui = new Ui(taskList, storage); + String welcomeMessage = ui.showWelcome(); + + dialogContainer.getChildren().addAll( + DialogBox.getDukeDialog(welcomeMessage, dukeImage) + ); + } + + public void setDuke(Duke d) { + duke = d; + } + + /** + * Creates two dialog boxes, one echoing user input and the other containing Duke's reply and then appends them to + * the dialog container. Clears the user input after processing. + */ + @FXML + private void handleUserInput() throws DukeException { + String input = userInput.getText(); + String response = duke.getResponse(input); + dialogContainer.getChildren().addAll( + DialogBox.getUserDialog(input, userImage), + DialogBox.getDukeDialog(response, dukeImage) + ); + + if (input.equals("bye")) { + exitIfByeInput(); + } + + userInput.clear(); + } + + private void exitIfByeInput() { + int time = 1000; + TimerTask timerTask = new TimerTask() { + public void run() { + Platform.exit(); + System.exit(0); + } + }; + + new Timer().schedule(timerTask, time); + } +} diff --git a/src/main/java/duke/Parser.java b/src/main/java/duke/Parser.java new file mode 100644 index 0000000000..dc43c771d9 --- /dev/null +++ b/src/main/java/duke/Parser.java @@ -0,0 +1,73 @@ +package duke; + +import duke.command.Command; +import duke.command.EditCommand; +import duke.command.InvalidCommand; +import duke.command.CloneCommand; +import duke.command.DeadlineCommand; +import duke.command.DoneCommand; +import duke.command.DeleteCommand; +import duke.command.FindCommand; +import duke.command.EventCommand; +import duke.command.TodoCommand; +import duke.command.ListCommand; + +/** + * Deals with making sense of the user command. + */ +public class Parser { + private String command; + + /** + * Represents a constructor for the Parser class where the user command is initialized. + * + * @param command Command typed the user. + */ + public Parser(String command) { + this.command = command; + } + + /** + * Returns the instance of the type of command entered by the user. + * + * @return Command object. + */ + public Command parse() { + int len = command.length(); + if (command.equals("list")) { + return new ListCommand(command); + } else if (command.startsWith("done") && Character.isDigit(command.charAt(len - 1))) { + return new DoneCommand(command); + } else if (command.startsWith("todo")) { + return new TodoCommand(command); + } else if (command.startsWith("deadline")) { + return new DeadlineCommand(command); + } else if (command.startsWith("event")) { + return new EventCommand(command); + } else if (command.startsWith("delete")) { + return new DeleteCommand(command); + } else if (command.startsWith("find")) { + return new FindCommand(command); + } else if (command.startsWith("edit")) { + return new EditCommand(command); + } else if (command.startsWith("clone")) { + return new CloneCommand(command); + } else { + return new InvalidCommand(command); + } + } + + /** + * Checks if the user types the command 'bye' or clicks 'enter' without typing any command. + * + * @return true or false. + */ + public boolean isExit() { + if (command.equals("bye") || command.equals("")) { + Ui.sayBye(); + Ui.showLine(); + return true; + } + return false; + } +} diff --git a/src/main/java/duke/Storage.java b/src/main/java/duke/Storage.java new file mode 100644 index 0000000000..c7af820d86 --- /dev/null +++ b/src/main/java/duke/Storage.java @@ -0,0 +1,104 @@ +package duke; + +import duke.task.TaskList; +import duke.task.Task; +import duke.task.Event; +import duke.task.Deadline; +import duke.task.Todo; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Scanner; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * Deals with loading tasks from the file and saving tasks in the file (duke.txt). + */ +public class Storage { + private String filepath; + private File file; + + /** + * Represents a constructor for the Storage class where the filepath is initialized. + * + * @param filepath Filepath of the file (duke.txt) where the task data is stored. + */ + public Storage(String filepath) { + this.filepath = filepath; + try { + File file = new File(filepath); + if (!file.exists()) { + file.createNewFile(); + } + this.file = file; + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Loads the task data from the duke.txt storage file into the task list. + * + * @param taskList TaskList where the tasks are stored. + */ + public void loadTaskListData(TaskList taskList) { + try { + Scanner s = new Scanner(this.file); + while (s.hasNext()) { + String str = s.nextLine(); + String[] parts = str.split("\\|", 4); + String taskType = parts[0].substring(3).trim(); + + addTaskToTaskList(parts, taskList, taskType); + } + + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + + private void addTaskToTaskList(String[] parts, TaskList taskList, String taskType) { + Task task = null; + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MMM d yyyy, h a"); + + if (taskType.equals("duke.task.Todo")) { + task = new Todo(parts[2].trim()); + } else if (taskType.equals("duke.task.Deadline")) { + LocalDateTime dateTime = LocalDateTime.parse(parts[3].substring(5).trim(), dtf); + task = new Deadline(parts[2].trim(), dateTime); + } else if (taskType.equals("duke.task.Event")) { + LocalDateTime dateTime = LocalDateTime.parse(parts[3].substring(5).trim(), dtf); + task = new Event(parts[2].trim(), dateTime); + } + + if (task != null) { + if (parts[1].trim().equals("X")) { + task.markAsDone(); + } + taskList.addTask(task); + } + } + + /** + * Writes the task data to the duke.txt file whenever the task list is updated. + * + * @param filePath Filepath of the file (duke.txt) where the task data is stored. + * @param taskList TaskList where the tasks are stored. + */ + public void writeToFile(String filePath, TaskList taskList) { + try { + FileWriter fw = new FileWriter(filePath); + for (int i = 0; i < taskList.getSize(); i++) { + int num = i + 1; + fw.write(num + ". " + taskList.getTask(i).getTaskListOnDisk() + "\n"); + } + fw.close(); + + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/duke/Ui.java b/src/main/java/duke/Ui.java new file mode 100644 index 0000000000..7e1aacba8d --- /dev/null +++ b/src/main/java/duke/Ui.java @@ -0,0 +1,221 @@ +package duke; + +import duke.task.Task; +import duke.task.TaskList; + +import java.util.Scanner; + +/** + * Represents the user interface which deals with interactions with the user. + */ +public class Ui { + Scanner sc; + private static TaskList taskList; + private static Storage storage; + + /** + * Represents a constructor for the Ui class where variables are initialized. + * + * @param taskList TaskList that stores the tasks. + * @param storage Storage that deals with loading tasks from the file and saving tasks in the file. + */ + public Ui(TaskList taskList, Storage storage) { + sc = new Scanner(System.in); + this.taskList = taskList; + this.storage = storage; + } + + /** + * Returns the command typed by the user. + * If the user doesn't type any command and clicks enter, an empty string is returned. + * + * @return String representation of the command entered by the user. + */ + public String getCommand() { + if (sc.hasNextLine()) { + String str = sc.nextLine(); + return str; + } + return ""; + } + + /** + * Returns the appropriate welcome message along with the existing task list when duke starts up. + * + * @return String representation of welcome commands and the current task list. + */ + public String showWelcome() { + String welcomeMessage = "Hello from duke :)) \n\n" + "Here is your current task list: \n" + showLine() + "\n" + + this.taskList.printList() + "\n" + showLine() + "\nEnd of task list \n\n" + "How can I help you?"; + printInput(welcomeMessage); + return welcomeMessage; + } + + /** + * Returns the string response to the bye command. + * + * @return String response to the bye command. + */ + public static String sayBye() { + String byeMessage = "Bye. Have a great day!"; + printInput(byeMessage); + return byeMessage; + } + + /** + * Returns a dashed line to enhance the user interface. + * + * @return String representation of a dashed line. + */ + public static String showLine() { + String line = "-----------------------------------------------"; + printInput(line); + return line; + } + + /** + * Returns a string value argument that is displayed on the screen. + * + * @param msg String value to be printed on the screen. + * @return String value to be printed on the screen. + */ + public static String printInput(String msg) { + System.out.println(msg); + return msg; + } + + /** + * Returns the string response to the task command. + * + * @param task Task object. + * @return String representation of the task as well as the number of tasks in the task list. + */ + public String taskResponse(Task task) { + String taskMessage = "Got it. I've added this task:" + System.lineSeparator() + task.toString() + + System.lineSeparator() + "Now you have " + taskList.getSize() + " task(s) in the list."; + printInput(taskMessage); + return taskMessage; + } + + /** + * Returns the string response to the done command. + * + * @param task Task object. + * @return String representation of the task that is done by the user. + */ + public String doneResponse(Task task) { + String doneMessage = "Nice! I've marked this task as done:" + System.lineSeparator() + task.toString(); + printInput(doneMessage); + return doneMessage; + } + + /** + * Returns the string response to the delete command. + * + * @param task Task object. + * @return String representation of the task that is deleted by the user as well as the number of tasks + * remaining in the task list. + */ + public String deleteResponse(Task task) { + String deleteMessage = "Noted. I've removed this task:" + System.lineSeparator() + task.toString() + + System.lineSeparator() + "Now you have " + taskList.getSize() + " task(s) in the list."; + printInput(deleteMessage); + return deleteMessage; + } + + private static boolean isWordPresent(String[] furtherBreakdownIntoParts, String wordToFind) { + for (int j = 0; j < furtherBreakdownIntoParts.length; j++) { + if (wordToFind.equals(furtherBreakdownIntoParts[j].trim())) { + return true; + } + } + return false; + } + + /** + * Returns the string response to the find command. + * + * @param wordToFind String value of the keyword. + * @param taskList TaskList object. + * @return String representation of the tasks in the task list that contain the wordToFind string. + */ + public String findResponse(String wordToFind, TaskList taskList) { + int count = 1; + String response = ""; + + for (int i = 0; i < taskList.getSize(); i++) { + Task task = taskList.getTask(i); + String[] partsBeforeSlash = task.toString().split("\\(", 2); + String[] furtherBreakdownIntoParts = partsBeforeSlash[0].split(" "); + + if (isWordPresent(furtherBreakdownIntoParts, wordToFind)) { + response += (i + 1) + ". " + task + "\n"; + System.lineSeparator(); + count++; + } + } + + assert count > 0: "count should be greater than 0"; + + if (count == 1) { + String message = printInput("Sorry, there are no matching tasks in your list :/"); + return message; + } + + String findMessage = "Here are the matching task(s) in your list:" + System.lineSeparator() + response; + printInput(findMessage); + return findMessage; + } + + /** + * Returns the string response to the clone command. + * + * @param value Number that the task is associated to in the task list. + * @return String representation of the updated task list containing the cloned item. + */ + public String cloneResponse(int value) { + String response = "Task " + value + " from the task list has been cloned!" + " Here is the latest task " + + "list: \n" + taskList.printList(); + printInput(response); + return response; + } + + /** + * Returns the string response to the edit task command. + * + * @param value Number that the task is associated to in the task list. + * @return String representation of the updated task list containing the new task. + */ + public String editTaskResponse(int value) { + String response = "Task " + value + " in your task list has been updated! Here is your latest list: \n" + + taskList.printList(); + printInput(response); + return response; + } + + /** + * Returns the string response to the edit description command. + * + * @param value Number that the task is associated to in the task list. + * @return String representation of the task list with updated description. + */ + public String editDescriptionResponse(int value) { + String response = "The description of Task " + value + " in your task list has been updated! Here is your " + + "latest list: " + "\n" + taskList.printList(); + printInput(response); + return response; + } + + /** + * Returns the string response to the edit datetime command. + * + * @param value Number that the task is associated to in the task list. + * @return String representation of the task list with updated date and time attributes. + */ + public String editDateTimeResponse(int value) { + String response = "The DateTime of Task " + value + " in your task list has been updated! Here is your latest list: " + + "\n" + taskList.printList(); + printInput(response); + return response; + } +} diff --git a/src/main/java/duke/command/CloneCommand.java b/src/main/java/duke/command/CloneCommand.java new file mode 100644 index 0000000000..1e7258ded6 --- /dev/null +++ b/src/main/java/duke/command/CloneCommand.java @@ -0,0 +1,62 @@ +package duke.command; + +import duke.Storage; +import duke.Ui; +import duke.exception.DukeException; +import duke.exception.EmptyDescriptionException; +import duke.exception.TaskNotFoundException; +import duke.task.Task; +import duke.task.TaskList; + +/** + * Represents the user command when the user clones a task in the task list. + */ +public class CloneCommand extends Command { + private String command; + private Storage storage; + + /** + * Represents a constructor for the CloneCommand class where the user command is initialized. + * + * @param command Command entered by the user. + */ + public CloneCommand(String command) { + super(command); + this.command = command; + } + + /** + * Returns the string representation of the class. + * + * @return String description of the class. + */ + public String toString() { + return "This is a clone command"; + } + + /** + * Executes the response when the user clones a task in the task list. + * + * @param taskList TaskList that stores the tasks. + * @param storage Storage that deals with loading tasks from the file and saving tasks in the file. + * @return String representation of the updated task list. + * @throws DukeException If command doesn't have a description or is in invalid format. + */ + public String execute(TaskList taskList, Storage storage) throws DukeException { + if (command.trim().length() <= 5) { + throw new EmptyDescriptionException(); + } + + int value = Integer.parseInt(command.replaceAll("[^0-9]", "")); + if (value > taskList.getSize() || value < 0) { + throw new TaskNotFoundException(); + } + + Task task = taskList.getTask(value - 1); + taskList.addTask(task); + storage.writeToFile("./duke.txt", taskList); + + Ui ui = new Ui(taskList, storage); + return ui.cloneResponse(value); + } +} diff --git a/src/main/java/duke/command/Command.java b/src/main/java/duke/command/Command.java new file mode 100644 index 0000000000..e640e5e457 --- /dev/null +++ b/src/main/java/duke/command/Command.java @@ -0,0 +1,31 @@ +package duke.command; + +import duke.Storage; +import duke.exception.DukeException; +import duke.task.TaskList; + +/** + * Represents the various types of commands that can be entered by the user. + */ +public abstract class Command { + private String command; + + /** + * Represents a constructor for the Command class where the user command is initialized. + * + * @param command Command entered by the user. + */ + public Command(String command) { + this.command = command; + } + + /** + * Represents Duke's response to various types of user commands. + * + * @param taskList TaskList where the tasks are stored. + * @param storage Storage that deals with loading tasks from the file and saving tasks in the file. + * @return String response to various types of commands. + * @throws DukeException If there is an error. + */ + public abstract String execute(TaskList taskList, Storage storage) throws DukeException; +} diff --git a/src/main/java/duke/command/DeadlineCommand.java b/src/main/java/duke/command/DeadlineCommand.java new file mode 100644 index 0000000000..31ca8c24e6 --- /dev/null +++ b/src/main/java/duke/command/DeadlineCommand.java @@ -0,0 +1,85 @@ +package duke.command; + +import duke.task.Deadline; +import duke.task.Task; +import duke.task.TaskList; +import duke.Storage; +import duke.exception.EmptyDescriptionException; +import duke.exception.DukeException; +import duke.exception.InvalidDateTimeException; +import duke.exception.InvalidTaskCommandException; +import duke.Ui; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + +/** + * Represents the user command when the user adds a deadline to the task list. + */ +public class DeadlineCommand extends Command { + private String command; + + /** + * Represents a constructor for the DeadlineCommand class where the user command is initialized. + * + * @param command Command entered by the user. + */ + public DeadlineCommand(String command) { + super(command); + this.command = command; + } + + /** + * Returns the string representation of the class. + * + * @return String description of the class. + */ + public String toString() { + return "This is a deadline command"; + } + + /** + * Executes the response when the user enters a deadline command and updates the task list and storage + * file (duke.txt) + * + * @param taskList TaskList that stores the tasks. + * @param storage Storage that deals with loading tasks from the file and saving tasks in the file. + * @return String representation of the new deadline task as well as the number of tasks in the task list. + * @throws DukeException If user doesn't provide a description for the command or enters the command in an + * invalid format. + */ + public String execute(TaskList taskList, Storage storage) throws DukeException { + if (command.trim().length() <= 8) { + throw new EmptyDescriptionException(); + } + + String[] parts = command.split("/", 2); + if (parts.length <= 1) { + throw new InvalidTaskCommandException(); + } + + if (parts[1].trim().equals("") || !parts[1].startsWith("by ")) { + throw new InvalidTaskCommandException(); + } + + try { + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm"); + LocalDateTime dateTime = LocalDateTime.parse(parts[1].substring(3).trim(), dtf); + + Task task = new Deadline(parts[0].substring(9), dateTime); + taskList.addTask(task); + assert taskList.getTask(taskList.getSize() - 1).equals(task): "last element in the task list should be " + + "equivalent to the most recently added task"; + + storage.writeToFile("./duke.txt", taskList); + + Ui ui = new Ui(taskList, storage); + String response = ui.taskResponse(task); + return response; + + } catch (DateTimeParseException e) { + throw new InvalidDateTimeException(); + } + } +} diff --git a/src/main/java/duke/command/DeleteCommand.java b/src/main/java/duke/command/DeleteCommand.java new file mode 100644 index 0000000000..a1a5d20dbb --- /dev/null +++ b/src/main/java/duke/command/DeleteCommand.java @@ -0,0 +1,68 @@ +package duke.command; + +import duke.exception.DukeException; +import duke.exception.EmptyDescriptionException; +import duke.exception.TaskNotFoundException; +import duke.task.Task; +import duke.task.TaskList; +import duke.Storage; +import duke.Ui; + +/** + * Represents the user command when the user tries to delete a task from the task list. + */ +public class DeleteCommand extends Command { + private String command; + + /** + * Represents a constructor for the DeleteCommand class where the user command is initialized. + * + * @param command Command entered by the user. + */ + public DeleteCommand(String command) { + super(command); + this.command = command; + } + + /** + * Returns the string representation of the class. + * + * @return String description of the class. + */ + public String toString() { + return "This is a delete command"; + } + + /** + * Executes the response when the user enters a delete command and updates the task list and storage + * file (duke.txt) + * + * @param taskList TaskList that stores the tasks. + * @param storage Storage that deals with loading tasks from the file and saving tasks in the file. + * @return String representation of the task that is deleted by the user as well as the number of + * tasks remaining in the task list. + * @throws DukeException If user doesn't provide a description for the command or tries to access a task + * that doesn't exist. + */ + public String execute(TaskList taskList, Storage storage) throws DukeException { + if (command.trim().length() <= 6) { + throw new EmptyDescriptionException(); + } + + int value = Integer.parseInt(command.replaceAll("[^0-9]", "")); + if (value > taskList.getSize() || value < 0) { + throw new TaskNotFoundException(); + } + + Task task = taskList.getTask(value-1); + taskList.removeTask(value-1); + boolean isTaskPresent = taskList.isTaskPresent(task); + assert isTaskPresent == false: "isTaskPresent should be false since the task is removed from the task list"; + + storage.writeToFile("./duke.txt", taskList); + + Ui ui = new Ui(taskList, storage); + String response = ui.deleteResponse(task); + return response; + } +} diff --git a/src/main/java/duke/command/DoneCommand.java b/src/main/java/duke/command/DoneCommand.java new file mode 100644 index 0000000000..ec8b5cd71b --- /dev/null +++ b/src/main/java/duke/command/DoneCommand.java @@ -0,0 +1,66 @@ +package duke.command; + +import duke.exception.DukeException; +import duke.exception.EmptyDescriptionException; +import duke.exception.TaskNotFoundException; +import duke.task.Task; +import duke.task.TaskList; +import duke.Storage; +import duke.Ui; + +/** + * Represents the user command when the user is done with a task in the task list. + */ +public class DoneCommand extends Command { + private String command; + + /** + * Represents a constructor for the DoneCommand class where the user command is initialized. + * + * @param command Command entered by the user. + */ + public DoneCommand(String command) { + super(command); + this.command = command; + } + + /** + * Returns the string representation of the class. + * + * @return String description of the class. + */ + public String toString() { + return "This is a done command"; + } + + /** + * Executes the response when the user enters a done command and updates the task list and storage + * file (duke.txt) + * + * @param taskList TaskList that stores the tasks. + * @param storage Storage that deals with loading tasks from the file and saving tasks in the file. + * @return String representation of the task that is done by the user. + * @throws DukeException If user doesn't provide a description for the command or tries to access a task + * that doesn't exist. + */ + public String execute(TaskList taskList, Storage storage) throws DukeException { + if (command.trim().length() <= 4) { + throw new EmptyDescriptionException(); + } + + int value = Integer.parseInt(command.replaceAll("[^0-9]", "")); + if (value > taskList.getSize() || value < 0) { + throw new TaskNotFoundException(); + } + + Task task = taskList.getTask(value - 1); + task.markAsDone(); + assert task.getStatusIcon().equals("X"): "Since the task is marked as done, the status icon returned should be X"; + + storage.writeToFile("./duke.txt", taskList); + + Ui ui = new Ui(taskList, storage); + String response = ui.doneResponse(task); + return response; + } +} diff --git a/src/main/java/duke/command/EditCommand.java b/src/main/java/duke/command/EditCommand.java new file mode 100644 index 0000000000..31c648ecec --- /dev/null +++ b/src/main/java/duke/command/EditCommand.java @@ -0,0 +1,185 @@ +package duke.command; + +import duke.Ui; +import duke.task.Task; +import duke.task.TaskList; +import duke.task.Todo; +import duke.task.Deadline; +import duke.task.Event; +import duke.Storage; +import duke.exception.EmptyDescriptionException; +import duke.exception.DukeException; +import duke.exception.InvalidDateTimeException; +import duke.exception.InvalidTaskCommandException; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + +/** + * Represents the user command when the user edits an item in the task list. + */ +public class EditCommand extends Command { + private String command; + private Storage storage; + + /** + * Represents a constructor for the EditCommand class where the user command is initialized. + * + * @param command Command entered by the user. + */ + public EditCommand(String command) { + super(command); + this.command = command; + } + + /** + * Returns the string representation of the class. + * + * @return String description of the class. + */ + public String toString() { + return "This is an edit command"; + } + + /** + * Executes the response when the user enters an edit command to edit a task in the task list. + * + * @param taskList TaskList that stores the tasks. + * @param storage Storage that deals with loading tasks from the file and saving tasks in the file. + * @return String representation of the updated task list. + * @throws DukeException If there is an error. + */ + public String execute(TaskList taskList, Storage storage) throws DukeException { + if (command.trim().length() <= 4) { + throw new EmptyDescriptionException(); + } + + String[] parts = command.split("/", 2); + if (parts.length <= 1) { + throw new InvalidTaskCommandException(); + } + + this.storage = storage; + String str = parts[1]; + if (str.startsWith("description")) { + return editDescription(parts, taskList); + } else if (str.startsWith("task")) { + return editTask(parts, taskList); + } else if (str.startsWith("datetime")) { + return editDateTime(parts, taskList); + } else { + throw new InvalidTaskCommandException(); + } + } + + private String editTask(String[] parts, TaskList taskList) throws DukeException { + String str = parts[1].substring(5); + int index = Integer.parseInt(parts[0].substring(5).trim()); + + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm"); + String[] furtherParts = str.split("/", 2); + Task newTask = null; + + try { + if (str.startsWith("deadline")) { + LocalDateTime dateTime = LocalDateTime.parse(furtherParts[1].substring(3).trim(), dtf); + newTask = new Deadline(furtherParts[0].substring(9), dateTime); + taskList.modifyTask(newTask, index-1); + + } else if (str.startsWith("event")) { + LocalDateTime dateTime = LocalDateTime.parse(furtherParts[1].substring(3).trim(), dtf); + newTask = new Event(furtherParts[0].substring(6), dateTime); + taskList.modifyTask(newTask, index-1); + + } else if (str.startsWith("todo")) { + taskList.modifyTask(new Todo(str.substring(5)), index - 1); + + } else { + throw new InvalidTaskCommandException(); + } + } catch (DateTimeParseException e) { + throw new InvalidDateTimeException(); + } + + storage.writeToFile("./duke.txt", taskList); + + Ui ui = new Ui(taskList, storage); + return ui.editTaskResponse(index); + } + + private String editDescription(String[] parts, TaskList taskList) throws InvalidTaskCommandException { + String str = parts[1]; + int index = Integer.parseInt(parts[0].substring(5).trim()); + Task oldTask = taskList.getTask(index-1); + boolean isDone = oldTask.isDone(); + Task newTask = null; + + if (oldTask.toString().startsWith("[D]") || oldTask.toString().startsWith("[E]")) { + String newDescription = str.substring(12); + newTask = this.assignNewTask(oldTask, newDescription, oldTask.getDate()); + taskList.modifyTask(newTask, index-1); + + } else if (oldTask.toString().startsWith("[T]")) { + taskList.modifyTask(new Todo(str.substring(12)), index-1); + + } else { + throw new InvalidTaskCommandException(); + } + + if (isDone) { + newTask.markAsDone(); + } + + storage.writeToFile("./duke.txt", taskList); + + Ui ui = new Ui(taskList, storage); + return ui.editDescriptionResponse(index); + } + + private String editDateTime(String[] parts, TaskList taskList) throws DukeException { + String str = parts[1]; + int index = Integer.parseInt(parts[0].substring(5).trim()); + Task oldTask = taskList.getTask(index-1); + boolean isDone = oldTask.isDone(); + Task newTask = null; + + if (oldTask.toString().startsWith("[D]") || oldTask.toString().startsWith("[E]")) { + try { + String newDateTime = str.substring(9); + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm"); + LocalDateTime dateTime = LocalDateTime.parse(newDateTime.trim(), dtf); + + String description = oldTask.getDescription(); + newTask = this.assignNewTask(oldTask, description, dateTime); + taskList.modifyTask(newTask, index-1); + + } catch (DateTimeParseException e) { + throw new InvalidDateTimeException(); + } + + } else { + throw new InvalidTaskCommandException(); + } + + if (isDone) { + newTask.markAsDone(); + } + + storage.writeToFile("./duke.txt", taskList); + + Ui ui = new Ui(taskList, storage); + return ui.editDateTimeResponse(index); + } + + private Task assignNewTask(Task oldTask, String description, LocalDateTime dateTime) { + Task newTask = null; + if (oldTask.toString().startsWith("[D]")) { + newTask = new Deadline(description, dateTime); + + } else if (oldTask.toString().startsWith("[E]")) { + newTask = new Event(description, dateTime); + } + return newTask; + } +} diff --git a/src/main/java/duke/command/EventCommand.java b/src/main/java/duke/command/EventCommand.java new file mode 100644 index 0000000000..44a824deb2 --- /dev/null +++ b/src/main/java/duke/command/EventCommand.java @@ -0,0 +1,84 @@ +package duke.command; + +import duke.task.Task; +import duke.task.TaskList; +import duke.task.Event; +import duke.Storage; +import duke.exception.DukeException; +import duke.exception.EmptyDescriptionException; +import duke.exception.InvalidDateTimeException; +import duke.exception.InvalidTaskCommandException; +import duke.Ui; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + +/** + * Represents the user command when the user adds an event to the task list. + */ +public class EventCommand extends Command { + private String command; + + /** + * Represents a constructor for the EventCommand class where the user command is initialized. + * + * @param command Command entered by the user. + */ + public EventCommand(String command) { + super(command); + this.command = command; + } + + /** + * Returns the string representation of the class. + * + * @return String description of the class. + */ + public String toString() { + return "This is an event command"; + } + + /** + * Executes the response when the user enters an event command and updates the task list and storage + * file (duke.txt) + * + * @param taskList TaskList that stores the tasks. + * @param storage Storage that deals with loading tasks from the file and saving tasks in the file. + * @return String representation of the new event task as well as the number of tasks in the task list. + * @throws DukeException If user doesn't provide a description for the command or enters the command in invalid format. + */ + public String execute(TaskList taskList, Storage storage) throws DukeException { + if (command.trim().length() <= 5) { + throw new EmptyDescriptionException(); + } + + String[] parts = command.split("/"); + if (parts.length <= 1) { + throw new InvalidTaskCommandException(); + } + + if (parts[1].trim().equals("") || !parts[1].startsWith("at ")) { + throw new InvalidTaskCommandException(); + } + + try { + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm"); + LocalDateTime dateTime = LocalDateTime.parse(parts[1].substring(3).trim(), dtf); + + Task task = new Event(parts[0].substring(6), dateTime); + taskList.addTask(task); + assert taskList.getTask(taskList.getSize() - 1).equals(task): "last element in the task list should be " + + "equivalent to the most recently added task"; + + storage.writeToFile("./duke.txt", taskList); + + Ui ui = new Ui(taskList, storage); + String response = ui.taskResponse(task); + return response; + + } catch (DateTimeParseException e) { + throw new InvalidDateTimeException(); + } + } +} diff --git a/src/main/java/duke/command/FindCommand.java b/src/main/java/duke/command/FindCommand.java new file mode 100644 index 0000000000..73b9c73a26 --- /dev/null +++ b/src/main/java/duke/command/FindCommand.java @@ -0,0 +1,55 @@ +package duke.command; + +import duke.exception.DukeException; +import duke.exception.EmptyDescriptionException; +import duke.task.TaskList; +import duke.Storage; +import duke.Ui; + +/** + * Represents the user command when the user wants to filter tasks that contain a common matching word. + */ +public class FindCommand extends Command { + private String command; + + /** + * Represents a constructor for the FindCommand class where the user command is initialized. + * + * @param command Command entered by the user. + */ + public FindCommand(String command) { + super(command); + this.command = command; + } + + /** + * Returns the string representation of the class. + * + * @return String description of the class. + */ + public String toString() { + return "This is a find command"; + } + + /** + * Executes the response when the user enters a find command + * + * @param taskList TaskList that stores the tasks. + * @param storage Storage that deals with loading tasks from the file and saving tasks in the file. + * @return String representation of the filtered tasks in the task list that contain the matching word + * entered by the user in the find command. + * @throws DukeException If user doesn't provide a description for the find command. + */ + public String execute(TaskList taskList, Storage storage) throws EmptyDescriptionException { + if (command.trim().length() <= 4) { + throw new EmptyDescriptionException(); + } + + String[] parts = this.command.split(" ", 2); + String wordToFind = parts[1]; + + Ui ui = new Ui(taskList, storage); + String response = ui.findResponse(wordToFind, taskList); + return response; + } +} diff --git a/src/main/java/duke/command/InvalidCommand.java b/src/main/java/duke/command/InvalidCommand.java new file mode 100644 index 0000000000..e313d1dc69 --- /dev/null +++ b/src/main/java/duke/command/InvalidCommand.java @@ -0,0 +1,45 @@ +package duke.command; + +import duke.Ui; +import duke.task.TaskList; +import duke.Storage; + +/** + * Represents the user command when the user enters an invalid command. + */ +public class InvalidCommand extends Command { + private String command; + + /** + * Represents a constructor for the InvalidCommand class where the user command is initialized. + * + * @param command Command entered by the user. + */ + public InvalidCommand(String command) { + super(command); + this.command = command; + } + + /** + * Returns the string representation of the class. + * + * @return String description of the class. + */ + public String toString() { + return "This is an invalid command"; + } + + /** + * Returns an error message when the user enters an invalid command. + * + * @param taskList TaskList that stores the tasks. + * @param storage Storage that deals with loading tasks from the file and saving tasks in the file. + * @return String response to an invalid command. + */ + public String execute(TaskList taskList, Storage storage) { + String response = "OOPS!!! I'm sorry, but I don't know what that means :-( \n\n" + "Please refer to the" + + " user guide to view all the possible commands and their formats!"; + Ui.printInput(response); + return response; + } +} diff --git a/src/main/java/duke/command/ListCommand.java b/src/main/java/duke/command/ListCommand.java new file mode 100644 index 0000000000..ed512ee795 --- /dev/null +++ b/src/main/java/duke/command/ListCommand.java @@ -0,0 +1,42 @@ +package duke.command; + +import duke.task.TaskList; +import duke.Storage; + +/** + * Represents the user command when the user wants to view the task list. + */ +public class ListCommand extends Command { + private String command; + + /** + * Represents a constructor for the ListCommand class where the user command is initialized. + * + * @param command Command entered by the user. + */ + public ListCommand(String command) { + super(command); + this.command = command; + } + + /** + * Returns the string representation of the class. + * + * @return String description of the class. + */ + public String toString() { + return "This is a list command"; + } + + /** + * Returns the task list when the user enters the list command. + * + * @param taskList TaskList that stores the tasks. + * @param storage Storage that deals with loading tasks from the file and saving tasks in the file. + * @return String representation of the task list. + */ + public String execute(TaskList taskList, Storage storage) { + String response = taskList.printList(); + return response; + } +} diff --git a/src/main/java/duke/command/TodoCommand.java b/src/main/java/duke/command/TodoCommand.java new file mode 100644 index 0000000000..a829a8c093 --- /dev/null +++ b/src/main/java/duke/command/TodoCommand.java @@ -0,0 +1,61 @@ +package duke.command; + +import duke.task.Task; +import duke.task.TaskList; +import duke.task.Todo; +import duke.Storage; +import duke.exception.DukeException; +import duke.exception.EmptyDescriptionException; +import duke.Ui; + +/** + * Represents the user command when the user enters a todo task. + */ +public class TodoCommand extends Command { + private String command; + + /** + * Represents a constructor for the TodoCommand class where the user command is initialized. + * + * @param command Command entered by the user. + */ + public TodoCommand(String command) { + super(command); + this.command = command; + } + + /** + * Returns the string representation of the class. + * + * @return String description of the class. + */ + public String toString() { + return "This is a todo command"; + } + + /** + * Executes the response when the user enters a todo command and updates the task list and storage + * file (duke.txt) + * + * @param taskList TaskList that stores the tasks. + * @param storage Storage that deals with loading tasks from the file and saving tasks in the file. + * @return String representation of the new todo task as well as the number of tasks in the task list. + * @throws DukeException If user doesn't provide a description for the todo command. + */ + public String execute(TaskList taskList, Storage storage) throws EmptyDescriptionException { + if (command.trim().length() <= 4) { + throw new EmptyDescriptionException(); + } + + Task task = new Todo(command.substring(5)); + taskList.addTask(task); + assert taskList.getTask(taskList.getSize() - 1).equals(task): "last element in the task list should be " + + "equivalent to the most recently added task"; + + storage.writeToFile("./duke.txt", taskList); + + Ui ui = new Ui(taskList, storage); + String response = ui.taskResponse(task); + return response; + } +} diff --git a/src/main/java/duke/exception/DukeException.java b/src/main/java/duke/exception/DukeException.java new file mode 100644 index 0000000000..cb9769b6e1 --- /dev/null +++ b/src/main/java/duke/exception/DukeException.java @@ -0,0 +1,26 @@ +package duke.exception; + +/** + * Encapsulates the main exception for Duke. + */ +public class DukeException extends Exception { + + /** + * Represents a constructor for the DukeException class where the exception message is initialized. + * + * @param message Exception message that is shown to the user. + */ + public DukeException(String message) { + super(message); + } + + /** + * Returns the string representation of the class. + * + * @return String description of the class. + */ + @Override + public String toString() { + return super.toString(); + } +} diff --git a/src/main/java/duke/exception/EmptyDescriptionException.java b/src/main/java/duke/exception/EmptyDescriptionException.java new file mode 100644 index 0000000000..3032c624bc --- /dev/null +++ b/src/main/java/duke/exception/EmptyDescriptionException.java @@ -0,0 +1,25 @@ +package duke.exception; + +/** + * Encapsulates the exception when the user doesn't provide any description for the command. + */ +public class EmptyDescriptionException extends DukeException { + + /** + * Represents a constructor for the EmptyDescriptionException class. + */ + public EmptyDescriptionException() { + super("OOPS!!! The description of this command cannot be empty. Refer to the user guide to view " + + "the correct format of this command!"); + } + + /** + * Returns the string representation of the class. + * + * @return String description of the class. + */ + @Override + public String toString() { + return super.toString(); + } +} diff --git a/src/main/java/duke/exception/InvalidDateTimeException.java b/src/main/java/duke/exception/InvalidDateTimeException.java new file mode 100644 index 0000000000..a0399d0157 --- /dev/null +++ b/src/main/java/duke/exception/InvalidDateTimeException.java @@ -0,0 +1,24 @@ +package duke.exception; + +/** + * Encapsulates the exception when the user enters an invalid date and time format. + */ +public class InvalidDateTimeException extends DukeException { + + /** + * Represents a constructor for the InvalidDateTimeException class. + */ + public InvalidDateTimeException() { + super("The format of your date and time is incorrect! It should be "); + } + + /** + * Returns the string representation of the class. + * + * @return String description of the class. + */ + @Override + public String toString() { + return super.toString(); + } +} diff --git a/src/main/java/duke/exception/InvalidTaskCommandException.java b/src/main/java/duke/exception/InvalidTaskCommandException.java new file mode 100644 index 0000000000..1be7af5e99 --- /dev/null +++ b/src/main/java/duke/exception/InvalidTaskCommandException.java @@ -0,0 +1,25 @@ +package duke.exception; + +/** + * Encapsulates the exception when the user enters an invalid task command. + */ +public class InvalidTaskCommandException extends DukeException { + + /** + * Represents a constructor for the InvalidTaskCommandException class. + */ + public InvalidTaskCommandException() { + super("Your command is not in the right format! Please refer to the user guide to view" + + " the correct format for various types of task commands!"); + } + + /** + * Returns the string representation of the class. + * + * @return String description of the class. + */ + @Override + public String toString() { + return super.toString(); + } +} diff --git a/src/main/java/duke/exception/TaskNotFoundException.java b/src/main/java/duke/exception/TaskNotFoundException.java new file mode 100644 index 0000000000..f6b7670741 --- /dev/null +++ b/src/main/java/duke/exception/TaskNotFoundException.java @@ -0,0 +1,24 @@ +package duke.exception; + +/** + * Encapsulates the exception when the user tries to find a task that doesn't exist. + */ +public class TaskNotFoundException extends DukeException { + + /** + * Represents a constructor for the TaskNotFoundException class. + */ + public TaskNotFoundException() { + super("Sorry, the task you are looking for doesn't exist!"); + } + + /** + * Returns the string representation of the class. + * + * @return String description of the class. + */ + @Override + public String toString() { + return super.toString(); + } +} diff --git a/src/main/java/duke/task/Deadline.java b/src/main/java/duke/task/Deadline.java new file mode 100644 index 0000000000..107c8008f0 --- /dev/null +++ b/src/main/java/duke/task/Deadline.java @@ -0,0 +1,54 @@ +package duke.task; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * Represents a task of type deadline in the task list. + */ +public class Deadline extends Task { + protected LocalDateTime by; + private String formattedDtf; + + /** + * Represents a constructor for the Deadline class where the description of task and date are initialized. + * + * @param description Description of the task. + * @param by The date of deadline in yyyy-MM-dd HHmm format. + */ + public Deadline(String description, LocalDateTime by) { + super(description); + this.by = by; + + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MMM d yyyy, h a"); + String formattedDtf = this.by.format(dtf); + this.formattedDtf = formattedDtf; + } + + /** + * Returns the string representation of the deadline task that is stored on duke.txt. + * + * @return String representation of the deadline task stored on duke.txt. + */ + public String getTaskListOnDisk() { + return "duke.task.Deadline |" + super.getStatusIcon() + "| " + description + " | by: " + formattedDtf; + } + + /** + * Returns the string representation of the deadline task that is stored in the task list. + * + * @return String description of the deadline task. + */ + @Override + public String toString() { + return "[D]" + super.toString() + " (by: " + formattedDtf + ")"; + } + + public String getDescription() { + return this.description; + } + + public LocalDateTime getDate() { + return by; + } +} diff --git a/src/main/java/duke/task/Event.java b/src/main/java/duke/task/Event.java new file mode 100644 index 0000000000..ab721b8765 --- /dev/null +++ b/src/main/java/duke/task/Event.java @@ -0,0 +1,54 @@ +package duke.task; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * Represents a task of type event in the task list. + */ +public class Event extends Task { + protected LocalDateTime at; + private String formattedDtf; + + /** + * Represents a constructor for the Event class where the description of task and date are initialized. + * + * @param description Description of the task. + * @param at The date of the event in yyyy-MM-dd HHmm format. + */ + public Event(String description, LocalDateTime at) { + super(description); + this.at = at; + + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MMM d yyyy, h a"); + String formattedDtf = this.at.format(dtf); + this.formattedDtf = formattedDtf; + } + + /** + * Returns the string representation of the event task that is stored on duke.txt. + * + * @return String representation of the event task stored on duke.txt. + */ + public String getTaskListOnDisk() { + return "duke.task.Event |" + super.getStatusIcon() + "| " + description + " | at: " + formattedDtf; + } + + /** + * Returns the string representation of the event task that is stored in the task list. + * + * @return String description of the event task. + */ + @Override + public String toString() { + return "[E]" + super.toString() + " (at: " + formattedDtf + ")"; + } + + public String getDescription() { + return this.description; + } + + public LocalDateTime getDate() { + return this.at; + } +} diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java new file mode 100644 index 0000000000..d163e84fc1 --- /dev/null +++ b/src/main/java/duke/task/Task.java @@ -0,0 +1,67 @@ +package duke.task; + +import java.time.LocalDateTime; + +/** + * Represents the various types of tasks that can be added to the task list. + */ +public abstract class Task { + protected String description; + protected boolean isDone; + + /** + * Represents a constructor for the Task class where variables are initialized. + * + * @param description Description of the task. + */ + public Task(String description) { + this.description = description; + this.isDone = false; + } + + /** + * Checks if the task has been completed or not. + * + * @return Either X or an empty string depending on whether the task is completed or not. + */ + public String getStatusIcon() { + return (isDone ? "X" : " "); + } + + public abstract LocalDateTime getDate(); + + public abstract String getDescription(); + + /** + * Marks the task as completed. + */ + public void markAsDone() { + this.isDone = true; + } + + /** + * Checks if the task is done or not. + * + * @return true or false. + */ + public boolean isDone() { + return this.isDone; + } + + /** + * Denotes the string representation of the task list that is stored on duke.txt. + * + * @return String representation of task list stored on duke.txt. + */ + public abstract String getTaskListOnDisk(); + + /** + * Returns the string representation of the task that is stored in the task list. + * + * @return String description of the task. + */ + @Override + public String toString() { + return "[" + this.getStatusIcon() + "]" + " " + this.description; + } +} diff --git a/src/main/java/duke/task/TaskList.java b/src/main/java/duke/task/TaskList.java new file mode 100644 index 0000000000..fe925e5b09 --- /dev/null +++ b/src/main/java/duke/task/TaskList.java @@ -0,0 +1,103 @@ +package duke.task; + +import duke.Ui; + +import java.util.ArrayList; + +/** + * Represents the list of tasks that are added by the user. + */ +public class TaskList { + private ArrayList userList; + + /** + * Represents a constructor for the TaskList class where the task list is initialized as an array list. + */ + public TaskList() { + userList = new ArrayList<>(); + } + + /** + * Returns every task in the task list. + * + * @return String representation of the various tasks (if any) in the task list. + */ + public String printList() { + if (userList.isEmpty()) { + String response = Ui.printInput("You don't have any tasks in the list!"); + return response; + } + + String response = ""; + int count = 1; + for (int i = 0; i < userList.size(); i++) { + Task t = userList.get(i); + Ui.printInput(t.toString()); + response += count + ". " + t + "\n"; + count++; + } + return response; + } + + /** + * Returns the size of the task list. + * + * @return Number of items in the task list. + */ + public int getSize() { + return userList.size(); + } + + /** + * Returns the task at the specified index (val) from the task list. + * + * @param val Index value. + * @return Task object. + */ + public Task getTask(int val) { + return userList.get(val); + } + + /** + * Adds the specified task to the task list. + * + * @param task Task object. + */ + public void addTask(Task task) { + userList.add(task); + } + + /** + * Removes the task at the specified index (val) from the task list. + * + * @param val Index value. + */ + public void removeTask(int val) { + userList.remove(val); + } + + /** + * Checks if the specified task is present in the task list. + * + * @param task Task object. + * @return true or false. + */ + public boolean isTaskPresent(Task task) { + for (int i = 0; i < userList.size(); i++) { + if (userList.get(i).equals(task)) { + return true; + } + } + return false; + } + + /** + * Modifies a specified task in a specific index in the task list. + * + * @param task Task object. + * @param index Integer position of the task in the task list that is to be modified. + */ + public void modifyTask(Task task, int index) { + userList.set(index, task); + } +} diff --git a/src/main/java/duke/task/Todo.java b/src/main/java/duke/task/Todo.java new file mode 100644 index 0000000000..dbf2d865dc --- /dev/null +++ b/src/main/java/duke/task/Todo.java @@ -0,0 +1,45 @@ +package duke.task; + +import java.time.LocalDateTime; + +/** + * Represents a task of type todo in the task list. + */ +public class Todo extends Task { + + /** + * Represents a constructor for the Todo class where the description of task is initialized. + * + * @param description Description of the task. + */ + public Todo(String description) { + super(description); + } + + /** + * Returns the string representation of the todo task that is stored on duke.txt. + * + * @return String representation of the todo task stored on duke.txt. + */ + public String getTaskListOnDisk() { + return "duke.task.Todo |" + super.getStatusIcon() + "| " + description; + } + + /** + * Returns the string representation of the todo task that is stored in the task list. + * + * @return String description of the todo task. + */ + @Override + public String toString() { + return "[T]" + super.toString(); + } + + public LocalDateTime getDate() { + return null; + } + + public String getDescription() { + return this.description; + } +} 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/images/anonymous.png b/src/main/resources/images/anonymous.png new file mode 100644 index 0000000000..4edceb631c Binary files /dev/null and b/src/main/resources/images/anonymous.png differ diff --git a/src/main/resources/images/duke_img.png b/src/main/resources/images/duke_img.png new file mode 100644 index 0000000000..51f9dd9ca3 Binary files /dev/null and b/src/main/resources/images/duke_img.png differ diff --git a/src/main/resources/view/DialogBox.fxml b/src/main/resources/view/DialogBox.fxml new file mode 100644 index 0000000000..cecbc478c8 --- /dev/null +++ b/src/main/resources/view/DialogBox.fxml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + \ 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..15d819bd5d --- /dev/null +++ b/src/main/resources/view/MainWindow.fxml @@ -0,0 +1,19 @@ + + + + + + + + + + + +