diff --git a/.todo.txt b/.todo.txt new file mode 100644 index 0000000000..2845acb71b --- /dev/null +++ b/.todo.txt @@ -0,0 +1,2 @@ +[T][N] hi +[T][N] kasjdna diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..f5c99a7f66 --- /dev/null +++ b/.travis.yml @@ -0,0 +1 @@ +language: java \ No newline at end of file diff --git a/.txt b/.txt new file mode 100644 index 0000000000..b6ea63bf1c --- /dev/null +++ b/.txt @@ -0,0 +1,3 @@ +hello + yellow + mellow \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000000..b213c49c59 --- /dev/null +++ b/build.gradle @@ -0,0 +1,67 @@ +plugins { + id 'java' + id 'application' + id 'checkstyle' + id 'org.openjfx.javafxplugin' version '0.0.7' + id 'com.github.johnrengelman.shadow' version '5.1.0' +} + +javafx { + version = "11.0.2" + modules = [ 'javafx.controls', 'javafx.fxml' ] +} + +dependencies { + String javaFxVersion = '11' + implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'linux' + implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'linux' + implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'linux' + implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'linux' + implementation group: 'org.openjfx', name: 'javafx-media', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-media', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-media', version: javaFxVersion, classifier: 'linux' + implementation group: 'org.openjfx', name: 'javafx-web', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-web', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-web', version: javaFxVersion, classifier: 'linux' + + testCompile('org.junit.jupiter:junit-jupiter:5.5.1') + testImplementation('org.junit.jupiter:junit-jupiter:5.5.1') +} + +test { + useJUnitPlatform() +} + +checkstyle { + toolVersion = '8.23' +} + +repositories { + mavenCentral() +} + +application { + // Change this to your main class. + mainClassName = "duke.Launcher" +} + +run { + standardInput = System.in +} + +shadowJar { + archiveBaseName = "duke" + archiveVersion = "0.1.3" + archiveClassifier = null + archiveAppendix = null +} +group 'seedu.duke' +version '0.1.0' \ No newline at end of file diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml new file mode 100644 index 0000000000..b1a57ba6c0 --- /dev/null +++ b/config/checkstyle/checkstyle.xml @@ -0,0 +1,257 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/README.md b/docs/README.md index fd44069597..4f3cefaac6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,20 +1,105 @@ -# User Guide +# Currents - User Guide -## Features + -### Feature 1 -Description of feature. +### Plan your personal timetable! -## Usage +## Features of Currents -### `Keyword` - Describe action +#### Todo: `todo` +Allows you to track tasks that needs to be done and adds it to a list. -Describe action and its outcome. +#### Deadline: `deadline` +Reminds you of your upcoming deadlines and adds it to a list. -Example of usage: +#### Event: `event` +Remind you of your upcoming events and adds it to a list. -`keyword (optional arguments)` +#### Done: `done` +Allows you to tick off todo/event/deadline tasks that have been completed. -Expected outcome: +#### Delete: `delete` +Allows you to delete finished tasks or wrong tasks that was inputted. -`outcome` +#### Find: `find` +Prints out matching words that you have inputted from the list. + +#### Expenses: `expenses` +Allows you to record your expenses. + +#### List: `list` +Prints out the entire list. + +#### Help: `help` +Prints out all the commands that is available in the application. + +#### Bye: `bye` +Closes the application. + +## Usage of Currents + + +Command | Example | Description +---------------|---------------|--------------- +`todo ` | todo go gym | Add a new to do task. +`event /at
` | event party /at 20/06/2021 1700 | Add a new event task. +`deadline /by
` | deadline essay /by 30/05/2023 2359 | Add a new deadline task. +`done ` | done 1 | Ticks off a todo/event/deadline task. +`delete ` | delete 1 | Deletes a tasks from the list +`find ` | find essay | Find the words that match with your input and prints out corresponding tasks. +`expenses $ /on ` | expenses $45.20 /on steak | Adds an expense to the list. +`list` | list | Prints out everything that you have added to your list. +`help` | help | Prints out all the command that you can use in the application. + +#### Todo: `todo` +Expected Outcome: + + + + +#### Event: `event` +Expected Outcome: + + + + +#### Deadline: `deadline` +Expected Outcome: + + + + +#### Done: `done` +Expected Outcome: + + + + +#### Delete: `delete` +Expected Outcome: + + + + +#### Find: `find` +Expected Outcome: + + + + +#### Expenses: `expenses` +Expected Outcome: + + + + +#### List: `list` +Expected Outcome: + + + + +#### Help: `help` +Expected Outcome: + + diff --git a/docs/Ui.png b/docs/Ui.png new file mode 100644 index 0000000000..46791edda5 Binary files /dev/null and b/docs/Ui.png differ diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 0000000000..ddeb671b60 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-time-machine \ No newline at end of file diff --git a/docs/images/currents.jpg b/docs/images/currents.jpg new file mode 100644 index 0000000000..1bc98621c9 Binary files /dev/null and b/docs/images/currents.jpg differ diff --git a/docs/images/deadline.jpg b/docs/images/deadline.jpg new file mode 100644 index 0000000000..7db8ef5cc9 Binary files /dev/null and b/docs/images/deadline.jpg differ diff --git a/docs/images/delete.jpg b/docs/images/delete.jpg new file mode 100644 index 0000000000..7993c6073e Binary files /dev/null and b/docs/images/delete.jpg differ diff --git a/docs/images/done.jpg b/docs/images/done.jpg new file mode 100644 index 0000000000..8cbfdea290 Binary files /dev/null and b/docs/images/done.jpg differ diff --git a/docs/images/event.jpg b/docs/images/event.jpg new file mode 100644 index 0000000000..aee20d0214 Binary files /dev/null and b/docs/images/event.jpg differ diff --git a/docs/images/expenses.jpg b/docs/images/expenses.jpg new file mode 100644 index 0000000000..166e76fc69 Binary files /dev/null and b/docs/images/expenses.jpg differ diff --git a/docs/images/find.jpg b/docs/images/find.jpg new file mode 100644 index 0000000000..9fcbac5439 Binary files /dev/null and b/docs/images/find.jpg differ diff --git a/docs/images/help.jpg b/docs/images/help.jpg new file mode 100644 index 0000000000..863d925da3 Binary files /dev/null and b/docs/images/help.jpg differ diff --git a/docs/images/list.jpg b/docs/images/list.jpg new file mode 100644 index 0000000000..5f39e87386 Binary files /dev/null and b/docs/images/list.jpg differ diff --git a/docs/images/todo.jpg b/docs/images/todo.jpg new file mode 100644 index 0000000000..a95094fc84 Binary files /dev/null and b/docs/images/todo.jpg differ diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..87b738cbd0 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..4d12c764e2 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue Sep 10 20:33:34 SGT 2019 +distributionUrl=https\://services.gradle.org/distributions/gradle-5.5.1-all.zip +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew new file mode 100755 index 0000000000..af6708ff22 --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## 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"' + +# 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, switch paths to Windows format before running java +if $cygwin ; 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=$((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" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000000..6d57edc706 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@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 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" + +@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/settings.gradle b/settings.gradle new file mode 100644 index 0000000000..d1e92fe5db --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'duke' diff --git a/src/.idea/$PRODUCT_WORKSPACE_FILE$ b/src/.idea/$PRODUCT_WORKSPACE_FILE$ new file mode 100644 index 0000000000..67bd976742 --- /dev/null +++ b/src/.idea/$PRODUCT_WORKSPACE_FILE$ @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/.idea/.gitignore b/src/.idea/.gitignore new file mode 100644 index 0000000000..5c98b42884 --- /dev/null +++ b/src/.idea/.gitignore @@ -0,0 +1,2 @@ +# Default ignored files +/workspace.xml \ No newline at end of file diff --git a/src/.idea/artifacts/src_jar.xml b/src/.idea/artifacts/src_jar.xml new file mode 100644 index 0000000000..0f80aa6c05 --- /dev/null +++ b/src/.idea/artifacts/src_jar.xml @@ -0,0 +1,9 @@ + + + $PROJECT_DIR$/out/artifacts/src_jar + + + + + + \ No newline at end of file diff --git a/src/.idea/misc.xml b/src/.idea/misc.xml new file mode 100644 index 0000000000..1763e153b6 --- /dev/null +++ b/src/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/.idea/modules.xml b/src/.idea/modules.xml new file mode 100644 index 0000000000..47664256fc --- /dev/null +++ b/src/.idea/modules.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/.idea/vcs.xml b/src/.idea/vcs.xml new file mode 100644 index 0000000000..6c0b863585 --- /dev/null +++ b/src/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ 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/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..9f37e4e0aa --- /dev/null +++ b/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: Duke + diff --git a/src/main/java/data/todo.txt b/src/main/java/data/todo.txt new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/main/java/duke/DialogBox.java b/src/main/java/duke/DialogBox.java new file mode 100644 index 0000000000..cf63432648 --- /dev/null +++ b/src/main/java/duke/DialogBox.java @@ -0,0 +1,87 @@ +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.Background; +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); + this.dialog.setMinSize(Label.USE_PREF_SIZE, Label.USE_PREF_SIZE); + 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); + } + + /** + * Sets the color of the dialog from the user. + * + * @param text User input. + * @param img Image that is linked to the user. + * @return Returns a DialogBox so that the user can use it to + * interact with the bot. + */ + public static DialogBox getUserDialog(String text, Image img) { + DialogBox box = new DialogBox(text, img); + box.setBackground(Background.EMPTY); + String style = "-fx-background-color: rgb(255, 218, 26);" + + "-fx-text-fill: black"; + box.dialog.setStyle(style); + return box; + } + + /** + * Flips the dialog for the bot and colors the bot. + * + * @param text Output from the bot. + * @param img Duke image link to the bot. + * @return Returns a DialogBox so that the user can interact with it + * and see the dialog pop up. + */ + public static DialogBox getDukeDialog(String text, Image img) { + var db = new DialogBox(text, img); + db.flip(); + String style = "-fx-background-color: rgb(255, 218, 26);" + + "-fx-text-fill: black"; + db.dialog.setStyle(style); + 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..fa0d8600dc --- /dev/null +++ b/src/main/java/duke/Duke.java @@ -0,0 +1,127 @@ +package duke; + +import duke.exceptions.DukeException; + +import java.io.IOException; +import java.io.FileNotFoundException; +import java.util.Timer; +import java.util.TimerTask; + +import duke.execution.command.ByeCommand; +import duke.execution.command.Command; +import duke.execution.Parser; +import duke.execution.Storage; +import duke.execution.CompleteList; +import duke.execution.Ui; +import javafx.application.Platform; + +public class Duke { + + private Storage storage; + private CompleteList errands; + private Ui ui; + private boolean byeBye = false; + + /** + * Constructor for Duke. + * + * @throws IOException If the named file exists but is a directory rather than a regular file, + * does not exist but cannot be created, or cannot be opened for any other reason. + */ + public Duke() throws IOException { + ui = new Ui(); + storage = new Storage("./todo.txt"); + try { + errands = new CompleteList(storage.load()); + } catch (DukeException | FileNotFoundException e) { + ui.showLoadingError(); + errands = new CompleteList(); + } + } + + /** + * Constructor for Duke that takes in a file to add text into. + * + * @param filepath File that the task is added to. + * @throws IOException If the named file exists but is a directory rather than a regular file, + * does not exist but cannot be created, or cannot be opened for any other reason. + */ + public Duke(String filepath) throws IOException { + ui = new Ui(); + storage = new Storage(filepath); + try { + errands = new CompleteList(storage.load()); + } catch (DukeException | FileNotFoundException e) { + ui.showLoadingError(); + errands = new CompleteList(); + } + } + + /** + * Contains the methods to start the bot and + * start to take in inputs for the bot. + */ + public void run() { + System.out.println("test"); + ui.greeting(); + boolean isThereANextCommand = false; + while (!isThereANextCommand) { + try { + String fullCommand = ui.readCommand(); + ui.printLine(); // show the divider line ("_______") + Command c = Parser.parse(fullCommand); + System.out.println(c.execute(errands, ui, storage)); + isThereANextCommand = c.shouldExit(); + } catch (DukeException | IOException e) { + ui.showError(e.getMessage()); + } finally { + ui.printLine(); + } + } + } + + /** + * Main method. + */ + public static void main(String[] args) throws IOException { + new Duke("todo.txt").run(); + } + + /** + * You should have your own function to generate a response to user input. + * Replace this stub with your completed method. + */ + String getResponse(String input) throws DukeException, IOException { + try { + String fullCommand = input; + Command c = Parser.parse(fullCommand); + if (c instanceof ByeCommand) { + byeBye = true; + } + return (c.execute(errands, ui, storage)); + } catch (DukeException | IOException e) { + ui.showError(e.getMessage()); + return e.getMessage(); + } finally { + if (byeBye) { + closeApplication(); + } + } + } + + /** + * Closes the application. + */ + private void closeApplication() { + Timer countdown = new Timer(); + TimerTask onExit = new TimerTask() { + @Override + public void run() { + Platform.exit(); + System.exit(0); + } + }; + + countdown.schedule(onExit, 2000); + } +} \ No newline at end of file diff --git a/src/main/java/duke/Launcher.java b/src/main/java/duke/Launcher.java new file mode 100644 index 0000000000..5483e63637 --- /dev/null +++ b/src/main/java/duke/Launcher.java @@ -0,0 +1,12 @@ +package duke; + +import javafx.application.Application; + +/** + * A launcher class to workaround classpath issues. + */ +public class Launcher { + public static void main(String[] args) { + Application.launch(Main.class, args); + } +} \ No newline at end of file diff --git a/src/main/java/duke/Main.java b/src/main/java/duke/Main.java new file mode 100644 index 0000000000..33b3ba325d --- /dev/null +++ b/src/main/java/duke/Main.java @@ -0,0 +1,35 @@ +package duke; + +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 Duke duke = new Duke(); + + public Main() throws IOException { + } + + @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.setTitle("Currents - Plan your personal timetable!"); + stage.show(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/main/java/duke/MainWindow.java b/src/main/java/duke/MainWindow.java new file mode 100644 index 0000000000..1765f14dd1 --- /dev/null +++ b/src/main/java/duke/MainWindow.java @@ -0,0 +1,70 @@ +package duke; + +import duke.exceptions.DukeException; + +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 duke.execution.Ui; + +import java.io.IOException; + +/** + * 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/ester.jpg")); + private Image dukeImage = new Image(this.getClass().getResourceAsStream("/images/JoshuaSeet.jpg")); + + /** + * Initializes the console that pops up when the application runs. + */ + @FXML + public void initialize() { + Ui ui = new Ui(); + + scrollPane.vvalueProperty().bind(dialogContainer.heightProperty()); + String style = "-fx-background-color: rgb(0, 81, 186);"; + this.dialogContainer.setStyle(style); + + //duke welcome message upon opening GUI + dialogContainer.getChildren().addAll( + DialogBox.getDukeDialog(ui.greeting(), 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 IOException, DukeException, InterruptedException { + String input = userInput.getText(); + String response = duke.getResponse(input); + dialogContainer.getChildren().addAll( + DialogBox.getUserDialog(input, userImage), + DialogBox.getDukeDialog(response, dukeImage) + ); + userInput.clear(); + } +} \ No newline at end of file diff --git a/src/main/java/duke/exceptions/DukeException.java b/src/main/java/duke/exceptions/DukeException.java new file mode 100644 index 0000000000..6233d24b4f --- /dev/null +++ b/src/main/java/duke/exceptions/DukeException.java @@ -0,0 +1,14 @@ +package duke.exceptions; + +public class DukeException extends Exception { + + /** + * Constructor for Duke Exceptions. + * + * @param message takes in the error and + * prints it out to the user. + */ + public DukeException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/src/main/java/duke/execution/CompleteList.java b/src/main/java/duke/execution/CompleteList.java new file mode 100644 index 0000000000..708f44e058 --- /dev/null +++ b/src/main/java/duke/execution/CompleteList.java @@ -0,0 +1,33 @@ +package duke.execution; + +import duke.models.Planner; + +import java.util.ArrayList; + +public class CompleteList { + + public static ArrayList listOfPlans = new ArrayList(); + + /** + * Constructor for CompleteList. + */ + public CompleteList() { + + } + + /** + * Overloaded Constructor for Task list in + * the event that a array list is available + * from the file. + * + * @param list Arraylist that contains all the tasks. + */ + public CompleteList(ArrayList list) { + listOfPlans = list; + } + + public void addToCompleteList(Planner assignment) { + assert assignment != null; + listOfPlans.add(assignment); + } +} diff --git a/src/main/java/duke/execution/ExpenseList.java b/src/main/java/duke/execution/ExpenseList.java new file mode 100644 index 0000000000..6045413dd6 --- /dev/null +++ b/src/main/java/duke/execution/ExpenseList.java @@ -0,0 +1,23 @@ +package duke.execution; + +import duke.models.Expenses; + +import java.util.ArrayList; + +public class ExpenseList extends CompleteList { + + protected static ArrayList listOfExpenses = new ArrayList(); + + public ExpenseList() { + + } + + public ExpenseList(ArrayList list) { + listOfExpenses = list; + } + + public void addToExpensesList(Expenses assignment) { + assert assignment != null; + listOfExpenses.add(assignment); + } +} diff --git a/src/main/java/duke/execution/Parser.java b/src/main/java/duke/execution/Parser.java new file mode 100644 index 0000000000..80de53367f --- /dev/null +++ b/src/main/java/duke/execution/Parser.java @@ -0,0 +1,571 @@ +package duke.execution; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +import duke.Duke; +import duke.execution.command.Command; +import duke.execution.command.ByeCommand; +import duke.execution.command.DeadlineCommand; +import duke.execution.command.EventCommand; +import duke.execution.command.DoneCommand; +import duke.execution.command.DeleteCommand; +import duke.execution.command.FindCommand; +import duke.execution.command.HelpCommand; +import duke.execution.command.ListCommand; +import duke.execution.command.ToDoCommand; +import duke.execution.command.ExpensesCommand; +import duke.exceptions.DukeException; + +public class Parser { + + /** + * Makes sense of the user input and finds out what command + * the user typed in. + * + * @param line Input by user. + * @return Returns the command that comes from the user. + * @throws DukeException Prints out the message to tell the user + * what was wrong with the input by the user. + */ + public static Command parse(String line) throws DukeException { + assert line != null; + String properInput = line.trim().toLowerCase(); + String[] inputArray = properInput.split(" "); + String taskType = inputArray[0]; + assert taskType != null; + if (!isValidTaskType(taskType)) { + Ui.printIndent(); + throw new DukeException("☹ OOPS!!! I'm sorry, but I don't \n" + + "know what that means :-(\n" + + " I can only do these functions for now: \n \n" + + " Todo \n" + " Eg. todo __(task)__\n" + + " Event \n" + " Eg. event __(task)__\n" + + " /at _(dd/MM/yyyy)_(hhmm)__\n" + + " Deadline \n" + " Eg. deadline __(task)__\n" + + " /by _(dd/MM/yyyy)_(hhmm)__\n" + + " Delete \n" + " Eg. delete __(number)__ or delete all\n" + + " Done \n" + " Eg. done __(number)__\n" + + " Find \n" + " Eg. find __(keyword)__\n" + + " Expenses \n" + " Eg. expenses __$(amount)__\n" + + " /on __(category)__\n" + + " List \n" + " Help\n" + " Bye\n"); + } + + //variable refers to either date or what the expenditure is spent on. + int variableIndex = 0; + String variable = inputArray[0]; + String description = getDescriptionOfTask(properInput); + if (taskType.equals("deadline") || taskType.equals("event") || taskType.equals("expenses")) { + assert description != null; + int slashIndex = properInput.indexOf("/"); + variableIndex = slashIndex + 4; + if (properInput.length() > variableIndex) { + variable = properInput.substring(variableIndex); + } else { + throw new DukeException("Sorry! Please follow the correct format! :)))"); + } + } + switch (taskType) { + case "todo": + if (isValidToDoCommand(properInput)) { + return new ToDoCommand(description); + } else { + Ui.printIndent(); + throw new DukeException("☹ OOPSY DAISY!!! Please follow \n" + + "the correct todo format! :<\n" + + " Todo \n" + + " Eg. todo __(task)__\n"); + } + case "deadline": + if (isValidDeadlineCommand(properInput) && isValidDateFormat(properInput)) { + return new DeadlineCommand(description, formatDate(variable)); + } else { + throw new DukeException("☹ OOPSY DAISY!!! Please follow \n" + + "the correct deadline format! :<\n" + + " Deadline \n" + + " Eg. deadline __(task)__ /by \n" + + " _(dd/MM/yyyy)_(hhmm)__\n"); + } + case "event": + if (isValidEventCommand(properInput) && isValidDateFormat(properInput)) { + return new EventCommand(description, formatDate(variable)); + } else { + Ui.printIndent(); + throw new DukeException("☹ OOPSY DAISY!!! Please follow \n" + + "the correct event format! :<\n" + + " Event \n" + + " Eg. event __(task)__ /at \n" + + " _(dd/MM/yyyy)_(hhmm)__\n"); + } + case "delete": + if (isValidDeleteCommand(properInput)) { + return new DeleteCommand(taskType, description); + } else { + Ui.printIndent(); + throw new DukeException("☹ OOPSY DAISY!!! Please follow \n" + + "the correct delete format! :<\n" + + " Delete \n" + + " Eg. delete __(number)__ or delete all\n"); + } + case "find": + if (isValidFindCommand(properInput)) { + return new FindCommand(taskType, description); + } else { + Ui.printIndent(); + throw new DukeException("☹ OOPSY DAISY!!! Please follow\n" + + "the correct find format! :<\n" + + " Find \n" + " Eg. find __(keyword)__\n"); + } + case "done": + if (isValidDoneCommand(properInput)) { + return new DoneCommand(taskType, description); + } else { + Ui.printIndent(); + throw new DukeException("☹ OOPSY DAISY!!! Please follow \n" + + "the correct done format! :<\n" + + " Done \n" + + " Eg. done __(number[not expenses task])__\n"); + } + case "expenses": + if (isValidExpensesCommand(properInput)) { + System.out.println("asda"); + return new ExpensesCommand(description, variable); + } else { + Ui.printIndent(); + throw new DukeException("☹ OOPSY DAISY!!! Please follow \n" + + "the correct done format! :<\n" + + " Expenses \n" + + " Eg. expenses __$(amount)__ /on __(category)__\n"); + } + case "list": + return new ListCommand(description); + case "bye": + Command byeCommand = new ByeCommand(description); + byeCommand.exitSwitch(); + return byeCommand; + case "help": + return new HelpCommand(description); + default: + throw new DukeException("☹ OOPS!!! I'm sorry, but I don't \n" + + "know what that means :-(\n" + + " I can only do these functions for now: \n \n" + + " Todo \n" + " Eg. todo __(task)__\n" + + " Event \n" + " Eg. event __(task)__\n" + + " /at _(dd/MM/yyyy)_(hhmm)__\n" + + " Deadline \n" + " Eg. deadline __(task)__\n" + + " /by _(dd/MM/yyyy)_(hhmm)__\n" + + " Delete \n" + " Eg. delete __(number)__ or delete all\n" + + " Done \n" + " Eg. done __(number)__\n" + + " Find \n" + " Eg. find __(keyword)__\n" + + " Expenses \n" + " Eg. expenses __$(amount)__\n" + + " /on __(category)__\n" + + " List \n" + " Help\n" + " Bye\n"); + } + } + + /** + * Gets the slash index from the input, if available. + * This is so that we can determine the dates easily. + * + * @param text Input by the user. + * @return Returns the index of the slash. + */ + public static int getSlashIndex(String text) { + return text.indexOf("/"); + } + + /** + * Gets the day numbers from the input. + * + * @param text Date and Time. + * @return Returns the day numbers. + * @throws DukeException If the numbers are not valid, then a DukeException will + * be thrown to inform the user. + */ + public static int getDayDateNumbers(String text) throws DukeException { + assert text != null; + if ((text.length() > (getSlashIndex(text) + 4)) && (text.length() > (getSlashIndex(text) + 6))) { + return Integer.parseInt(text.substring(getSlashIndex(text) + 4, getSlashIndex(text) + 6)); + } else { + throw new DukeException("Wrong Format! Please enter a date\n" + + " format as follows: dd/mm/yyyy hhmm."); + } + } + + /** + * Gets the month numbers from the input. + * + * @param text Date and Time. + * @return Returns the month numbers. + * @throws DukeException If the numbers are not valid, then a DukeException will + * be thrown to inform the user. + */ + public static int getMonthDateNumbers(String text) throws DukeException { + assert text != null; + if ((text.length() > (getSlashIndex(text) + 7)) && (text.length() > (getSlashIndex(text) + 9))) { + return Integer.parseInt(text.substring(getSlashIndex(text) + 7, getSlashIndex(text) + 9)); + } else { + throw new DukeException("Wrong Format! Please enter a date\n" + + " format as follows: dd/mm/yyyy hhmm."); + } + } + + /** + * Gets the year numbers from the input. + * + * @param text Date and Time. + * @return Returns the year numbers. + * @throws DukeException If the numbers are not valid, then a DukeException will + * be thrown to inform the user. + */ + public static int getYearDateNumbers(String text) throws DukeException { + assert text != null; + if ((text.length() > (getSlashIndex(text) + 10)) && (text.length() > (getSlashIndex(text) + 14))) { + return Integer.parseInt(text.substring(getSlashIndex(text) + 10, getSlashIndex(text) + 14)); + } else { + throw new DukeException("Wrong Format! Please enter a date\n" + + " format as follows: dd/mm/yyyy hhmm."); + } + } + + /** + * Gets the hour numbers from the input. + * + * @param text Date and Time. + * @return Returns the hour numbers. + * @throws DukeException If the numbers are not valid, then a DukeException will + * be thrown to inform the user. + */ + public static int getHourDateNumbers(String text) throws DukeException { + assert text != null; + if ((text.length() > (getSlashIndex(text) + 15)) && (text.length() > (getSlashIndex(text) + 17))) { + return Integer.parseInt(text.substring(getSlashIndex(text) + 15, getSlashIndex(text) + 17)); + } else { + Ui.printIndent(); + throw new DukeException("Wrong Format! Please enter a date\n" + + " format as follows: dd/mm/yyyy hhmm."); + } + } + + + /** + * Gets the minute numbers from the input. + * + * @param text Date and Time. + * @return Returns the minute numbers. + * @throws DukeException If the numbers are not valid, then a DukeException will + * be thrown to inform the user. + */ + public static int getMinuteDateNumbers(String text) throws DukeException { + assert text != null; + if (text.length() >= (getSlashIndex(text) + 17)) { + return Integer.parseInt(text.substring(getSlashIndex(text) + 17)); + } else { + throw new DukeException("Wrong Format! Please enter a date\n" + + " format as follows: dd/mm/yyyy hhmm."); + } + } + + + /** + * Checks whether the numbers are within the limit of days, + * months, years, hours and minutes. + * + * @param text Date and Time. + * @return Returns a boolean that checks whether the numbers are valid or not. + * @throws DukeException If the numbers are not valid, then a DukeException will + * be thrown to inform the user. + */ + public static boolean isValidDateNumbers(String text) throws DukeException { + assert text != null; + int dayDate = getDayDateNumbers(text); + int monthDate = getMonthDateNumbers(text); + int yearDate = getYearDateNumbers(text); + int timeHour = getHourDateNumbers(text); + int timeMin = getMinuteDateNumbers(text); + return dayDate > 0 && dayDate <= 31 && monthDate > 0 && monthDate <= 12 + && timeHour > 0 && timeHour <= 24 && timeMin >= 0 && timeMin <= 59 + && yearDate >= 2019; + } + + /** + * Checks whether the dates and numbers given are valid or not. + * + * @param text Dates and Time. + * @return Returns a boolean that checks whether the numbers are valid or not. + * @throws DukeException If the numbers are not valid, then a DukeException will + * be thrown to inform the user. + */ + public static boolean isValidDateFormat(String text) throws DukeException { + assert text != null; + if (isValidDateNumbers(text)) { + return true; + } else { + Ui.printIndent(); + throw new DukeException("Invalid Date Format!\n" + + " There are at most 31 days, 12 months,\n" + + " 23 hours and 59 minutes! \n" + + "And remember that the year is 2019!\n" + + " Please try again! Thank you! :)"); + } + } + + /** + * Method to format the date into the appropriate format. + * For example, 10/02/2012 1800 to 10th of February 2012, 6:00 pm. + * + * @param date Takes in a valid date to format it. + * @return Returns the correctly formatted date with the + * appropriate strings. + */ + public static String formatDate(String date) throws DukeException { + assert date != null; + String formatted = date; + if (!date.contains(")")) { + try { + Date d = new SimpleDateFormat("dd/MM/yyyy hhmm").parse(date); + String day = new SimpleDateFormat("dd").format(d); + String month = new SimpleDateFormat("MMMMMMMMMMMMMMM").format(d); + String year = new SimpleDateFormat("yyyy").format(d); + String time = new SimpleDateFormat("h:mm a").format(d).toLowerCase(); + String endOfDate; + int dayInteger = Integer.parseInt(day); + + if (dayInteger % 10 == 1 && dayInteger != 11) { + endOfDate = "st"; + } else if (dayInteger % 10 == 2 && dayInteger != 12) { + endOfDate = "nd"; + } else if (dayInteger % 10 == 3 && dayInteger != 13) { + endOfDate = "rd"; + } else { + endOfDate = "th"; + } + formatted = dayInteger + endOfDate + " of " + month + " " + year + ", " + time; + } catch (ParseException e) { + Ui.printIndent(); + System.out.println(e.getMessage()); + Ui.printIndent(); + System.out.println("That is the wrong date format! >:-("); + } + } else { + throw new DukeException("Sorry, wrong format!"); + } + return formatted; + } + + /** + * Checks whether the task type is at least one of the functions available. + * + * @param taskType User input. + * @return Returns a boolean that checks whether the task type is valid or not. + */ + public static boolean isValidTaskType(String taskType) { + assert taskType != null; + if (taskType.equals("todo") || taskType.equals("event") || taskType.equals("deadline") + || taskType.equals("delete") || taskType.equals("done") || taskType.equals("find") + || taskType.equals("list") || taskType.equals("bye") || taskType.equals("expenses") + || taskType.equals("help")) { + return true; + } else { + return false; + } + } + + /** + * Sieves out the description of the task and returns it. + * + * @param text User input. + * @return Returns the description of the task without task type and dates/variables. + * @throws DukeException Throws out a DukeException if the text doesnt follow any of the + * task formats. + */ + public static String getDescriptionOfTask(String text) throws DukeException { + assert text != null; + String description = text; + int spaceIndex = text.indexOf(" "); + if ((text.contains("deadline") && isValidDeadlineCommand(text)) + || (text.contains("event") && isValidEventCommand(text)) + || (text.contains("expenses") && isValidExpensesCommand(text))) { + int slashIndex = text.indexOf("/"); + description = text.substring(spaceIndex + 1, slashIndex - 1); + return description; + } else if (text.contains("todo") || text.contains("done") + || text.contains("delete") || text.contains("find")) { + description = text.substring(spaceIndex + 1); + return description; + } else { + return description; + } + } + + /** + * Checks whether the to do command input given is valid + * and follows the format that is provided. + * + * @param text User input. + * @return Returns a boolean that tells us whether the to do command is valid. + */ + public static boolean isValidToDoCommand(String text) { + assert text != null; + return text.contains(" ") && text.length() > 5; + } + + /** + * Checks whether the deadline command input given is valid + * and follows the format that is provided. + * + * @param text User input. + * @return Returns a boolean that tells us whether the deadline command is valid. + */ + public static boolean isValidDeadlineCommand(String text) { + assert text != null; + return text.contains(" ") && text.contains("/") && text.contains("by"); + } + + /** + * Checks whether the event command input given is valid + * and follows the format that is provided. + * + * @param text User input. + * @return Returns a boolean that tells us whether the event command is valid. + */ + public static boolean isValidEventCommand(String text) { + assert text != null; + return text.contains(" ") && text.contains("/") && text.contains("at"); + } + + /** + * Checks whether the delete command input given is valid + * and follows the format that is provided. + * + * @param text User input. + * @return Returns a boolean that tells us whether the delete command is valid. + * @throws DukeException If the format is wrong, a DukeException will be thrown + * to inform the user and to retype it properly again. + * @throws NumberFormatException If the user types in a character that is not a number, + * an exception will be thrown to inform the user. + */ + public static boolean isValidDeleteCommand(String text) throws DukeException, NumberFormatException { + assert text != null; + if (text.length() < 7) { + Ui.printIndent(); + throw new DukeException("Wrong Format! Please add an 'all' or\n" + + " a valid number after the delete word! :)"); + } else { + char[] valueArray = text.substring(7).toCharArray(); + boolean isNumber = false; + for (int i = 0; i < valueArray.length; i++) { + isNumber = false; + if (Character.isDigit(valueArray[i])) { + isNumber = true; + } + } + if (text.contains("all")) { + return text.contains(" "); + } else if (isNumber && Integer.parseInt(text.substring(7)) > 0) { + return text.contains(" ") && Integer.parseInt(text.substring(7)) <= CompleteList.listOfPlans.size(); + } else { + Ui.printIndent(); + throw new DukeException("Wrong Format! Please add an 'all' or\n" + + "a valid number after the delete word! Thank You :)"); + } + } + } + + /** + * Checks whether the find command input given is valid + * and follows the format that is provided. + * + * @param text User input. + * @return Returns a boolean that tells us whether the find command is valid. + */ + public static boolean isValidFindCommand(String text) { + assert text != null; + return text.contains(" ") && text.length() > 5; + } + + /** + * Checks whether the done command input given is valid + * and follows the format that is provided. + * + * @param text User input. + * @return Returns a boolean that tells us whether the done commmand is valid. + * @throws DukeException If the format is wrong, a DukeException will be thrown + * to inform the user and to retype it properly again. + */ + public static boolean isValidDoneCommand(String text) throws DukeException { + assert text != null; + if (text.length() < 5) { + Ui.printIndent(); + throw new DukeException("Wrong Format! Please add a \n" + + "valid number after the done word! :)"); + } else { + char[] valueArray = text.substring(5).toCharArray(); + boolean isNumber = false; + for (int i = 0; i < valueArray.length; i++) { + isNumber = false; + if (Character.isDigit(valueArray[i])) { + isNumber = true; + } + } + if (isNumber && Integer.parseInt(text.substring(5)) > 0) { + return text.contains(" ") && Integer.parseInt(text.substring(5)) <= CompleteList.listOfPlans.size() + && isValidDoneNumberGiven(text.substring(5)); + } else { + Ui.printIndent(); + throw new DukeException("Wrong Format! Please add a valid \n" + + "number that is a task (and not an expenses!!)\n" + + " after the done word! Thank You :)"); + } + } + } + + /** + * Checks whether the expenses command given is valid + * and follows the format provided. + * + * @param text User input + * @return Returns a boolean that tells us if the input is valid. + */ + public static boolean isValidExpensesCommand(String text) { + assert text != null; + return text.contains(" ") && text.contains("/") && text.contains("on") && text.length() > 20; + } + + /** + * Checks whether the done number given is valid. In other + * words, checks if done number is given to either todo, event + * or deadline. + * + * @param num Number given by the user. + * @return Returns a boolean that tells the user whether the number given + * satisfies the conditions. + */ + public static boolean isValidDoneNumberGiven(String num) { + int taskNumber = Integer.parseInt(num); + try { + BufferedReader br = new BufferedReader(new FileReader(Storage.file)); + String text; + int counter = 0; + int lineCounter = 0; + while ((text = br.readLine()) != null) { + lineCounter++; + if (lineCounter == taskNumber) { + if (text.contains("[Expenses]")) { + return false; + } else { + return true; + } + } + } + } catch (IOException e) { + System.out.println(e); + } + return false; + } +} diff --git a/src/main/java/duke/execution/Storage.java b/src/main/java/duke/execution/Storage.java new file mode 100644 index 0000000000..83ac073fe9 --- /dev/null +++ b/src/main/java/duke/execution/Storage.java @@ -0,0 +1,176 @@ +package duke.execution; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Scanner; + +import duke.models.Planner; +import duke.models.Deadline; +import duke.models.Event; +import duke.models.Expenses; +import duke.models.Task; +import duke.models.Todo; + +import duke.exceptions.DukeException; + +public class Storage { + + protected static ArrayList taskList = new ArrayList(); + public static String file = ".todo.txt"; + + /** + * Constructor for Storage. + * + * @param file File that the list of tasks to be. + */ + public Storage(String file) { + + } + + /** + * Adds tasks to the file. + * + * @param filepath File that the task is added to. + * @param textToAdd Tasks that needs to be added. + * @throws IOException If the named file exists but + * is a directory rather than a regular file, + * does not exist but cannot be created, or + * cannot be opened for any other reason. + */ + public void addToFile(String filepath, String textToAdd) throws IOException { + assert filepath != null; + assert textToAdd != null; + FileWriter typer = new FileWriter(filepath, true); + typer.write(textToAdd + System.lineSeparator()); + typer.close(); + } + + /** + * Writes task to a file. + * Can be used as a way to overwrite tasks in the file as well. + * + * @param filepath File that the task is added to. + * @param textToAdd Tasks that needs to be added. + * @throws IOException If the named file exists but + * is a directory rather than a regular file, + * does not exist but cannot be created, or + * cannot be opened for any other reason. + */ + public void writeToFile(String filepath, String textToAdd) throws IOException { + assert filepath != null; + assert textToAdd != null; + FileWriter typer = new FileWriter(filepath); + typer.write(textToAdd); + typer.close(); + } + + /** + * Counts the number of tasks in the list. + * + * @param filename File that the tasks are in. + * @return Returns the number of tasks. + * @throws IOException If the named file exists but + * is a directory rather than a regular file, + * does not exist but cannot be created, or + * cannot be opened for any other reason. + */ + public static int countLines(String filename) throws IOException { + assert filename != null; + try (InputStream inputs = new BufferedInputStream(new FileInputStream(filename))) { + byte[] characters = new byte[1024]; + int readCharacters = inputs.read(characters); + if (readCharacters == -1) { + // no lines to read + return 0; + } + int count = 0; + while (readCharacters == 1024) { + for (int i = 0; i < 1024; ) { + if (characters[i++] == '\n') { + ++count; + } + } + readCharacters = inputs.read(characters); + } + // count remaining characters + while (readCharacters != -1) { + for (int i = 0; i < readCharacters; ++i) { + if (characters[i] == '\n') { + ++count; + } + } + readCharacters = inputs.read(characters); + } + + return count == 0 ? 1 : count; + } + } + + /** + * Loads the task into the task list + * in TaskList from the file. + * + * @return ArrayList that has been copied from the file. + * @throws IOException If the named file exists but is a directory rather than a regular file, + * does not exist but cannot be created, or cannot be opened for any other reason. + * @throws DukeException If there is nothing in the file to be loaded, + * this exception will be thrown. + */ + public ArrayList load() throws IOException, DukeException { + File f = new File(file); + assert f != null; + Scanner sc = new Scanner(f); + ArrayList tempList; + if (countLines(file) == 0) { + throw new DukeException("Woahsies wavy! There is nothing in this file!"); + } else { + while (sc.hasNext()) { + String plans = sc.nextLine(); + int startBracketIndex = plans.indexOf("["); + int closeBracketIndex = plans.indexOf("]"); + String taskType = plans.substring(startBracketIndex + 1, closeBracketIndex); + int spaceIndex = plans.indexOf(" "); + switch (taskType) { + case "T": + Task toDo = new Todo(plans.substring(spaceIndex)); + taskList.add(toDo); + TaskList.listOfTasks.add(toDo); + break; + case "D": + int byIndex = plans.indexOf("("); + Task deadline = new Deadline(plans.substring(spaceIndex, byIndex - 1), + plans.substring(byIndex + 4)); + taskList.add(deadline); + TaskList.listOfTasks.add(deadline); + break; + case "E": + int atIndex = plans.indexOf("("); + Task event = new Event(plans.substring(spaceIndex, atIndex - 1), + plans.substring(atIndex + 4)); + taskList.add(event); + TaskList.listOfTasks.add(event); + break; + case "Expenses": + int onIndex = plans.indexOf("("); + Expenses expense = new Expenses(plans.substring(spaceIndex, onIndex - 1), + plans.substring(onIndex + 4)); + taskList.add(expense); + ExpenseList.listOfExpenses.add(expense); + break; + default: + break; + } + } + Ui.printLine(); + Ui.printIndent(); + System.out.println("Your file has been loaded! :)"); + tempList = new ArrayList(taskList); + return tempList; + } + } +} diff --git a/src/main/java/duke/execution/TaskList.java b/src/main/java/duke/execution/TaskList.java new file mode 100644 index 0000000000..29db5c3584 --- /dev/null +++ b/src/main/java/duke/execution/TaskList.java @@ -0,0 +1,33 @@ +package duke.execution; + +import java.util.ArrayList; + +import duke.models.Task; + +public class TaskList extends CompleteList { + + public static ArrayList listOfTasks = new ArrayList(); + + /** + * Constructor for TaskList. + */ + public TaskList() { + + } + + /** + * Overloaded Constructor for Task list in + * the event that a array list is available + * from the file. + * + * @param list Arraylist that contains all the tasks. + */ + public TaskList(ArrayList list) { + listOfTasks = list; + } + + public void addToTaskList(Task assignment) { + assert assignment != null; + listOfTasks.add(assignment); + } +} diff --git a/src/main/java/duke/execution/Ui.java b/src/main/java/duke/execution/Ui.java new file mode 100644 index 0000000000..79d7b9ed31 --- /dev/null +++ b/src/main/java/duke/execution/Ui.java @@ -0,0 +1,173 @@ +package duke.execution; + +import java.io.IOException; +import java.util.Scanner; + +public class Ui { + + protected Scanner scan = new Scanner(System.in); + + /** + * Constructor for Ui. + */ + public Ui() { + + } + + /** + * Prints the greeting at the initiation of the chat bot. + */ + public String greeting() { + String dukeLogo = " ____ _ \n" + + " | _ \\ _ _| | _____ \n" + + " | | | | | | | |/ / _ \\\n" + + " | |_| | |_| | < __/\n" + + " |____/ \\__,_|_|\\_\\___|\n"; + + // Prints out greeting of the chat bot. + String logo = " Hello! My name is \n" + dukeLogo + "\n" + + " What can I do for you? \n"; + printIndent(); + logo += " I can only do these functions for now: \n \n" + + " Todo \n" + " Eg. todo __(task)__\n" + + " Event \n" + " Eg. event __(task)__\n" + + " /at _(dd/MM/yyyy)_(hhmm)__\n" + + " Deadline \n" + " Eg. deadline __(task)__\n" + + " /by _(dd/MM/yyyy)_(hhmm)__\n" + + " Delete \n" + " Eg. delete __(number)__ or delete all\n" + + " Done \n" + " Eg. done __(number)__\n" + + " Find \n" + " Eg. find __(keyword)__\n" + + " Expenses \n" + " Eg. expenses __$(amount)__\n" + + " /on __(category)__\n" + + " List \n" + " Help\n" + " Bye\n"; + //printIndent(); + //System.out.println("Ill be adding in more features soon! Please be patient! :)"); + return logo; + } + + /** + * Prints indentation. + * Helps to order the output, making it much neater. + */ + public static void printIndent() { + System.out.print(" "); + } + + /** + * Prints line. + * Helps to order the output and makes it + * much neater. + */ + public static void printLine() { + printIndent(); + System.out.println("_____________________________" + + "______________________________________"); + } + + /** + * Prints a statement informing the user that the bot + * has added the task into the list. + */ + public String printGI() { + return "Got it. I've added this task:"; + } + + /** + * Ends the chat bot. + */ + public String printBye() { + return "Bye. Hope to see you again soon!"; + } + + /** + * Reads what the user writes. + * + * @return Returns what the scanner reads. + */ + public String readCommand() { + return scan.nextLine(); + } + + /** + * To remove a task if it is not needed anymore. + * + * @param i Indicates the task number that is done. + */ + public static String printDelete(int i) { + return CompleteList.listOfPlans.get(i - 1).toString(); + } + + /** + * Prints a statement to tell the user that the task has been removed. + */ + public String printRemove() { + return "Noted. I've removed this task."; + } + + /** + * Prints the number of tasks in the list. + * + * @throws IOException If the named file exists but is a directory rather than a regular file, + * does not exist but cannot be created, or cannot be opened for any other reason. + */ + public static String printNumOfTasks() throws IOException { + return "Now you have " + Ui.getNumOfTasks() + " tasks in the list."; + } + + /** + * Gets the number of task inside the file. + * + * @return Number of tasks. + * @throws IOException If the named file exists + * but is a directory rather than a regular file, + * does not exist but cannot be created, or + * cannot be opened for any other reason. + */ + public static int getNumOfTasks() throws IOException { + return Storage.countLines(Storage.file); + } + + /** + * When there is nothing in the file, this method + * will print out to the user, telling them that there + * is no previous tasks saved in the file. + */ + public void showLoadingError() { + printLine(); + printIndent(); + System.out.println("Nothing in file!"); + } + + /** + * Prints out the error message. + * + * @param error Error message. + */ + public void showError(String error) { + assert error != null; + System.out.println(error); + } + + /** + * Prints out a String that informs the user what functions + * are available on this application. + * + * @return Returns a String that lists out all the functions. + */ + public String printHelp() { + printLine(); + printIndent(); + return " I can only do these functions for now: \n \n" + + " Todo \n" + " Eg. todo __(task)__\n" + + " Event \n" + " Eg. event __(task)__\n" + + " /at _(dd/MM/yyyy)_(hhmm)__\n" + + " Deadline \n" + " Eg. deadline __(task)__\n" + + " /by _(dd/MM/yyyy)_(hhmm)__\n" + + " Delete \n" + " Eg. delete __(number)__ or delete all\n" + + " Done \n" + " Eg. done __(number)__\n" + + " Find \n" + " Eg. find __(keyword)__\n" + + " Expenses \n" + " Eg. expenses __$(amount)__\n" + + " /on __(category)__\n" + + " List \n" + " Help\n" + " Bye\n"; + } +} \ No newline at end of file diff --git a/src/main/java/duke/execution/command/ByeCommand.java b/src/main/java/duke/execution/command/ByeCommand.java new file mode 100644 index 0000000000..e8d7c8738b --- /dev/null +++ b/src/main/java/duke/execution/command/ByeCommand.java @@ -0,0 +1,34 @@ +package duke.execution.command; + +import duke.execution.CompleteList; +import duke.execution.Storage; +import duke.execution.Ui; + +public class ByeCommand extends Command { + + /** + * Constructor for Bye Command. + * + * @param action Bye action to shut down duke bot. + */ + public ByeCommand(String action) { + super(action); + } + + /** + * Prints out bye statement to signal to user + * that the bot is shutting down. + * + * @param errands Saves tasks into tasklist if task + * is present + * @param ui Prints out messages to show to user. + * @param storage Stores tasks into file. + */ + @Override + public String execute(CompleteList errands, Ui ui, Storage storage) { + assert errands != null; + assert ui != null; + assert storage != null; + return ui.printBye(); + } +} diff --git a/src/main/java/duke/execution/command/Command.java b/src/main/java/duke/execution/command/Command.java new file mode 100644 index 0000000000..1fddf763cd --- /dev/null +++ b/src/main/java/duke/execution/command/Command.java @@ -0,0 +1,71 @@ +package duke.execution.command; + +import java.io.IOException; + +import duke.exceptions.DukeException; + +import duke.execution.CompleteList; +import duke.execution.Storage; +import duke.execution.Ui; + +public class Command { + + protected String action; + protected String variable; + private static boolean canExit = false; + + /** + * Constructor for Command classes. + * + * @param action Description of tasks. + */ + public Command(String action) { + this.action = action; + } + + /** + * Constructor for Command classes. + * + * @param action Description of tasks. + * @param variable Variable that changes depending on the command. + */ + public Command(String action, String variable) { + this.action = action; + this.variable = variable; + } + + /** + * Tells the loop whether it should exit it. + * + * @return Returns the boolean canExit. + */ + public boolean shouldExit() { + return canExit; + } + + /** + * Changes the boolean canExit to the opposite value. + * + * @return Returns the newly changed boolean. + */ + public boolean exitSwitch() { + return canExit = !canExit; + } + + /** + * Dummy return value as it is always overrided by child classes. + * + * @param list Not needed in this case. + * @param ui Not needed in this case. + * @param storage Not needed in this case. + * @return Returns a dummy string. + * @throws IOException If the named file exists but is a directory rather + * than a regular file, does not exist but cannot be + * created, or cannot be opened for any other reason. + * @throws DukeException If there is a different input that is not accepted, + * a error message will show up. + */ + public String execute(CompleteList list, Ui ui, Storage storage) throws IOException, DukeException { + return ""; + } +} diff --git a/src/main/java/duke/execution/command/DeadlineCommand.java b/src/main/java/duke/execution/command/DeadlineCommand.java new file mode 100644 index 0000000000..072afdf986 --- /dev/null +++ b/src/main/java/duke/execution/command/DeadlineCommand.java @@ -0,0 +1,55 @@ +package duke.execution.command; + +import java.io.IOException; +import duke.execution.CompleteList; +import duke.execution.Storage; +import duke.execution.TaskList; +import duke.execution.Ui; + +import duke.models.Deadline; +import duke.models.Task; + +public class DeadlineCommand extends Command { + + /** + * Constructor for Deadline Command. + * + * @param action Description of the task. + * @param variable Date to finish the tasks. + */ + public DeadlineCommand(String action, String variable) { + super(action, variable); + } + + /** + * Executes the deadline command and prints out statements to + * tell the user that the deadline tasks has been added to + * the list of tasks. + * + * @param errands Adds the deadline to the list of tasks. + * @param ui Prints out statements to indicate to user what + * has happened. + * @param storage Stores the tasks inside another file so that + * the task will be available the next time the + * bot starts up. + * @return Returns String to print out to the user. + * @throws IOException If the named file exists but is a directory rather + * than a regular file, does not exist but cannot be + * created, or cannot be opened for any other reason. + */ + @Override + public String execute(CompleteList errands, Ui ui, Storage storage) throws IOException { + assert errands != null; + assert ui != null; + assert storage != null; + Task assignmentToDo = new Deadline(action, variable); + TaskList tasks = new TaskList(); + tasks.addToTaskList(assignmentToDo); + errands.addToCompleteList(assignmentToDo); + storage.addToFile(Storage.file, assignmentToDo.toString()); + String deadlineOutput = ui.printGI() + "\n"; + deadlineOutput += " " + assignmentToDo.toString() + "\n"; + deadlineOutput += Ui.printNumOfTasks(); + return deadlineOutput; + } +} \ No newline at end of file diff --git a/src/main/java/duke/execution/command/DeleteCommand.java b/src/main/java/duke/execution/command/DeleteCommand.java new file mode 100644 index 0000000000..023fb59e76 --- /dev/null +++ b/src/main/java/duke/execution/command/DeleteCommand.java @@ -0,0 +1,62 @@ +package duke.execution.command; + +import java.io.IOException; + +import duke.execution.CompleteList; +import duke.execution.Storage; +import duke.execution.Ui; + +import duke.models.Planner; + +public class DeleteCommand extends Command { + + /** + * Constructor for Delete command. + * + * @param action Delete command word. + * @param variable Number of task to be deleted. + */ + public DeleteCommand(String action, String variable) { + super(action, variable); + } + + /** + * Executes the delete command and prints out statements to + * tell the user that the delete tasks has been deleted to + * the list of tasks. + * + * @param errands Not needed in this case. + * @param ui Prints out statements to indicate to user what + * has happened. + * @param storage Stores the tasks inside another file so that + * the task will be available the next time the + * bot starts up. + * @return Returns String to print out to the user. + * @throws IOException If the named file exists but is a directory rather + * than a regular file, does not exist but cannot be + * created, or cannot be opened for any other reason. + */ + @Override + public String execute(CompleteList errands, Ui ui, Storage storage) throws IOException { + assert errands != null; + assert ui != null; + assert storage != null; + if (variable.equals("all")) { + storage.writeToFile(Storage.file, ""); + CompleteList.listOfPlans.clear(); + Ui.printIndent(); + return "Everything in your list has been removed!\n" + + "Add more tasks to get started again!!!"; + } else { + int taskNumber = Integer.parseInt(variable); + CompleteList.listOfPlans.remove(taskNumber - 1); + storage.writeToFile(Storage.file, ""); + for (Planner errand : CompleteList.listOfPlans) { + storage.addToFile(Storage.file, errand.toString()); + } + String deleteOutput = ui.printRemove() + "\n" + Ui.printDelete(taskNumber) + "\n"; + deleteOutput += Ui.printNumOfTasks(); + return deleteOutput; + } + } +} diff --git a/src/main/java/duke/execution/command/DoneCommand.java b/src/main/java/duke/execution/command/DoneCommand.java new file mode 100644 index 0000000000..c07e2ab5c9 --- /dev/null +++ b/src/main/java/duke/execution/command/DoneCommand.java @@ -0,0 +1,75 @@ +package duke.execution.command; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; + +import duke.execution.CompleteList; +import duke.execution.Storage; +import duke.execution.Ui; +import duke.execution.TaskList; + +public class DoneCommand extends Command { + + /** + * Constructor for Done command. + * + * @param action Description of the task. + * @param variable Number of tasks that is completed. + */ + public DoneCommand(String action, String variable) { + super(action, variable); + } + + /** + * Executes the done command and prints out statements to + * tell the user that the deadline tasks has been added to + * the list of tasks. + * + * @param errands Not needed in this case. + * @param ui Not needed in this case. + * @param storage Not needed in this case. + * @return Returns String to print out to the user. + */ + @Override + public String execute(CompleteList errands, Ui ui, Storage storage) { + assert errands != null; + assert ui != null; + assert storage != null; + int taskNum = Integer.parseInt(variable); + System.out.println(taskNum - getNumOfExpensesBeforeDoneTask(taskNum) - 1); + TaskList.listOfTasks.get(taskNum - getNumOfExpensesBeforeDoneTask(taskNum) - 1).markAsDone(); + String doneOutput = "Nice! I've marked this task as done:\n"; + doneOutput += TaskList.listOfTasks.get(taskNum - getNumOfExpensesBeforeDoneTask(taskNum) - 1).toString(); + return doneOutput; + } + + /** + * Checks how many expenses task there are before + * the tasks that is to be ticked off. + * + * @param taskNum Task Number from User input. + * @return returns the number of expenses in front of the done task. + */ + public static int getNumOfExpensesBeforeDoneTask(int taskNum) { + try { + BufferedReader br = new BufferedReader(new FileReader(Storage.file)); + String text; + int counter = 0; + int lineCounter = 0; + while ((text = br.readLine()) != null) { + lineCounter++; + if (text.contains("Expenses")) { + counter++; + } + if (lineCounter == taskNum) { + break; + } + } + return counter; + } catch (IOException e) { + System.out.println(e); + } + return 0; + } +} diff --git a/src/main/java/duke/execution/command/EventCommand.java b/src/main/java/duke/execution/command/EventCommand.java new file mode 100644 index 0000000000..d7f10d4b20 --- /dev/null +++ b/src/main/java/duke/execution/command/EventCommand.java @@ -0,0 +1,56 @@ +package duke.execution.command; + +import java.io.IOException; + +import duke.execution.CompleteList; +import duke.execution.Storage; +import duke.execution.TaskList; +import duke.execution.Ui; + +import duke.models.Event; +import duke.models.Task; + +public class EventCommand extends Command { + + /** + * Constructor for Event Command. + * + * @param action Description of the task. + * @param variable Date to finish the tasks. + */ + public EventCommand(String action, String variable) { + super(action, variable); + } + + /** + * Executes the deadline command and prints out statements to + * tell the user that the deadline tasks has been added to + * the list of tasks. + * + * @param errands Adds the deadline to the list of tasks. + * @param ui Prints out statements to indicate to user what + * has happened. + * @param storage Stores the tasks inside another file so that + * the task will be available the next time the + * bot starts up. + * @return Returns String to print out to the user. + * @throws IOException If the named file exists but is a directory rather + * than a regular file, does not exist but cannot be + * created, or cannot be opened for any other reason. + */ + @Override + public String execute(CompleteList errands, Ui ui, Storage storage) throws IOException { + assert errands != null; + assert ui != null; + assert storage != null; + TaskList tasks = new TaskList(); + Task assignmentToDo = new Event(action, variable); + tasks.addToTaskList(assignmentToDo); + errands.addToCompleteList(assignmentToDo); + storage.addToFile(Storage.file, assignmentToDo.toString()); + String eventOutput = ui.printGI() + "\n"; + eventOutput += " " + assignmentToDo.toString() + "\n"; + eventOutput += Ui.printNumOfTasks(); + return eventOutput; + } +} \ No newline at end of file diff --git a/src/main/java/duke/execution/command/ExpensesCommand.java b/src/main/java/duke/execution/command/ExpensesCommand.java new file mode 100644 index 0000000000..4e8967af67 --- /dev/null +++ b/src/main/java/duke/execution/command/ExpensesCommand.java @@ -0,0 +1,33 @@ +package duke.execution.command; + +import java.io.IOException; + +import duke.execution.CompleteList; +import duke.execution.ExpenseList; +import duke.execution.Storage; +import duke.execution.Ui; + +import duke.models.Expenses; + +public class ExpensesCommand extends Command { + + public ExpensesCommand(String action, String variable) { + super(action, variable); + } + + @Override + public String execute(CompleteList errands, Ui ui, Storage storage) throws IOException { + assert errands != null; + assert ui != null; + assert storage != null; + Expenses expense = new Expenses(action, variable); + ExpenseList expenses = new ExpenseList(); + expenses.addToExpensesList(expense); + expenses.addToCompleteList(expense); + storage.addToFile(Storage.file, expense.toString()); + String expenseOutput = ui.printGI() + "\n"; + expenseOutput += " " + expense.toString() + "\n"; + expenseOutput += Ui.printNumOfTasks(); + return expenseOutput; + } +} diff --git a/src/main/java/duke/execution/command/FindCommand.java b/src/main/java/duke/execution/command/FindCommand.java new file mode 100644 index 0000000000..67d1e1bca4 --- /dev/null +++ b/src/main/java/duke/execution/command/FindCommand.java @@ -0,0 +1,81 @@ +package duke.execution.command; + +import duke.exceptions.DukeException; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Scanner; + +import duke.execution.CompleteList; +import duke.execution.Storage; +import duke.execution.Ui; + +public class FindCommand extends Command { + + /** + * Constructor for FindCommand. + * + * @param action Find command word.s + * @param variable Number of task to be deleted. + */ + public FindCommand(String action, String variable) { + super(action, variable); + + } + + /** + * Executes the deadline command and prints out statements to + * tell the user that the deadline tasks has been added to + * the list of tasks. + * + * @param errands Not needed in this case. + * @param ui Prints out statements to indicate to user what + * has happened. + * @param storage Not needed in this case. + * @return Returns String to print out to the user. + * @throws IOException If the named file exists but is a directory rather + * than a regular file, does not exist but cannot be + * created, or cannot be opened for any other reason. + * @throws DukeException If there is no matching word, an error message + * will be sent to the user. + */ + @Override + public String execute(CompleteList errands, Ui ui, Storage storage) throws DukeException, IOException { + assert errands != null; + assert ui != null; + assert storage != null; + File f = new File(Storage.file); + Scanner sc = new Scanner(f); + ArrayList tempList = new ArrayList<>(); + int num = 1; + while (sc.hasNext()) { + String text = sc.nextLine(); + int spaceIndex = text.indexOf(" "); + int bracketIndex = text.length(); + if (text.contains("(")) { + bracketIndex = text.indexOf("("); + } + String description = text.substring(spaceIndex + 1, bracketIndex); + if (description.contains(variable)) { + String task = num + "." + text; + tempList.add(task); + num++; + } + } + if (tempList.isEmpty()) { + Ui.printIndent(); + throw new DukeException("No such word is found in\n" + + "any of the tasks."); + } else { + Ui.printIndent(); + String matchingTask = "Here are the matching tasks\n" + + " in your list!\n"; + for (String str : tempList) { + Ui.printIndent(); + matchingTask += str + "\n"; + } + return matchingTask; + } + } +} diff --git a/src/main/java/duke/execution/command/HelpCommand.java b/src/main/java/duke/execution/command/HelpCommand.java new file mode 100644 index 0000000000..a966d4ac11 --- /dev/null +++ b/src/main/java/duke/execution/command/HelpCommand.java @@ -0,0 +1,23 @@ +package duke.execution.command; + +import java.io.IOException; + +import duke.execution.CompleteList; +import duke.execution.Storage; +import duke.execution.Ui; + +public class HelpCommand extends Command { + + public HelpCommand(String action) { + super(action); + } + + @Override + public String execute(CompleteList errands, Ui ui, Storage storage) throws IOException { + assert errands != null; + assert ui != null; + assert storage != null; + return ui.printHelp(); + } +} + diff --git a/src/main/java/duke/execution/command/ListCommand.java b/src/main/java/duke/execution/command/ListCommand.java new file mode 100644 index 0000000000..aec719b04f --- /dev/null +++ b/src/main/java/duke/execution/command/ListCommand.java @@ -0,0 +1,53 @@ +package duke.execution.command; + +import java.io.File; +import java.io.FileNotFoundException; +import java.util.Scanner; + +import duke.execution.CompleteList; +import duke.execution.Storage; +import duke.execution.Ui; + +public class ListCommand extends Command { + + /** + * Constructor for ListCommand. + * + * @param action List Command word. + */ + public ListCommand(String action) { + super(action); + } + + /** + * Executes the list command and prints out all the + * tasks in the list. + * + * @param errands Not needed in this case. + * @param ui Not needed in this case. + * @param storage Not needed in this case. + * @return Returns those tasks that match the keyword. + * @throws FileNotFoundException If there is no prior list of task + * available, there is nothing to print, + * thus, an error message will be shown. + */ + @Override + public String execute(CompleteList errands, Ui ui, Storage storage) throws FileNotFoundException { + assert errands != null; + assert ui != null; + assert storage != null; + if (CompleteList.listOfPlans.isEmpty()) { + return "There is no tasks currently!!!"; + } else { + String list = "Here are the tasks in your list:\n"; + File temp = new File(Storage.file); + Scanner s = new Scanner(temp); + int numbering = 1; + while (s.hasNext()) { + list += numbering + ". " + s.nextLine() + "\n"; + numbering++; + } + return list; + } + } +} diff --git a/src/main/java/duke/execution/command/ToDoCommand.java b/src/main/java/duke/execution/command/ToDoCommand.java new file mode 100644 index 0000000000..6be19c8ac3 --- /dev/null +++ b/src/main/java/duke/execution/command/ToDoCommand.java @@ -0,0 +1,55 @@ +package duke.execution.command; + +import java.io.IOException; + +import duke.execution.CompleteList; +import duke.execution.Storage; +import duke.execution.TaskList; +import duke.execution.Ui; + +import duke.models.Task; +import duke.models.Todo; + +public class ToDoCommand extends Command { + + /** + * Constructor for To Do Command. + * + * @param action Description of To Do task. + */ + public ToDoCommand(String action) { + super(action); + } + + /** + * Executes the To do command. Adds the to do task to + * a list and prints out the task again to confirm that + * task has been added to the list. + * + * @param errands Adds the deadline to the list of tasks. + * @param ui Prints out statements to indicate to user what + * has happened. + * @param storage Stores the tasks inside another file so that + * the task will be available the next time the + * bot starts up. + * @return Returns String to print out to the user. + * @throws IOException If the named file exists but is a directory rather + * than a regular file, does not exist but cannot be + * created, or cannot be opened for any other reason. + */ + @Override + public String execute(CompleteList errands, Ui ui, Storage storage) throws IOException { + assert errands != null; + assert ui != null; + assert storage != null; + Task assignmentToDo = new Todo(action); + TaskList tasks = new TaskList(); + tasks.addToTaskList(assignmentToDo); + errands.addToCompleteList(assignmentToDo); + storage.addToFile(Storage.file, assignmentToDo.toString()); + String todoOutput = ui.printGI() + "\n"; + todoOutput += " " + assignmentToDo.toString() + "\n"; + todoOutput += Ui.printNumOfTasks(); + return todoOutput; + } +} diff --git a/src/main/java/duke/models/Deadline.java b/src/main/java/duke/models/Deadline.java new file mode 100644 index 0000000000..444d8963d2 --- /dev/null +++ b/src/main/java/duke/models/Deadline.java @@ -0,0 +1,30 @@ +package duke.models; + +public class Deadline extends Task { + + protected String by; + + /** + * Constructor for Deadline task. + * + * @param description Deadline task to be added. + * @param by Date of the deadline task. + */ + public Deadline(String description, String by) { + super(description); + this.by = by; + } + + /** + * Method to give the string that is to be + * added to the list of tasks. + * + * @return Returns the string to be loaded into + * the file and printed out. + */ + @Override + public String toString() { + assert by != null; + return "[D]" + super.toString() + " " + description + " (by: " + by + ")"; + } +} \ No newline at end of file diff --git a/src/main/java/duke/models/Event.java b/src/main/java/duke/models/Event.java new file mode 100644 index 0000000000..783122e737 --- /dev/null +++ b/src/main/java/duke/models/Event.java @@ -0,0 +1,30 @@ +package duke.models; + +public class Event extends Task { + + protected String when; + protected boolean isValid; + + /** + * Constructor for Event task. + * + * @param description Event task to be attended. + * @param when Date of the event. + */ + public Event(String description, String when) { + super(description); + this.when = when; + } + + /** + * Method to give the string that is to be + * added to the list of tasks. + * + * @return Returns the string to be loaded into + * the file and printed out. + */ + @Override + public String toString() { + return "[E]" + super.toString() + " " + description + " (at: " + when + ")"; + } +} \ No newline at end of file diff --git a/src/main/java/duke/models/Expenses.java b/src/main/java/duke/models/Expenses.java new file mode 100644 index 0000000000..6563653d4c --- /dev/null +++ b/src/main/java/duke/models/Expenses.java @@ -0,0 +1,22 @@ +package duke.models; + +public class Expenses extends Planner { + + protected String on; + + public Expenses(String description, String on) { + super(description); + this.on = on; + } + + /** + * Method to mark the task to done. + */ + public void markAsDone() { + isDone = true; + } + + public String toString() { + return "[Expenses] " + description + " (on: " + on + ")"; + } +} diff --git a/src/main/java/duke/models/Find.java b/src/main/java/duke/models/Find.java new file mode 100644 index 0000000000..e083525591 --- /dev/null +++ b/src/main/java/duke/models/Find.java @@ -0,0 +1,14 @@ +package duke.models; + +public class Find extends Task { + + /** + * Constructor for Find tasks. + * + * @param description Description of tasks to find. + */ + public Find(String description) { + super(description); + } + +} diff --git a/src/main/java/duke/models/Planner.java b/src/main/java/duke/models/Planner.java new file mode 100644 index 0000000000..1815cc2e46 --- /dev/null +++ b/src/main/java/duke/models/Planner.java @@ -0,0 +1,19 @@ +package duke.models; + +public class Planner { + + protected String description; + protected boolean isDone; + + public Planner(String description) { + this.description = description; + this.isDone = false; + } + + /** + * Method to mark the task to done. + */ + public void markAsDone() { + isDone = true; + } +} diff --git a/src/main/java/duke/models/Task.java b/src/main/java/duke/models/Task.java new file mode 100644 index 0000000000..51ddfe51f9 --- /dev/null +++ b/src/main/java/duke/models/Task.java @@ -0,0 +1,48 @@ +package duke.models; + +public class Task extends Planner { + + protected boolean isDone; + protected boolean isCorrectFormat; + + /** + * Constructor for Task. + * + * @param description Takes in a string that is + * either Todo, Event or Deadline. + */ + public Task(String description) { + super(description); + this.isDone = false; + this.isCorrectFormat = false; + } + + + /** + * Returns tick or cross symbol. + * + * @return A tick or cross to symbolize whether the task has been done. + */ + public String getStatusIcon() { + return (isDone ? "done" : "not done"); + } + + /** + * Method to mark the task to done. + */ + public void markAsDone() { + isDone = true; + } + + /** + * Method to get the String for whether + * the task is done or not. + * + * @return Returns the tick or cross in brackets. + */ + public String toString() { + return "[" + getStatusIcon() + "]"; + } + + +} diff --git a/src/main/java/duke/models/Todo.java b/src/main/java/duke/models/Todo.java new file mode 100644 index 0000000000..c9f82efc2a --- /dev/null +++ b/src/main/java/duke/models/Todo.java @@ -0,0 +1,24 @@ +package duke.models; + +public class Todo extends Task { + + /** + * Constructor for Todo task. + * + * @param description Takes in todo task. + */ + public Todo(String description) { + super(description); + } + + /** + * Method to get the string for Todo tasks. + * + * @return Returns the formatted string to + * be added into tasklist and file. + */ + @Override + public String toString() { + return "[T]" + super.toString() + " " + description; + } +} \ No newline at end of file diff --git a/src/main/resources/images/JoshuaSeet.jpg b/src/main/resources/images/JoshuaSeet.jpg new file mode 100644 index 0000000000..708ec88763 Binary files /dev/null and b/src/main/resources/images/JoshuaSeet.jpg differ diff --git a/src/main/resources/images/ester.jpg b/src/main/resources/images/ester.jpg new file mode 100644 index 0000000000..6052bbdd9b Binary files /dev/null and b/src/main/resources/images/ester.jpg 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..d1a786be62 --- /dev/null +++ b/src/main/resources/view/MainWindow.fxml @@ -0,0 +1,20 @@ + + + + + + + + + + + + +