diff --git a/README.md b/README.md deleted file mode 100644 index 8715d4d915..0000000000 --- a/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# 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. - -## Setting up in Intellij - -Prerequisites: JDK 11, update Intellij to the most recent version. - -1. Open Intellij (if you are not in the welcome screen, click `File` > `Close Project` to close the existing project first) -1. Open the project into Intellij as follows: - 1. Click `Open`. - 1. Select the project directory, and click `OK`. - 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: - ``` - Hello from - ____ _ - | _ \ _ _| | _____ - | | | | | | | |/ / _ \ - | |_| | |_| | < __/ - |____/ \__,_|_|\_\___| - ``` diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000000..84a5d2c694 --- /dev/null +++ b/build.gradle @@ -0,0 +1,52 @@ +plugins { + id 'java' + id 'application' + id 'com.github.johnrengelman.shadow' version '5.1.0' + id 'checkstyle' +} + +checkstyle { + toolVersion = '10.2' +} + +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() +} + +application { + mainClassName = "Launcher" +} + +shadowJar { + archiveBaseName = "dook" + archiveClassifier = null +} + +run{ + standardInput = System.in +} \ No newline at end of file diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml new file mode 100644 index 0000000000..d618671b83 --- /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/docs/README.md b/docs/README.md index 8077118ebe..d2462a16d0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,29 +1,100 @@ -# User Guide +# DOOK -## Features +## Quick start -### Feature-ABC +1. Ensure you have Java `11` or above installed in your Computer. -Description of the feature. +1. Download the latest `dook.jar` from [here](https://github.com/iapetusbob/ip/releases). -### Feature-XYZ +1. Copy the file to the folder you want to use as the _home folder_ for your DOOK. -Description of the feature. +1. Open a command terminal, `cd` into the folder you put the jar file in, and use the `java -jar dook.jar` command to run the application.
+ A GUI similar to the below should appear in a few seconds. Note how the app contains some sample data.
+ ![Ui](Ui.png) -## Usage +1. Type the command in the command box and press Enter to execute it. e.g. typing **`help`** and pressing Enter will show all the commands at your disposal.
+ Some example commands you can try: -### `Keyword` - Describe action + * `list` : Lists all contacts. -Describe the action and its outcome. + * `add todo Buy Carrots` : Adds a task of type *Todo* called **Buy Carrots** to the list. -Example of usage: + * `delete 3` : Deletes the 3rd task hown in the tasklist. -`keyword (optional arguments)` + * `bye` : Saves the current tasklist into the harddrive for next boot up of DOOK. -Expected outcome: +1. Refer to the [Features](#features) below for details of each command. -Description of the outcome. +## Features: -``` -expected output -``` +### Viewing help : ``help`` + +Brings users to the help page. + +Format: ``help`` + +### Adding a task: ``add`` + +Adds a task to the list. + +Format: ``add `` + +Examples: + +``add todo buy onions and garlic`` + +``add event Jack Birthday Party /from 10/10/23 1700 /to 10/10/23 2200`` + + * Types of Tasks supported: + * **Todo** : The simplest type of task, all it needs is the name of the task. + * ``add todo Buy Carrots`` + * **Deadline** : A type of task with a due date, or a *deadline*. use ``/by`` to indicate the due date. + * ``add deadline Return Book /by 10/10/2023 12:00 pm`` + * **Event** : A task with a start date and time, and an end date and time. Use ``/from`` to indicate the start date and time, and ``/to`` for the end date and time. + * ``add event Jack's Birthday Party /from 11/11/2023 1700 /to 11/11/2023 2200`` + +### Listing all tasks : ``list`` + +Shows a list of all tasks in the list. + +Format: ``list`` + +### Finding via keywords : ``find `` + +Finds tasks in the list with sepcified keywords. + +Format: ``find <...>`` + +Examples : + +``find buy marked`` + + * **Note** : With ``find``, the list of tasks shown with the relevant keywords are shown with their original indexing, i.e. the shown tasks after ``find``-ing may not be in consecutive indexing, but their original positions in the list. + +### Marking tasks : ``mark `` + +Marks the task at specified index as done. + +Format : ``mark `` + +Examples : + +``mark 2`` + +### Unmarking : ``unmark`` + +Unmarks the task with specified index. + +Format : ``unmark 2`` + +### Deleting a person : ``delete`` + +Deletes the specified task from the list. + +Format: ``delete`` + +### Saving the data : ``bye`` + +Saves the current list for next bootup of DOOK. + +Format : ``bye`` diff --git a/docs/Ui.png b/docs/Ui.png new file mode 100644 index 0000000000..aeb84f8008 Binary files /dev/null and b/docs/Ui.png differ diff --git a/docs/UserGuide.md b/docs/UserGuide.md new file mode 100644 index 0000000000..d2462a16d0 --- /dev/null +++ b/docs/UserGuide.md @@ -0,0 +1,100 @@ +# DOOK + +## Quick start + +1. Ensure you have Java `11` or above installed in your Computer. + +1. Download the latest `dook.jar` from [here](https://github.com/iapetusbob/ip/releases). + +1. Copy the file to the folder you want to use as the _home folder_ for your DOOK. + +1. Open a command terminal, `cd` into the folder you put the jar file in, and use the `java -jar dook.jar` command to run the application.
+ A GUI similar to the below should appear in a few seconds. Note how the app contains some sample data.
+ ![Ui](Ui.png) + +1. Type the command in the command box and press Enter to execute it. e.g. typing **`help`** and pressing Enter will show all the commands at your disposal.
+ Some example commands you can try: + + * `list` : Lists all contacts. + + * `add todo Buy Carrots` : Adds a task of type *Todo* called **Buy Carrots** to the list. + + * `delete 3` : Deletes the 3rd task hown in the tasklist. + + * `bye` : Saves the current tasklist into the harddrive for next boot up of DOOK. + +1. Refer to the [Features](#features) below for details of each command. + +## Features: + +### Viewing help : ``help`` + +Brings users to the help page. + +Format: ``help`` + +### Adding a task: ``add`` + +Adds a task to the list. + +Format: ``add `` + +Examples: + +``add todo buy onions and garlic`` + +``add event Jack Birthday Party /from 10/10/23 1700 /to 10/10/23 2200`` + + * Types of Tasks supported: + * **Todo** : The simplest type of task, all it needs is the name of the task. + * ``add todo Buy Carrots`` + * **Deadline** : A type of task with a due date, or a *deadline*. use ``/by`` to indicate the due date. + * ``add deadline Return Book /by 10/10/2023 12:00 pm`` + * **Event** : A task with a start date and time, and an end date and time. Use ``/from`` to indicate the start date and time, and ``/to`` for the end date and time. + * ``add event Jack's Birthday Party /from 11/11/2023 1700 /to 11/11/2023 2200`` + +### Listing all tasks : ``list`` + +Shows a list of all tasks in the list. + +Format: ``list`` + +### Finding via keywords : ``find `` + +Finds tasks in the list with sepcified keywords. + +Format: ``find <...>`` + +Examples : + +``find buy marked`` + + * **Note** : With ``find``, the list of tasks shown with the relevant keywords are shown with their original indexing, i.e. the shown tasks after ``find``-ing may not be in consecutive indexing, but their original positions in the list. + +### Marking tasks : ``mark `` + +Marks the task at specified index as done. + +Format : ``mark `` + +Examples : + +``mark 2`` + +### Unmarking : ``unmark`` + +Unmarks the task with specified index. + +Format : ``unmark 2`` + +### Deleting a person : ``delete`` + +Deletes the specified task from the list. + +Format: ``delete`` + +### Saving the data : ``bye`` + +Saves the current list for next bootup of DOOK. + +Format : ``bye`` diff --git a/gradle/wrapper/.idea/vcs.xml b/gradle/wrapper/.idea/vcs.xml new file mode 100644 index 0000000000..b2bdec2d71 --- /dev/null +++ b/gradle/wrapper/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/gradle/wrapper/.idea/workspace.xml b/gradle/wrapper/.idea/workspace.xml new file mode 100644 index 0000000000..6b70686356 --- /dev/null +++ b/gradle/wrapper/.idea/workspace.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1675932079737 + + + + \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..7454180f2a Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..69a9715077 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000000..744e882ed5 --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MSYS* | MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000000..107acd32c4 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/src/main/java/DOOK.java b/src/main/java/DOOK.java new file mode 100644 index 0000000000..6590082e00 --- /dev/null +++ b/src/main/java/DOOK.java @@ -0,0 +1,104 @@ +import java.io.IOException; + +import DukeHelpfulCode.Exceptions.*; +import DukeHelpfulCode.Utilities.*; +import DukeHelpfulCode.Commands.*; + + +/** + * The DOOK program is adapted DUKE from NUS SoC CS2103 + * DOOK is a glorified to-do list. + * + * @author Yuan Hao + * @version who knows + * @since 11 Feb 2023 + */ + +public class DOOK { + + private static String LINEBREAK = "_________________________________________________________________\n"; + private static TaskList USERLIST = new TaskList(); + + private UI ui; + private Storage storage; + private TaskList tasks; + + public DOOK(){ + this.ui = new UI(); + this.storage = new Storage("tasks.txt"); + try { + this.tasks = new TaskList(storage.load()); + } catch (DukeException e) { // e should be EmptyTaskListException + ui.showLoadingError(); + this.tasks = new TaskList(); + } catch (IOException e) { + e.printStackTrace(); + this.tasks = new TaskList(); + } + } + + public void makeDOOK(String filePath) { + this.ui = new UI(); + this.storage = new Storage(filePath); + try { + this.tasks = new TaskList(storage.load()); + } catch (DukeException e) { // e should be EmptyTaskListException + ui.showLoadingError(); + this.tasks = new TaskList(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Runs DOOK. + */ + public void run() { + boolean isExit = false; + while (!isExit) { + try { + String fullCommand = ui.readCommand(); + ui.showLine(); // show the divider line ("_______") + Command c = Parser.parse(fullCommand); + c.execute(tasks); + isExit = c.isExit(); + } catch (DukeException e) { + ui.showError(e.getMessage()); + } finally { + ui.showLine(); + } + } + } + + protected String getResponse(String input) { + if (!input.equals("bye")) { + try { + Command c = Parser.parse(input); + return c.execute(tasks); + } catch (NoSuchTaskException e) { + return "Sorry, I can't find this task."; + } catch (TaskAlrMarkException e) { + return "Sorry but this task is already marked."; + } catch (TaskAlrUnmarkException e) { + return "Sorry but this task is not marked."; + } catch (DukeException e) { + return "Sorry, I don't understand."; + } + } + else { + try { + storage.write(tasks); + return new ExitCommand().execute(tasks); + } catch (IOException e) { + return "lol"; + } + } + + } + + public static void main(String[] args) { + new DOOK().run(); + } + + +} diff --git a/src/main/java/DialogBox.java b/src/main/java/DialogBox.java new file mode 100644 index 0000000000..60636ac988 --- /dev/null +++ b/src/main/java/DialogBox.java @@ -0,0 +1,59 @@ +import java.io.IOException; +import java.util.Collections; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.control.Label; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; + +/** + * An example of a custom control using FXML. + * This control represents a dialog box consisting of an ImageView to represent the speaker's face and a label + * containing text from the speaker. + */ +public class DialogBox extends HBox { + @FXML + private Label dialog; + @FXML + private ImageView displayPicture; + + private DialogBox(String text, Image img) { + try { + FXMLLoader fxmlLoader = new FXMLLoader(MainWindow.class.getResource("/view/DialogBox.fxml")); + fxmlLoader.setController(this); + fxmlLoader.setRoot(this); + fxmlLoader.load(); + } catch (IOException e) { + e.printStackTrace(); + } + + dialog.setText(text); + displayPicture.setImage(img); + } + + /** + * Flips the dialog box such that the ImageView is on the left and text on the right. + */ + private void flip() { + ObservableList tmp = FXCollections.observableArrayList(this.getChildren()); + Collections.reverse(tmp); + getChildren().setAll(tmp); + setAlignment(Pos.TOP_LEFT); + } + + public static DialogBox getUserDialog(String text, Image img) { + return new DialogBox(text, img); + } + + public static DialogBox getDukeDialog(String text, Image img) { + var db = new DialogBox(text, img); + db.flip(); + return db; + } +} \ No newline at end of file diff --git a/src/main/java/Duke.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/DukeHelpfulCode/.idea/.gitignore b/src/main/java/DukeHelpfulCode/.idea/.gitignore new file mode 100644 index 0000000000..26d33521af --- /dev/null +++ b/src/main/java/DukeHelpfulCode/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/src/main/java/DukeHelpfulCode/.idea/misc.xml b/src/main/java/DukeHelpfulCode/.idea/misc.xml new file mode 100644 index 0000000000..0319d5d58f --- /dev/null +++ b/src/main/java/DukeHelpfulCode/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/main/java/DukeHelpfulCode/.idea/modules.xml b/src/main/java/DukeHelpfulCode/.idea/modules.xml new file mode 100644 index 0000000000..38d2fab88b --- /dev/null +++ b/src/main/java/DukeHelpfulCode/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/main/java/DukeHelpfulCode/.idea/vcs.xml b/src/main/java/DukeHelpfulCode/.idea/vcs.xml new file mode 100644 index 0000000000..4fce1d86b4 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/main/java/DukeHelpfulCode/.idea/workspace.xml b/src/main/java/DukeHelpfulCode/.idea/workspace.xml new file mode 100644 index 0000000000..8d70db568f --- /dev/null +++ b/src/main/java/DukeHelpfulCode/.idea/workspace.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 1675667404340 + + + + \ No newline at end of file diff --git a/src/main/java/DukeHelpfulCode/Commands/.idea/.gitignore b/src/main/java/DukeHelpfulCode/Commands/.idea/.gitignore new file mode 100644 index 0000000000..26d33521af --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Commands/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/src/main/java/DukeHelpfulCode/Commands/.idea/misc.xml b/src/main/java/DukeHelpfulCode/Commands/.idea/misc.xml new file mode 100644 index 0000000000..0319d5d58f --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Commands/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/main/java/DukeHelpfulCode/Commands/.idea/modules.xml b/src/main/java/DukeHelpfulCode/Commands/.idea/modules.xml new file mode 100644 index 0000000000..7615205404 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Commands/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/main/java/DukeHelpfulCode/Commands/.idea/vcs.xml b/src/main/java/DukeHelpfulCode/Commands/.idea/vcs.xml new file mode 100644 index 0000000000..bc59970703 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Commands/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/main/java/DukeHelpfulCode/Commands/.idea/workspace.xml b/src/main/java/DukeHelpfulCode/Commands/.idea/workspace.xml new file mode 100644 index 0000000000..b3befc9f65 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Commands/.idea/workspace.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1675758777249 + + + + \ No newline at end of file diff --git a/src/main/java/DukeHelpfulCode/Commands/AddCommand.java b/src/main/java/DukeHelpfulCode/Commands/AddCommand.java new file mode 100644 index 0000000000..66946dc8e8 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Commands/AddCommand.java @@ -0,0 +1,31 @@ +package DukeHelpfulCode.Commands; + +import DukeHelpfulCode.Tasks.*; +import DukeHelpfulCode.Utilities.*; + +import java.io.IOException; + +public class AddCommand extends Command{ + + Task task; + + public AddCommand(Task task){ + this.task = task; + } + public AddCommand(){}; + + @Override + public String execute(TaskList taskList) { + return taskList.add(task); + }; + + @Override + public boolean isExit(){ + return false; + } + + public String toString(){ + return "add -> Adds a Task to your list.\n Format: add \n"; + } + +} diff --git a/src/main/java/DukeHelpfulCode/Commands/AddCommandParser.java b/src/main/java/DukeHelpfulCode/Commands/AddCommandParser.java new file mode 100644 index 0000000000..8d4aa3979e --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Commands/AddCommandParser.java @@ -0,0 +1,146 @@ +package DukeHelpfulCode.Commands; + +import DukeHelpfulCode.Exceptions.*; + +import DukeHelpfulCode.Tasks.Deadline; +import DukeHelpfulCode.Tasks.Event; +import DukeHelpfulCode.Tasks.Task; +import DukeHelpfulCode.Tasks.Todo; + +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.time.LocalDateTime; + +import java.util.Arrays; +import java.util.Locale; + +public class AddCommandParser { + + private static String[] possibleFormats = { + "dd/MM/yy HHmm", "dd/MM/yyyy HHmm", + "dd/MM/yy hh:mm a", "dd/MM/yyyy hh:mm a", + }; + + /* + * "yyyy-MM-dd HHmm", "yyyy/MM/dd HHmm", + "dd-MM-yyyy HHmm", "dd/MM/yyyy HHmm", + "yyyy-MM-dd hh:mm a", "yyyy/MM/dd hh:mm a", + "dd-MM-yyyy hh:mm a", "dd/MM/yyyy hh:mm a", + "HHmm yyyy-MM-dd", "HHmm yyyy/MM/dd", + "HHmm dd-MM-yyyy", "HHmm dd/MM/yyyy", + "hh:mm a yyyy-MM-dd", "hh:mm a yyyy/MM/dd", + "hh:mm a dd-MM-yyyy", "hh:mm a dd/MM/yyyy", + "dd-MM-yy HHmm", "dd/MM/yy HHmm", + "yy-MM-dd HHmm", "yy/MM/dd HHmm", + "dd-MM-yy hh:mm a", "dd/MM/yy hh:mm a", + "yy-MM-dd hh:mm a", "yy/MM/dd hh:mm a", + "HHmm dd-MM-yy", "HHmm dd/MM/yy", + "HHmm yy-MM-dd", "HHmm yy/MM/dd", + "hh:mm a dd-MM-yy", "hh:mm a dd/MM/yy", + "hh:mm a yy-MM-dd", "hh:mm a yy/MM/dd", + "dd MMM yyyy hh:mm a" + * */ + + public static Command parse(String[] userInput) { + Task task; + String taskType; + String taskName = ""; + + try { + taskType = userInput[1]; + } catch (ArrayIndexOutOfBoundsException e) { + return new ErrorCommand("Sorry, what kind of task is this?\n"); + } + +// try { +// String test = userInput[1]; +// } catch (ArrayIndexOutOfBoundsException e) { +// throw new NoTaskNameException(); +// } + + if (taskType.toLowerCase(Locale.ROOT).equals("todo")) { + for (int i = 2; i < userInput.length; i++) { + taskName += userInput[i] + " "; + } + if (taskName.equals("")) { + return new ErrorCommand("Sorry, no name for this task is given.\n"); + } + task = new Todo(taskName); + + } else if (taskType.toLowerCase(Locale.ROOT).equals("event")) { + + String start = ""; + String end = ""; + int i = 2; + + if (!Arrays.asList(userInput).contains("/from") || !Arrays.asList(userInput).contains("/to")) { + return new ErrorCommand("Sorry, I don't understand when this Event starts or ends."); + } + + while (!userInput[i].equals("/from")) { + taskName += userInput[i] + " "; + i++; + } + if (taskName.equals("")) { + return new ErrorCommand("Sorry, no name for this task is given.\n"); + } + i++; + while (!userInput[i].equals("/to")) { + start += userInput[i] + " "; + i++; + } + i++; + for (int j = i; j < userInput.length; j++) { + end += userInput[j] + " "; + } + try { + task = new Event(taskName, formatDateTime(start.substring(0, start.length() - 1)), formatDateTime(end.substring(0, end.length() - 1))); + } catch (DateTimeParseException e) { + return new ErrorCommand("Sorry, I don't understand the date you've entered.\n"); + } + + } else if (taskType.toLowerCase(Locale.ROOT).equals("deadline")) { + String by = ""; + int i = 2; + if (!Arrays.asList(userInput).contains("/by")) { + return new ErrorCommand("Sorry, I don't understand when this Deadline is due."); + } + while (!userInput[i].equals("/by")) { + taskName += userInput[i] + " "; + i++; + } + if (taskName.equals("")) { + return new ErrorCommand("Sorry, no name for this task is given.\n"); + } + i++; + for (int j = i; j < userInput.length; j++) { + by += userInput[j] + " "; + } + LocalDateTime byDate = formatDateTime(by.substring(0, by.length() - 1)); + if (byDate == null){ + return new ErrorCommand("Sorry, I don't understand the date you entered."); + } else { + task = new Deadline(taskName, byDate); + } + + } else { + return new ErrorCommand("Sorry, what kind of task is this?\n"); + } + + return new AddCommand(task); +} + private static LocalDateTime formatDateTime(String dueDate) throws DateTimeParseException{ + LocalDateTime dt = null; + for (String format : possibleFormats) { + try { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format); + dt = LocalDateTime.parse(dueDate.toUpperCase(Locale.ROOT), formatter); + break; + } catch (DateTimeParseException e) { + continue; + } + } + return dt; + } + +} diff --git a/src/main/java/DukeHelpfulCode/Commands/Command.java b/src/main/java/DukeHelpfulCode/Commands/Command.java new file mode 100644 index 0000000000..0af5753d0a --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Commands/Command.java @@ -0,0 +1,19 @@ +package DukeHelpfulCode.Commands; + +import DukeHelpfulCode.Exceptions.NoSuchTaskException; +import DukeHelpfulCode.Exceptions.TaskAlrMarkException; +import DukeHelpfulCode.Exceptions.TaskAlrUnmarkException; +import DukeHelpfulCode.Utilities.*; + +import java.io.IOException; + +public abstract class Command { + /** All commands will inherit from this abstract class + * commands that inherit: AddCommand, DeleteCommand, ExitCommand etc + * @return + */ + + public abstract String execute(TaskList taskList) throws TaskAlrMarkException, NoSuchTaskException, TaskAlrUnmarkException; + + public abstract boolean isExit(); +} diff --git a/src/main/java/DukeHelpfulCode/Commands/DatetimeFormatter.java b/src/main/java/DukeHelpfulCode/Commands/DatetimeFormatter.java new file mode 100644 index 0000000000..f229930476 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Commands/DatetimeFormatter.java @@ -0,0 +1,16 @@ +package DukeHelpfulCode.Commands; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + +public class DatetimeFormatter { + public static LocalDateTime formatDateTime(String datetime, String format){ + LocalDateTime dt = null; + try { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format); + dt = LocalDateTime.parse(datetime, formatter); + } catch (DateTimeParseException e) {} + return dt; + } +} diff --git a/src/main/java/DukeHelpfulCode/Commands/DeleteCommand.java b/src/main/java/DukeHelpfulCode/Commands/DeleteCommand.java new file mode 100644 index 0000000000..e36b3c42f6 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Commands/DeleteCommand.java @@ -0,0 +1,39 @@ +package DukeHelpfulCode.Commands; + +import DukeHelpfulCode.Exceptions.NoSuchTaskException; +import DukeHelpfulCode.Utilities.Storage; +import DukeHelpfulCode.Utilities.TaskList; +import DukeHelpfulCode.Utilities.UI; + +import java.io.IOException; + +public class DeleteCommand extends Command{ + + int taskNum; + + public DeleteCommand(int taskNum){ + this.taskNum = taskNum; + } + public DeleteCommand(){}; + + @Override + public String execute(TaskList taskList) { + String res; + try { + res = taskList.delete(taskNum); + } catch (NoSuchTaskException e) { + res = e.getMessage(); + } + return res; + } + + @Override + public boolean isExit(){ + return false; + } + + @Override + public String toString() { + return "delete -> Removes the specified Task from your list.\n Format: delete \n"; + } +} diff --git a/src/main/java/DukeHelpfulCode/Commands/DeleteCommandParser.java b/src/main/java/DukeHelpfulCode/Commands/DeleteCommandParser.java new file mode 100644 index 0000000000..d1bdf95bbb --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Commands/DeleteCommandParser.java @@ -0,0 +1,17 @@ +package DukeHelpfulCode.Commands; + +public class DeleteCommandParser { + + public static Command parse(String[] userInput) { + int index; + + try { + index = Integer.parseInt(userInput[1]); + } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) { + return new ErrorCommand("Sorry, I don't understand."); + } + index = Integer.parseInt(userInput[1]); + + return new DeleteCommand(index); + } +} diff --git a/src/main/java/DukeHelpfulCode/Commands/ErrorCommand.java b/src/main/java/DukeHelpfulCode/Commands/ErrorCommand.java new file mode 100644 index 0000000000..1165ace9de --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Commands/ErrorCommand.java @@ -0,0 +1,24 @@ +package DukeHelpfulCode.Commands; + +import DukeHelpfulCode.Exceptions.NoSuchTaskException; +import DukeHelpfulCode.Exceptions.TaskAlrMarkException; +import DukeHelpfulCode.Utilities.TaskList; + +public class ErrorCommand extends Command{ + + String errorMessage; + + public ErrorCommand(String errorMessage){ + this.errorMessage = errorMessage; + } + + @Override + public String execute(TaskList taskList) throws TaskAlrMarkException, NoSuchTaskException { + return errorMessage; + } + + @Override + public boolean isExit() { + return false; + } +} diff --git a/src/main/java/DukeHelpfulCode/Commands/ExitCommand.java b/src/main/java/DukeHelpfulCode/Commands/ExitCommand.java new file mode 100644 index 0000000000..5b4bc931eb --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Commands/ExitCommand.java @@ -0,0 +1,26 @@ +package DukeHelpfulCode.Commands; + +import DukeHelpfulCode.Utilities.Storage; +import DukeHelpfulCode.Utilities.TaskList; +import DukeHelpfulCode.Utilities.UI; + +public class ExitCommand extends Command { + + public ExitCommand(){} + + @Override + public String execute(TaskList taskList) { + return "Thanks for using DOOK. Hope you have a great day ahead!"; + } + + @Override + public boolean isExit(){ + return true; + } + + @Override + public String toString(){ + return "bye -> Exits DOOK.\n Format: bye\n"; + } + +} diff --git a/src/main/java/DukeHelpfulCode/Commands/FindCommand.java b/src/main/java/DukeHelpfulCode/Commands/FindCommand.java new file mode 100644 index 0000000000..3dc747c4c6 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Commands/FindCommand.java @@ -0,0 +1,26 @@ +package DukeHelpfulCode.Commands; + +import DukeHelpfulCode.Exceptions.NoSuchTaskException; +import DukeHelpfulCode.Exceptions.TaskAlrMarkException; +import DukeHelpfulCode.Utilities.TaskList; + +public class FindCommand extends Command{ + + String[] keywords; + + public FindCommand(String[] keywords){ + this.keywords = keywords; + } + + public FindCommand(){} + + @Override + public String execute(TaskList taskList) throws TaskAlrMarkException, NoSuchTaskException { + return taskList.find(keywords); + } + + @Override + public boolean isExit() { + return false; + } +} diff --git a/src/main/java/DukeHelpfulCode/Commands/FindCommandParser.java b/src/main/java/DukeHelpfulCode/Commands/FindCommandParser.java new file mode 100644 index 0000000000..775bc88895 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Commands/FindCommandParser.java @@ -0,0 +1,10 @@ +package DukeHelpfulCode.Commands; + +import java.util.Arrays; + +public class FindCommandParser { + + public static Command parse(String[] userInput) { + return new FindCommand(Arrays.copyOfRange(userInput,1,userInput.length)); + } +} diff --git a/src/main/java/DukeHelpfulCode/Commands/HelpCommand.java b/src/main/java/DukeHelpfulCode/Commands/HelpCommand.java new file mode 100644 index 0000000000..b6dba28c3a --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Commands/HelpCommand.java @@ -0,0 +1,35 @@ +package DukeHelpfulCode.Commands; + +import DukeHelpfulCode.Utilities.Storage; +import DukeHelpfulCode.Utilities.TaskList; +import DukeHelpfulCode.Utilities.UI; + +public class HelpCommand extends Command{ + /** if dk what the user uinpuit justt thro whtis LMAO + * + */ + + public HelpCommand(){} + + @Override + public String execute(TaskList taskList){ + return "Here is the list of Commands:\n" + + ">add : Adds the task to the list\n" + + ">mark / unmark : Marks the index-th item\n as done/not done\n" + + ">delete : Deletes the index-th item\n" + + ">list: Shows the current task list\n" + + ">find : shows the list of tasks with said\n keywords with their indexes\n" + + ">bye: saves the task list and exits DOOK\n" + + ">help: shows the list of commands\n"; + }; + + @Override + public boolean isExit(){ + return false; + } + + @Override + public String toString(){ + return "help -> Displays the list of commands.\n Format: help\n"; + } +} diff --git a/src/main/java/DukeHelpfulCode/Commands/ListCommand.java b/src/main/java/DukeHelpfulCode/Commands/ListCommand.java new file mode 100644 index 0000000000..3379400a66 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Commands/ListCommand.java @@ -0,0 +1,25 @@ +package DukeHelpfulCode.Commands; + +import DukeHelpfulCode.Utilities.Storage; +import DukeHelpfulCode.Utilities.TaskList; +import DukeHelpfulCode.Utilities.UI; + +public class ListCommand extends Command{ + + public ListCommand(){} + + @Override + public String execute(TaskList taskList) { + return taskList.toString(); + } + + @Override + public boolean isExit() { + return false; + } + + @Override + public String toString(){ + return "list -> Displays your list.\n Format: list\n"; + } +} diff --git a/src/main/java/DukeHelpfulCode/Commands/MarkCommand.java b/src/main/java/DukeHelpfulCode/Commands/MarkCommand.java new file mode 100644 index 0000000000..6fbf84dd0f --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Commands/MarkCommand.java @@ -0,0 +1,38 @@ +package DukeHelpfulCode.Commands; + +import DukeHelpfulCode.Exceptions.NoSuchTaskException; +import DukeHelpfulCode.Exceptions.TaskAlrMarkException; +import DukeHelpfulCode.Exceptions.TaskAlrUnmarkException; +import DukeHelpfulCode.Utilities.Storage; +import DukeHelpfulCode.Utilities.TaskList; +import DukeHelpfulCode.Utilities.UI; + +import java.io.IOException; + +public class MarkCommand extends Command{ + + boolean isMark; + int taskNum; + + public MarkCommand(boolean isMark, int taskNum){ + this.isMark = isMark; + this.taskNum = taskNum; + } + public MarkCommand(){}; + + @Override + public String execute(TaskList taskList) throws TaskAlrMarkException, TaskAlrUnmarkException, NoSuchTaskException { + String res = taskList.mark(isMark, taskNum); + return res; + }; + + @Override + public boolean isExit(){ + return false; + } + + @Override + public String toString(){ + return "mark / unmark -> Marks / Unmarks the specified Task\n Format: mark/unmark \n"; + } +} diff --git a/src/main/java/DukeHelpfulCode/Commands/MarkCommandParser.java b/src/main/java/DukeHelpfulCode/Commands/MarkCommandParser.java new file mode 100644 index 0000000000..b7bb0a50b0 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Commands/MarkCommandParser.java @@ -0,0 +1,27 @@ +package DukeHelpfulCode.Commands; + +import java.util.Locale; + +public class MarkCommandParser { + + public static Command parse(String[] userInput) { + boolean isMark = true; + int index; + + try { + if (userInput[0].toLowerCase(Locale.ROOT).equals("unmark")) { + isMark = false; + } + index = Integer.parseInt(userInput[1]); + } catch (NumberFormatException e) { + return new ErrorCommand("Sorry, I don't understand."); + } catch (IndexOutOfBoundsException e) { + return new ErrorCommand("Sorry, that index does not exist."); + } + if (index <= 0) { + return new ErrorCommand("Sorry, that index does not exist."); + } + + return new MarkCommand(isMark, index); + } +} diff --git a/src/main/java/DukeHelpfulCode/Commands/Parser.java b/src/main/java/DukeHelpfulCode/Commands/Parser.java new file mode 100644 index 0000000000..170c3050c6 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Commands/Parser.java @@ -0,0 +1,61 @@ +package DukeHelpfulCode.Commands; + +import java.util.Arrays; +import java.util.Locale; + +import DukeHelpfulCode.Exceptions.*; + +public class Parser { + /** + * parses the commands kekw + * + */ + + public static Command parse(String fullCommand) throws NoTaskTypeException, NoTaskNameException, NoDueTimeException, NoStartTimeException, NoEndTimeException, NoSuchTaskException { + /** + * Converts the user input into a Command. + * + * @param fullCommand The user input + * @return command The Command that the user wants + * @throws NoTaskTypeException Thrown if parser does not find the task type if adding + * @throws NoTaskNameException Thrown if parser does not find the task name if adding + * @throws NoDueTimeException Thrown if parser does not find the due dateTime if adding deadline + * @throws NoStartTimeException Thrown if parser does not find the start dateTime if adding event + * @throws NoEndTimeException Thrown if parser does not find the end dateTime if adding event + * @throws NoSuchTaskException Thrown if deleting/marking task that isnt there on the list + */ + Command cmd = new HelpCommand(); + String[] cmdArr = fullCommand.split(" "); + // System.out.println(Arrays.asList(cmdArr)); + + if (cmdArr[0].toLowerCase(Locale.ROOT).equals("bye")){ + cmd = new ExitCommand(); + + } else if (cmdArr[0].toLowerCase(Locale.ROOT).equals("help")){ + cmd = new HelpCommand(); + + } else if (cmdArr[0].toLowerCase(Locale.ROOT).equals("list")){ + cmd = new ListCommand(); + + } else if (cmdArr[0].toLowerCase(Locale.ROOT).equals("add")){ + new AddCommandParser(); + cmd = AddCommandParser.parse(cmdArr); + + } else if (cmdArr[0].toLowerCase(Locale.ROOT).equals("delete")){ + cmd = DeleteCommandParser.parse(cmdArr); + + } else if (cmdArr[0].toLowerCase(Locale.ROOT).equals("mark")){ + cmd = MarkCommandParser.parse(cmdArr); + + } else if (cmdArr[0].toLowerCase(Locale.ROOT).equals("unmark")){ + cmd = MarkCommandParser.parse(cmdArr); + + } else if (cmdArr[0].toLowerCase(Locale.ROOT).equals("find")) { + cmd = FindCommandParser.parse(cmdArr); + + } + return cmd; + } + + +} diff --git a/src/main/java/DukeHelpfulCode/Exceptions/DukeException.java b/src/main/java/DukeHelpfulCode/Exceptions/DukeException.java new file mode 100644 index 0000000000..ed9a44297d --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Exceptions/DukeException.java @@ -0,0 +1,7 @@ +package DukeHelpfulCode.Exceptions; + +public class DukeException extends Exception{ + public DukeException(String message){ + super(message); + } +} diff --git a/src/main/java/DukeHelpfulCode/Exceptions/EmptyTaskListException.java b/src/main/java/DukeHelpfulCode/Exceptions/EmptyTaskListException.java new file mode 100644 index 0000000000..9b758ec734 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Exceptions/EmptyTaskListException.java @@ -0,0 +1,7 @@ +package DukeHelpfulCode.Exceptions; + +public class EmptyTaskListException extends DukeException{ + public EmptyTaskListException(){ + super("It appears that your Task List is currently Empty!\n"); + } +} diff --git a/src/main/java/DukeHelpfulCode/Exceptions/NoDueTimeException.java b/src/main/java/DukeHelpfulCode/Exceptions/NoDueTimeException.java new file mode 100644 index 0000000000..af1c2b76e8 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Exceptions/NoDueTimeException.java @@ -0,0 +1,7 @@ +package DukeHelpfulCode.Exceptions; + +public class NoDueTimeException extends DukeException{ + public NoDueTimeException(){ + super("Sorry, when is this due?\n"); + } +} diff --git a/src/main/java/DukeHelpfulCode/Exceptions/NoEndTimeException.java b/src/main/java/DukeHelpfulCode/Exceptions/NoEndTimeException.java new file mode 100644 index 0000000000..5111ddfb82 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Exceptions/NoEndTimeException.java @@ -0,0 +1,7 @@ +package DukeHelpfulCode.Exceptions; + +public class NoEndTimeException extends DukeException{ + public NoEndTimeException(){ + super("Sorry, when is this Event ending?\n"); + } +} diff --git a/src/main/java/DukeHelpfulCode/Exceptions/NoStartTimeException.java b/src/main/java/DukeHelpfulCode/Exceptions/NoStartTimeException.java new file mode 100644 index 0000000000..6fccc19dc3 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Exceptions/NoStartTimeException.java @@ -0,0 +1,7 @@ +package DukeHelpfulCode.Exceptions; + +public class NoStartTimeException extends DukeException{ + public NoStartTimeException(){ + super("Sorry, when is this Event starting?\n"); + } +} diff --git a/src/main/java/DukeHelpfulCode/Exceptions/NoSuchTaskException.java b/src/main/java/DukeHelpfulCode/Exceptions/NoSuchTaskException.java new file mode 100644 index 0000000000..b81f17fe5f --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Exceptions/NoSuchTaskException.java @@ -0,0 +1,7 @@ +package DukeHelpfulCode.Exceptions; + +public class NoSuchTaskException extends DukeException{ + public NoSuchTaskException(){ + super("sorry, but I can't find this Task."); + } +} diff --git a/src/main/java/DukeHelpfulCode/Exceptions/NoTaskNameException.java b/src/main/java/DukeHelpfulCode/Exceptions/NoTaskNameException.java new file mode 100644 index 0000000000..7407ecc0f6 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Exceptions/NoTaskNameException.java @@ -0,0 +1,7 @@ +package DukeHelpfulCode.Exceptions; + +public class NoTaskNameException extends DukeException{ + public NoTaskNameException(){ + super("Sorry, what's the name of this Task?\n"); + } +} diff --git a/src/main/java/DukeHelpfulCode/Exceptions/NoTaskTypeException.java b/src/main/java/DukeHelpfulCode/Exceptions/NoTaskTypeException.java new file mode 100644 index 0000000000..767ddce432 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Exceptions/NoTaskTypeException.java @@ -0,0 +1,7 @@ +package DukeHelpfulCode.Exceptions; + +public class NoTaskTypeException extends DukeException{ + public NoTaskTypeException(){ + super("Sorry, what Task is this?\n(todo, deadline, event)\n"); + } +} diff --git a/src/main/java/DukeHelpfulCode/Exceptions/TaskAlrMarkException.java b/src/main/java/DukeHelpfulCode/Exceptions/TaskAlrMarkException.java new file mode 100644 index 0000000000..abf2bcd454 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Exceptions/TaskAlrMarkException.java @@ -0,0 +1,7 @@ +package DukeHelpfulCode.Exceptions; + +public class TaskAlrMarkException extends DukeException{ + public TaskAlrMarkException(){ + super("It appears that this Task has already been marked as Done. Would you like to mark it as Not Done instead?\n"); + } +} diff --git a/src/main/java/DukeHelpfulCode/Exceptions/TaskAlrUnmarkException.java b/src/main/java/DukeHelpfulCode/Exceptions/TaskAlrUnmarkException.java new file mode 100644 index 0000000000..8e5b4d9f63 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Exceptions/TaskAlrUnmarkException.java @@ -0,0 +1,7 @@ +package DukeHelpfulCode.Exceptions; + +public class TaskAlrUnmarkException extends DukeException{ + public TaskAlrUnmarkException() { + super(""); + } +} diff --git a/src/main/java/DukeHelpfulCode/Tasks/Deadline.java b/src/main/java/DukeHelpfulCode/Tasks/Deadline.java new file mode 100644 index 0000000000..e0dbc0d986 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Tasks/Deadline.java @@ -0,0 +1,70 @@ +package DukeHelpfulCode.Tasks; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.Scanner; + +public class Deadline extends Task{ + // tasks that need to be done before a specific date/time + private LocalDateTime dateTime = null; + private String[] possibleFormats = { + "yyyy-MM-dd HHmm", "yyyy/MM/dd HHmm", + "dd-MM-yyyy HHmm", "dd/MM/yyyy HHmm", + "yyyy-MM-dd hh:mm a", "yyyy/MM/dd hh:mm a", + "dd-MM-yyyy hh:mm a", "dd/MM/yyyy hh:mm a", + "HHmm yyyy-MM-dd", "HHmm yyyy/MM/dd", + "HHmm dd-MM-yyyy", "HHmm dd/MM/yyyy", + "hh:mm a yyyy-MM-dd", "hh:mm a yyyy/MM/dd", + "hh:mm a dd-MM-yyyy", "hh:mm a dd/MM/yyyy", + "yy-MM-dd HHmm", "yy/MM/dd HHmm", + "dd-MM-yy HHmm", "dd/MM/yy HHmm", + "yy-MM-dd hh:mm a", "yy/MM/dd hh:mm a", + "dd-MM-yy hh:mm a", "dd/MM/yy hh:mm a", + "HHmm yy-MM-dd", "HHmm yy/MM/dd", + "HHmm dd-MM-yy", "HHmm dd/MM/yy", + "hh:mm a yy-MM-dd", "hh:mm a yy/MM/dd", + "hh:mm a dd-MM-yy", "hh:mm a dd/MM/yy", + "dd MMM yyyy hh:mm a"}; + + public Deadline(String name, LocalDateTime dueDate) { + super(name,"deadline"); + this.dateTime = dueDate; + } + + public Deadline(String name, LocalDateTime dueDate, boolean isDone) { + super(name, "deadline", isDone); + this.dateTime = dueDate; + } + + private LocalDateTime formatDateTime(String dueDate) { + LocalDateTime dt = null; + for (String format : possibleFormats) { + try { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format); + dt = LocalDateTime.parse(dueDate, formatter); + break; + } catch (DateTimeParseException e) { + // Do nothing, just continue to the next format + } + } + return dt; + } + + public String toString(){ + DateTimeFormatter dtFormatter = DateTimeFormatter.ofPattern("dd MMM yyyy hh:mm a"); + return "[D] " + super.toString() + " (by: " + this.dateTime.format(dtFormatter) + ")"; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Deadline) { + Deadline objTask = (Deadline) obj; + return objTask.getName().equals(this.getName()) + && objTask.dateTime.equals(this.dateTime); + } else { + return false; + } + } + +} diff --git a/src/main/java/DukeHelpfulCode/Tasks/Event.java b/src/main/java/DukeHelpfulCode/Tasks/Event.java new file mode 100644 index 0000000000..5475f65e59 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Tasks/Event.java @@ -0,0 +1,44 @@ +package DukeHelpfulCode.Tasks; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + +public class Event extends Task{ + // tasks that start at a specific date/time and ends at a specific date/time + + LocalDateTime startDateTime; + LocalDateTime endDateTime; + + public Event(String name, LocalDateTime startDateTime, LocalDateTime endDateTime) { + super(name,"event"); + this.startDateTime = startDateTime; + this.endDateTime = endDateTime; + } + public Event(String name, LocalDateTime startDateTime, LocalDateTime endDateTime, boolean isDone){ + super(name, "event",isDone); + this.startDateTime = startDateTime; + this.endDateTime = endDateTime; + } + + public String toString() { + DateTimeFormatter dtFormatter = DateTimeFormatter.ofPattern("dd MMM yyyy hh:mm a"); + return "[E] " + + super.toString() + + " (from: " + this.startDateTime.format(dtFormatter) + + " to: " + this.endDateTime.format(dtFormatter) + ")"; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Event) { + Event objTask = (Event) obj; + return objTask.getName().equals(this.getName()) + && objTask.startDateTime.equals(this.startDateTime) + && objTask.endDateTime.equals(this.endDateTime); + } else { + return false; + } + } + +} diff --git a/src/main/java/DukeHelpfulCode/Tasks/Task.java b/src/main/java/DukeHelpfulCode/Tasks/Task.java new file mode 100644 index 0000000000..82727c63bf --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Tasks/Task.java @@ -0,0 +1,74 @@ +package DukeHelpfulCode.Tasks; + +public class Task { + /** + * Task class for things added to the TaskList + * Methods: + * markAsDone -> mark Task as done if not done and vice versa. + */ + + private static String LINEBREAK = "=================================\n"; + private String name; + private Boolean isDone; + private String type; + + public Task (String name, String type) { + this.name = name; + this.isDone = false; + this.type = type; + } + + public Task (String name, String type, boolean isDone){ + this.name = name; + this.type = type; + this.isDone = isDone; + } + + public String getName() { + return this.name; + } + + public String getType() { + return this.type; + } + + public boolean isDone(){ + return isDone; + } + + public String toString() { + /** + * Returns "[done] Task" + */ + char doneX = ' '; + if (isDone) { + doneX = 'X'; + } + return "[" + doneX + "]" + " " + name; + } + + public boolean equals(Object obj){ + if (obj instanceof Task) { + Task objTask = (Task) obj; + return objTask.name.equals(this.name); + } else { + return false; + } + } + + public String mark() { + /** + * Marks Task as done if not done and vice versa. + */ + if (isDone) { + isDone = false; + return LINEBREAK + "OK, '" + this.name + "' has been marked as Not Done.\n"; + + } else { + isDone = true; + return LINEBREAK + "OK, '" + this.name + "' has been marked as Done.\n"; + + } + } + +} \ No newline at end of file diff --git a/src/main/java/DukeHelpfulCode/Tasks/Todo.java b/src/main/java/DukeHelpfulCode/Tasks/Todo.java new file mode 100644 index 0000000000..24ff6602f9 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Tasks/Todo.java @@ -0,0 +1,25 @@ +package DukeHelpfulCode.Tasks; + +public class Todo extends Task{ + // tasks without any date/time atached to it + public Todo(String name) { + super(name, "todo"); + } + public Todo(String name, boolean isDone) { + super(name, "todo", isDone); + } + + public String toString(){ + return "[T] " + super.toString(); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Todo) { + Todo objTask = (Todo) obj; + return objTask.getName().equals(this.getName()); + } else { + return false; + } + } +} diff --git a/src/main/java/DukeHelpfulCode/Utilities/Storage.java b/src/main/java/DukeHelpfulCode/Utilities/Storage.java new file mode 100644 index 0000000000..06e30ca748 --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Utilities/Storage.java @@ -0,0 +1,158 @@ +package DukeHelpfulCode.Utilities; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + +import java.io.File; +import java.io.FileWriter; +import java.io.BufferedWriter; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; + +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.time.LocalDateTime; + +import java.util.ArrayList; +import java.util.List; + +import DukeHelpfulCode.Tasks.*; +import DukeHelpfulCode.Exceptions.*; + +public class Storage { + + private static String[] possibleFormats = { + "yyyy-MM-dd HHmm", "yyyy/MM/dd HHmm", + "dd-MM-yyyy HHmm", "dd/MM/yyyy HHmm", + "yyyy-MM-dd hh:mm a", "yyyy/MM/dd hh:mm a", + "dd-MM-yyyy hh:mm a", "dd/MM/yyyy hh:mm a", + "HHmm yyyy-MM-dd", "HHmm yyyy/MM/dd", + "HHmm dd-MM-yyyy", "HHmm dd/MM/yyyy", + "hh:mm a yyyy-MM-dd", "hh:mm a yyyy/MM/dd", + "hh:mm a dd-MM-yyyy", "hh:mm a dd/MM/yyyy", + "yy-MM-dd HHmm", "yy/MM/dd HHmm", + "dd-MM-yy HHmm", "dd/MM/yy HHmm", + "yy-MM-dd hh:mm a", "yy/MM/dd hh:mm a", + "dd-MM-yy hh:mm a", "dd/MM/yy hh:mm a", + "HHmm yy-MM-dd", "HHmm yy/MM/dd", + "HHmm dd-MM-yy", "HHmm dd/MM/yy", + "hh:mm a yy-MM-dd", "hh:mm a yy/MM/dd", + "hh:mm a dd-MM-yy", "hh:mm a dd/MM/yy", + "dd MMM yyyy hh:mm a"}; + + public String filePath; + + public Storage(String filePath){ + this.filePath = filePath; + } + + // should have a read, write and search function in this class + + private Task taskFromText(String[] s){ + /** + * Reads the task from the Text. + * + * @param s The text to read the task from + * @return task Task that the user indicated + */ + String type = s[0]; // [T] = todo | [D] = deadline | [E] = event + boolean isDone = s[1].equals("[X]"); // note that if not done, s[1] will be "[" + String name = ""; + Task t = null; + int i = isDone ? 2 : 3; + if (type.equals("[T]")){ + for (; i < s.length; i++){ + name += s[i] + " "; + } + t = new Todo(name, isDone); + } else if (type.equals("[D]")){ + while (!s[i].equals("(by:")){ + name += s[i] + " "; + i++; + } + i++; // to skip the "(by:" + String dd = s[i] + " " + s[i+1] + " " + s[i+2] + " " + s[i+3] + " " + s[i+4]; + // dd MMM yy hh:mm a) + t = new Deadline(name, formatDateTime(dd.substring(0,dd.length()-1)), isDone); + } else if (type.equals("[E]")){ + while (!s[i].equals("(from:")){ + name += s[i] + " "; + i++; + } + i++; // to skip the "(from:" + String sd = s[i] + " " + s[i+1] + " " + s[i+2] + " " + s[i+3] + " " + s[i+4]; + // dd MMM yy hh:mm a) + i+=6; // to skip "to:" + String ed = s[i] + " " + s[i+1] + " " + s[i+2] + " " + s[i+3] + " " + s[i+4]; + // dd MMM yy hh:mm a) + t = new Event(name, formatDateTime(sd), formatDateTime(ed.substring(0,ed.length()-1)),isDone); + } + + return t; + + } + + private LocalDateTime formatDateTime(String s) { + /** + * Formats the datetime from string + * + * @param s The text version of the datetime + * @return dateTime the formatted dateTime + */ + LocalDateTime dt = null; + try { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MMM yyyy hh:mm a"); + dt = LocalDateTime.parse(s, formatter); + } catch (DateTimeParseException e) { + // Do nothing, just continue to the next format + } + return dt; + } + + public List load() throws EmptyTaskListException, IOException { + /** + * Loads the currently existing tasks and stuff? + * this function goes into the new Tasklist() + * if empty throws EmptyTaskListException + * if not empty return the tasklist current existing + * + * @param none + * @return taskList The currently existing stuff from the save file. + */ + File taskListText = new File("tasks.txt"); + List taskList = new ArrayList<>(); + if (!taskListText.exists()) { + taskListText.createNewFile(); + } else { + BufferedReader reader = new BufferedReader(new FileReader(this.filePath)); + String line; + while ((line = reader.readLine()) != null) { + taskList.add(taskFromText(line.split(" "))); + } + if (taskList.size() == 0) { + throw new EmptyTaskListException(); + } + } + + return taskList; + + } + + public void write(TaskList tl) throws IOException { + /** + * Writes to the save file + * + * @param tl Tasklist + * @return none + */ + BufferedWriter writer = new BufferedWriter(new FileWriter(this.filePath)); + for (int i = 0; i < tl.len(); i++){ + System.out.println(tl.getTaskList().get(i).toString()); + writer.write(tl.getTaskList().get(i).toString()+"\n"); + writer.flush(); + } + } + +} diff --git a/src/main/java/DukeHelpfulCode/Utilities/TaskList.java b/src/main/java/DukeHelpfulCode/Utilities/TaskList.java new file mode 100644 index 0000000000..345bccec5a --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Utilities/TaskList.java @@ -0,0 +1,142 @@ +package DukeHelpfulCode.Utilities; + +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +import DukeHelpfulCode.Exceptions.*; +import DukeHelpfulCode.Tasks.*; + +public class TaskList { + /** + * List used by userCmds 'add' and 'list'. + * Methods: + * addToList() -> appends Task to the list + * markAsDone(int i) -> mark Task in i-th index as done. + */ + private static String LINEBREAK = "=================================\n"; + + private static List tasks = new ArrayList<>(); + + public static List getTaskList() { + /** + * Returns the current state of the list. + * + * @param none + * @return taskList The current taskList + */ + return tasks; + } + + public TaskList(List taskList){ + /** + * taskList can be empty, but thats fine + */ + this.tasks = taskList; + } + + public TaskList(){} + + public String toString() { + /** + * Returns the string representation of the current TaskList. + * + * @param none + * @return result String representation of the tasklist + * Tasks are listed vertically with 1-index + */ + String result = ""; + for (int i = 0; i < this.tasks.size(); i++){ + result += (i+1) +". " + this.tasks.get(i).toString() + "\n"; + } + return result; + } + + public String add(Task task){ + /** + * Adds Task to the TaskList. + * + * @param task The task to be added to the list + * @return none + */ + /*if (taskList.contains(task)){ + return "Oops, it seems that you have already added this Task to your list!\n"; + } + */ + if (tasks.contains(task)){ + return LINEBREAK + "Uhh, you already has dis tasks in da list boss.\n" + LINEBREAK; + } else { + tasks.add(task); + return LINEBREAK + "Got it. I've added this task: \n" + task.toString() + "\nNow you have " + this.len() + " tasks in your list.\n" + LINEBREAK; + } + } + + public String mark(boolean isMark, int i) throws NoSuchTaskException, TaskAlrMarkException, TaskAlrUnmarkException { + /** + * Marks the i-1 th index Task as done if not done and vice versa. + * Note: list is 0-index but displayed as 1-index, hence i would be 1-index. + * If i > userList.size(), throw TaskNotInListException. + * If Task done but "mark" and vice versa, throw TaskAlrMarkException. + * + * @param isMark User's command to "mark" or "unmark" a Task as done or not done. + * @param i The index of the Task to be marked. Note that user input i is 1-index, so -1 is needed. + */ + if (i > this.tasks.size()) { + throw new NoSuchTaskException(); + } else if (isMark && this.tasks.get(i-1).isDone()) { + throw new TaskAlrMarkException(); + } else if (!isMark && !this.tasks.get(i-1).isDone()){ + throw new TaskAlrUnmarkException(); + } else { + return this.tasks.get(i - 1).mark(); + } + } + + public String delete(int taskNum) throws NoSuchTaskException { + /** + * Deletes the task selected by the user with the indexing + * + * @param taskNum taskNum is the 1-indexed indexing of the task chosen by the user to be deleted. + * It is 1-indexed because the dsiplay list is 1-indexed. + * @return none + */ + // deletes taskNum-1 indexed task from the list + if (taskNum > this.len() || taskNum <= 0){ + throw new NoSuchTaskException(); + } + else { + this.tasks.remove(taskNum - 1); + return "The " + taskNum +"th Task on the list has been removed!\n" + LINEBREAK; + } + } + + public String find(String[] keywords){ + String findResult = ""; + for (int i = 0; i < tasks.size(); i++) { + for (String keyword : keywords){ + if (tasks.get(i).getName().contains(keyword) || tasks.get(i).getType().contains(keyword) + || ((keyword.equals("mark") || keyword.equals("marked") || keyword.equals("done")) && tasks.get(i).isDone()) + || ((keyword.equals("not marked") || keyword.equals("unmarked") || keyword.equals("not done")) && !tasks.get(i).isDone())) { + findResult += (i+1) + ". " + tasks.get(i).toString() + "\n"; + break; + } + } + } + if (findResult.equals("")) { + return "No tasks match your search..."; + } else { + return "Here are the tasks that contains the keywords:\n" + findResult; + } + } + + public int len() { + /** + * Returns the number of Tasks in the TaskList currently. + * + * @param none + * @return none + */ + return tasks.size(); + } + +} \ No newline at end of file diff --git a/src/main/java/DukeHelpfulCode/Utilities/UI.java b/src/main/java/DukeHelpfulCode/Utilities/UI.java new file mode 100644 index 0000000000..246d839a8e --- /dev/null +++ b/src/main/java/DukeHelpfulCode/Utilities/UI.java @@ -0,0 +1,99 @@ +package DukeHelpfulCode.Utilities; + +import java.nio.charset.StandardCharsets; +import java.util.Scanner; + +import DukeHelpfulCode.Commands.*; + +public class UI { + /** Handles the user inputs and stuff + * methods + * showWelcome() + * showLine() = linebreak + * showError(Exception ) + */ + + private static String LINEBREAK = "=================================\n"; + private static String convertFromUtf8ToIso(String s1) { + if(s1 == null) { + return null; + } + String s = new String(s1.getBytes(StandardCharsets.UTF_8)); + byte[] b = s.getBytes(StandardCharsets.ISO_8859_1); + return new String(b, StandardCharsets.ISO_8859_1); + } + + public String intro = "Hello from DOOK, your own tasks manager\n(for irl tasks, not computer ones)\n" + + LINEBREAK; + + public String showCommands(){ + /** + * Prints the list of commands. + * + * @param none + * @return none + */ + /** + * Prints the list of Commands + */ + Command[] allCmd = {new HelpCommand(), + new AddCommand(), + new DeleteCommand(), + new MarkCommand(), + new ListCommand(), + new ExitCommand()}; + String commandList = LINEBREAK + "Here's the list of commands:\n" + LINEBREAK; // just add the tostring of the commands + for (int i = 0; i < allCmd.length; i++){ + commandList += i+1 + ". " + allCmd[i].toString(); + } + return commandList; + } + + public String showLine(){ + /** + * Prints Linebreak. + * + * @param none + * @return none + */ + return LINEBREAK; + } + + public String exit(){ + /** + * Exits DOOK. + * + * @param none + * @return none + */ + return LINEBREAK + "Thanks for using DOOK. Hope you have a great day ahead!"; + } + + public String showLoadingError(){ + return "Oops, there seems to be a problem with loading your previous Task List?\n"; + } + + public String showError(String message){ + /** + * Prints the error message + * + * @param message The error message to be displayed. + * @return none + */ + return message; + } + + public void showList(){} + + public String readCommand() { + /** + * Reads the user Command. + * + * @params none + * @return command The command that the user inputs. + */ + Scanner sc = new Scanner(System.in); + System.out.println("How may I help you today?\n"); + return sc.nextLine(); + } +} diff --git a/src/main/java/Launcher.java b/src/main/java/Launcher.java new file mode 100644 index 0000000000..11dbf00c62 --- /dev/null +++ b/src/main/java/Launcher.java @@ -0,0 +1,10 @@ +import javafx.application.Application; + +/** + * A launcher class to workaround classpath issues. + */ +public class Launcher { + public static void main(String[] args) { + Application.launch(Main.class, args); + } +} \ No newline at end of file diff --git a/src/main/java/Main.java b/src/main/java/Main.java new file mode 100644 index 0000000000..721ec4e1af --- /dev/null +++ b/src/main/java/Main.java @@ -0,0 +1,29 @@ +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 Duke using FXML. + */ +public class Main extends Application { + + private DOOK dook = new DOOK(); + + @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().setDOOK(dook); + stage.show(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/main/java/MainWindow.java b/src/main/java/MainWindow.java new file mode 100644 index 0000000000..fa7795f245 --- /dev/null +++ b/src/main/java/MainWindow.java @@ -0,0 +1,64 @@ +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 DukeHelpfulCode.Utilities.UI; + +/** + * Controller for MainWindow. Provides the layout for the other controls. + */ +public class MainWindow extends AnchorPane { + @FXML + private ScrollPane scrollPane; + @FXML + private VBox dialogContainer; + @FXML + private TextField userInput; + @FXML + private Button sendButton; + + private DOOK dook; + + private Image userImage = new Image(this.getClass().getResourceAsStream("/images/soyjak.png")); + private Image dukeImage = new Image(this.getClass().getResourceAsStream("/images/DOOK.png")); + + @FXML + public void initialize() { + scrollPane.vvalueProperty().bind(dialogContainer.heightProperty()); + } + + public void setDOOK(DOOK d) { + dook = d; + addDialog(new UI().intro); + } + + /** + * Creates two dialog boxes, one echoing user input and the other containing Duke's reply and then appends them to + * the dialog container. Clears the user input after processing. + */ + @FXML + private void handleUserInput() { + String input = userInput.getText(); + String response = dook.getResponse(input); + dialogContainer.getChildren().addAll( + DialogBox.getUserDialog(input, userImage), + DialogBox.getDukeDialog(response, dukeImage) + ); + userInput.clear(); + } + /** + * Creates dialog boxes. Clears the user input after processing. + */ + @FXML + private void addDialog(String response) { + + dialogContainer.getChildren().addAll( + DialogBox.getDukeDialog(response, dukeImage) + ); + + userInput.clear(); + } +} \ No newline at end of file diff --git a/src/main/resources/data/tasks.txt b/src/main/resources/data/tasks.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/main/resources/images/DOOK.png b/src/main/resources/images/DOOK.png new file mode 100644 index 0000000000..577a3e86af Binary files /dev/null and b/src/main/resources/images/DOOK.png differ diff --git a/src/main/resources/images/soyjak.png b/src/main/resources/images/soyjak.png new file mode 100644 index 0000000000..b484190d06 Binary files /dev/null and b/src/main/resources/images/soyjak.png differ diff --git a/src/main/resources/view/DialogBox.fxml b/src/main/resources/view/DialogBox.fxml new file mode 100644 index 0000000000..e433809947 --- /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..0e30c115cd --- /dev/null +++ b/src/main/resources/view/MainWindow.fxml @@ -0,0 +1,19 @@ + + + + + + + + + + + +