diff --git a/README.md b/README.md index 8715d4d915..6b6e4a56b1 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,32 @@ -# Duke project template +# DukePro +> “Your mind is for having ideas, not holding them.” – David Allen ([source](https://dansilvestre.com/productivity-quotes)) -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. +DukePro frees your mind of having to remember things you need to do. It's, -## Setting up in Intellij +- text-based +- easy to learn +- ~~FAST~~ *SUPER* FAST and EASY to use -Prerequisites: JDK 11, update Intellij to the most recent version. +All you need to do is, -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 - ____ _ - | _ \ _ _| | _____ - | | | | | | | |/ / _ \ - | |_| | |_| | < __/ - |____/ \__,_|_|\_\___| - ``` +1. download it from [here](https://github.com/Hoodineee/ip). +2. double-click it. +3. add your tasks. +4. let it manage your tasks for you :wink: + +And it is **FREE**! + +Features: + +- [x] Managing tasks +- [ ] Managing deadlines (coming soon) +- [ ] Reminders (coming soon) + +If you Java programmer, you can use it to practice Java too. Here's the `main` method: +```java +public class Main { + public static void main(String[] args) { + Application.launch(MainApp.class, args); + } +} +``` diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000000..b32cd97368 --- /dev/null +++ b/build.gradle @@ -0,0 +1,56 @@ +plugins { + id 'java' + id 'application' + id 'com.github.johnrengelman.shadow' version '5.1.0' +} + +repositories { + mavenCentral() +} + +dependencies { + String javaFxVersion = '11' + + implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'linux' + implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'linux' + implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'linux' + implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'win' + implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'mac' + implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'linux' + + testImplementation 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' +} + +test { + useJUnitPlatform() + + testLogging { + events "passed", "skipped", "failed" + + showExceptions true + exceptionFormat "full" + showCauses true + showStackTraces true + showStandardStreams = false + } +} + +application { + mainClassName = "Launcher" +} + +shadowJar { + archiveBaseName = "DuckWifaKnife" + archiveClassifier = null +} + +run{ + standardInput = System.in +} diff --git a/data/duckwifaknife.txt b/data/duckwifaknife.txt new file mode 100644 index 0000000000..8d9992d171 --- /dev/null +++ b/data/duckwifaknife.txt @@ -0,0 +1 @@ +[D][ ] commit ip (by: Feb 2 2022) diff --git a/docs/README.md b/docs/README.md index 8077118ebe..7e13f37456 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,29 +1,168 @@ # User Guide +DuckWifaKnife, a friendly duck that helps you manage your tasks -## Features +### Feature - `todo` -### Feature-ABC +Adds a Todo type task to your tasklist. -Description of the feature. +### Feature - `deadline` -### Feature-XYZ +Adds a Deadline type task to your tasklist. -Description of the feature. +### Feature - `event` + +Adds an Event type task to your tasklist. + +### Feature - `notes` + +Adds a note to your noteslist. + +### Feature - `list` + +Lists out all the tasks and notes in your tasklist and noteslist. + +### Feature - `mark` + +Marks the specific task in the index given as done in the tasklist. + +### Feature - `unmark` + +Marks the specific task in the index given as not done in the tasklist. + +### Feature - `find` + +Find any matching task in the tasklist with the given keyword. + +### Feature - `delete` + +Deletes the specific task in the index given. + +### Feature - `bye` + +Closes the program. ## Usage -### `Keyword` - Describe action +### `todo` - The todo feature will be activated. -Describe the action and its outcome. +A Todo type task will be created and added to the tasklist. Example of usage: -`keyword (optional arguments)` +`todo finalise ip` + +Expected outcome: + +![image](https://user-images.githubusercontent.com/97339748/190917787-9783b9df-4e8b-458f-b167-34337fc92d71.png) + +### `deadline` - The dealine feature will be activated. + +A Deadline type task will be created and added to the tasklist. + +Example of usage: + +`deadline commit ip /by 20/09/2022 2359` + +Expected outcome: + +![image](https://user-images.githubusercontent.com/97339748/190917832-7492ea68-2e54-461e-b5e8-90b58f383baa.png) + +### `event` - The event feature will be activated. + +A Event type task will be created and added to the tasklist. + +Example of usage: + +`event done with ip celebration /at 21/09/2022 0000` + +Expected outcome: + +![image](https://user-images.githubusercontent.com/97339748/190917846-f5df45c6-ef52-4ab0-acea-df2c9bfaab61.png) + +### `notes` - The notes feature will be activated. + +A Note will be created and added to the noteslist. + +Example of usage: + +`notes i'm bad at coding` + +Expected outcome: + +![image](https://user-images.githubusercontent.com/97339748/190917860-c0f3c0f2-1f40-41ff-8d9b-c6db562544f3.png) + +### `list` - The list feature will be activated. + +Lists all the tasks and notes in the tasklist and noteslist. + +Example of usage: + +`list` + +Expected outcome: + +![image](https://user-images.githubusercontent.com/97339748/190917875-f2413279-36e8-4645-b7ff-87ea16c662a4.png) + +### `mark` - The mark feature will be activated. + +The task at the index given will be marked as done. + +Example of usage: + +`mark 2` + +Expected outcome: + +![image](https://user-images.githubusercontent.com/97339748/190917885-421d6875-f07a-4ec2-a1a3-c22038b38a8e.png) + +### `unmark` - The mark feature will be activated. + +The task at the index given will be marked as done. + +Example of usage: + +`unmark 2` + +Expected outcome: + +![image](https://user-images.githubusercontent.com/97339748/190917896-b1405211-8bc3-4096-be1a-d9adeec50513.png) + +### `find` - The find feature will be activated. + +Finds any tasks or notes with the given keyword. + +Example of usage: + +`find ip` + +Expected outcome: + +![image](https://user-images.githubusercontent.com/97339748/190918104-f0d69d66-3b1d-4244-878b-da9f1110cc5d.png) + +### `delete` - The delete feature will be activated. + +The task at the index given will deleted. + +Example of usage: + +`delete 2` + +Expected outcome: + +![image](https://user-images.githubusercontent.com/97339748/190918126-981a1876-3077-49fa-b6f5-017b89508660.png) + +### `bye` - The bye feature will be activated. + +Closes the program. + +Example of usage: + +`bye` Expected outcome: -Description of the outcome. +The program will close. ``` -expected output +Bye. Hope to see you again soon! ``` diff --git a/docs/Ui.png b/docs/Ui.png new file mode 100644 index 0000000000..5bca3dddcd Binary files /dev/null and b/docs/Ui.png differ diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..f3d88b1c2f Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000000..b7c8c5dbf5 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000000..2fe81a7d95 --- /dev/null +++ b/gradlew @@ -0,0 +1,183 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000000..62bd9b9cce --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,103 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java deleted file mode 100644 index 5d313334cc..0000000000 --- a/src/main/java/Duke.java +++ /dev/null @@ -1,10 +0,0 @@ -public class Duke { - public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); - } -} diff --git a/src/main/java/GUI/DialogBox.java b/src/main/java/GUI/DialogBox.java new file mode 100644 index 0000000000..1ce498edc4 --- /dev/null +++ b/src/main/java/GUI/DialogBox.java @@ -0,0 +1,61 @@ +package GUI; + +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/GUI/MainWindow.java b/src/main/java/GUI/MainWindow.java new file mode 100644 index 0000000000..e554ebe2d6 --- /dev/null +++ b/src/main/java/GUI/MainWindow.java @@ -0,0 +1,57 @@ +package GUI; + +import duke.Duke; +import javafx.application.Platform; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.TextField; +import javafx.scene.image.Image; +import javafx.scene.layout.VBox; +/** + * Controller for MainWindow. Provides the layout for the other controls. + */ +public class MainWindow extends VBox { + @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/DaUser.png")); + private Image dukeImage = new Image(this.getClass().getResourceAsStream("/images/DaDuke.png")); + + @FXML + public void initialize() { + scrollPane.vvalueProperty().bind(dialogContainer.heightProperty()); + dialogContainer.getChildren().add(DialogBox.getDukeDialog + ("Hello! I'm Duck\n" + "What can I do for you?", this.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() { + String input = userInput.getText(); + String response = duke.getResponse(input); + dialogContainer.getChildren().addAll( + DialogBox.getUserDialog(input, userImage), + DialogBox.getDukeDialog(response, dukeImage) + ); + if (response.startsWith("Bye")) { + Platform.exit(); + } + userInput.clear(); + } +} \ No newline at end of file diff --git a/src/main/java/Launcher.java b/src/main/java/Launcher.java new file mode 100644 index 0000000000..6e85208576 --- /dev/null +++ b/src/main/java/Launcher.java @@ -0,0 +1,11 @@ +import duke.Main; +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/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..2c9a9745c5 --- /dev/null +++ b/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: duke.Duke + diff --git a/src/main/java/command/AddCommand.java b/src/main/java/command/AddCommand.java new file mode 100644 index 0000000000..ff991270b3 --- /dev/null +++ b/src/main/java/command/AddCommand.java @@ -0,0 +1,148 @@ +package command; + +import storage.Storage; +import task.TaskList; +import task.NotesList; +import ui.Ui; +import exception.DukeException; +import task.Task; +import task.Todo; +import task.Deadline; +import task.Event; +import task.Notes; + +/** + * Represents an Add Command that inherits from + * the abstract class Command. + */ + +public class AddCommand extends Command { + protected String commandLine; + + /** + * Constructor for this AddCommand that takes in a + * commandLine as a String. + * + * @param commandLine Command from the user. + */ + public AddCommand(String commandLine) { + this.commandLine = commandLine; + } + + /** + * Returns a boolean false to show that this + * is not the last command. + * + * @return false. + */ + @Override + public boolean isExit() { + return false; + } + + /** + * Executes the command depending on which type of + * task it is and prints a string to tell the user that + * the task has been added. + * + * @param taskList The ArrayList that contains all the tasks. + * @param ui The Ui that interacts with the next command from the user. + * @param storage The Storage used to store the tasks. + * @throws DukeException If the description of task is empty. + */ + @Override + public String execute(TaskList taskList, NotesList notesList, Ui ui, Storage storage) throws DukeException { + String response = ""; + assert !taskList.isEmpty(); + assert !notesList.isEmpty(); + if (commandLine.startsWith("todo")) { + try { + if (commandLine.length() <= 5) { + throw new DukeException("The description of a todo cannot be empty."); + } else { + String actTask = commandLine.substring(5); + Task currTask = new Todo(actTask); + taskList.add(currTask); + storage.updateData(taskList, notesList); + response = "Got it. I've added this todo task:\n" + + " " + currTask + "\n" + "Now you have " + + taskList.size() + " tasks in the list.\n"; + System.out.println(response); + return response; + } + } catch (DukeException e) { + System.out.println(e.toString()); + return e.toString(); + } + } else if (commandLine.startsWith("deadline")) { + try { + if (commandLine.length() <= 9) { + throw new DukeException("The description of a deadline cannot be empty."); + } else { + if (!commandLine.contains("/")) { + throw new DukeException("There is no date! >:(\n"); + } else { + int slashIndex = commandLine.indexOf("/"); + String actTask = commandLine.substring(9, slashIndex - 1); + String taskDate = commandLine.substring(slashIndex + 4); + Task currTask = new Deadline(actTask, taskDate); + taskList.add(currTask); + storage.updateData(taskList, notesList); + response = "Got it. I've added this deadline task:\n" + + " " + currTask + "\n" + "Now you have " + + taskList.size() + " tasks in the list.\n"; + System.out.println(response); + return response; + } + } + } catch (DukeException e) { + System.out.println(e.toString()); + return e.toString(); + } + } else if (commandLine.startsWith("event")) { + try { + if (commandLine.length() <= 6) { + throw new DukeException("The description of a event cannot be empty."); + } else { + if (!commandLine.contains("/")) { + throw new DukeException("There is no date! >:("); + } else { + int slashIndex = commandLine.indexOf("/"); + String actTask = commandLine.substring(6, slashIndex - 1); + String taskDate = commandLine.substring(slashIndex + 4); + Task currTask = new Event(actTask, taskDate); + taskList.add(currTask); + storage.updateData(taskList, notesList); + response = "Got it. I've added this event task:\n" + + " " + currTask + "\n" + "Now you have " + + taskList.size() + " tasks in the list.\n"; + System.out.println(response); + return response; + } + } + } catch (DukeException e) { + System.out.println(e.toString()); + return e.toString(); + } + } else { + try { + if (commandLine.length() <= 6) { + throw new DukeException("The description of a notes cannot be empty."); + } else { + String actTask = commandLine.substring(6); + Task currNote = new Notes(actTask); + notesList.add(currNote); + storage.updateData(taskList, notesList); + response = "Got it. I've added this note:\n" + + " " + currNote + "\n" + "Now you have " + + notesList.size() + " notes in the list.\n"; + System.out.println(response); + return response; + } + } catch (DukeException e) { + System.out.println(e.toString()); + return e.toString(); + } + } + } +} diff --git a/src/main/java/command/ByeCommand.java b/src/main/java/command/ByeCommand.java new file mode 100644 index 0000000000..3cd5b4170a --- /dev/null +++ b/src/main/java/command/ByeCommand.java @@ -0,0 +1,49 @@ +package command; + +import storage.Storage; +import task.NotesList; +import task.TaskList; +import ui.Ui; + +/** + * Represents a Bye Command that inherits from + * the abstract class Command. + */ +public class ByeCommand extends Command { + protected String commandLine; + + /** + * Constructor for this that takes in a + * commandLine as a String. + * + * @param commandLine Command from the user. + */ + public ByeCommand(String commandLine) { + this.commandLine = commandLine; + } + + /** + * Returns a boolean true to show that this + * is the last command. + * + * @return true. + */ + @Override + public boolean isExit() { + return true; + } + + /** + * Executes the command and prints a goodbye + * string to the user. + * + * @param taskList The ArrayList that contains all the tasks. + * @param ui The Ui that interacts with the next command from the user. + * @param storage The Storage used to store the tasks. + */ + @Override + public String execute(TaskList taskList, NotesList notesList, Ui ui, Storage storage) { + ui.showGoodbye(); + return "Bye. Hope to see you again soon!"; + } +} diff --git a/src/main/java/command/Command.java b/src/main/java/command/Command.java new file mode 100644 index 0000000000..c2bc1a5a15 --- /dev/null +++ b/src/main/java/command/Command.java @@ -0,0 +1,32 @@ +package command; + +import storage.Storage; +import task.TaskList; +import task.NotesList; +import ui.Ui; + +/** + * An abstract class Command. + */ +public abstract class Command { + + /** + * An abstract method that is implemented in its + * children classes returns a boolean depending on whether + * it is the last command from the user. + * + * @return boolean. + */ + public abstract boolean isExit(); + + /** + * An abstract method that is implemented in its + * children classes that executes the command from the user + * differently depending on what command the user gives. + * + * @param taskList The ArrayList that contains all the tasks. + * @param ui The Ui that interacts with the next command from the user. + * @param storage The Storage used to store the tasks. + */ + public abstract String execute(TaskList taskList, NotesList notesList, Ui ui, Storage storage); +} diff --git a/src/main/java/command/DeleteCommand.java b/src/main/java/command/DeleteCommand.java new file mode 100644 index 0000000000..dea4107784 --- /dev/null +++ b/src/main/java/command/DeleteCommand.java @@ -0,0 +1,79 @@ +package command; + +import storage.Storage; +import task.NotesList; +import task.TaskList; +import ui.Ui; +import exception.DukeException; +import task.Task; +import task.Notes; + +/** + * Represents a Delete Command that inherits from + * the abstract class Command. + */ +public class DeleteCommand extends Command { + protected String commandLine; + + /** + * Constructor for this DeleteCommand that takes in a + * commandLine as a String. + * + * @param commandLine Command from the user. + */ + public DeleteCommand(String commandLine) { + this.commandLine = commandLine; + } + + /** + * Returns a boolean false to show that this + * is not the last command. + * + * @return false. + */ + @Override + public boolean isExit() { + return false; + } + + /** + * Executes the command to delete a task that the user + * wants to remove. + * + * @param taskList The ArrayList that contains all the tasks. + * @param ui The Ui that interacts with the next command from the user. + * @param storage The Storage used to store the tasks. + * @throws DukeException If there are no such task in the taskList. + */ + @Override + public String execute(TaskList taskList, NotesList notesList, Ui ui, Storage storage) { + String response = ""; + int index = Integer.parseInt(commandLine.substring(7)) - 1; + try { + assert !taskList.isEmpty(); + assert !notesList.isEmpty(); + if (index > taskList.size() - 1 || index < 0) { + throw new DukeException("You have no such tasks."); + } else { + Task task = taskList.get(index); + if (task instanceof Notes) { + notesList.remove(index); + response = "Noted. I've removed this task:\n" + + " " + task.toString() + "\n" + "Now you have " + + notesList.size() + " tasks in the list.\n"; + } else { + taskList.remove(index); + response = "Noted. I've removed this note:\n" + + " " + task.toString() + "\n" + "Now you have " + + taskList.size() + " notes in the list.\n"; + } + storage.updateData(taskList, notesList); + System.out.println(response); + return response; + } + } catch (DukeException e) { + System.out.println(e.toString()); + return e.toString(); + } + } +} diff --git a/src/main/java/command/EditCommand.java b/src/main/java/command/EditCommand.java new file mode 100644 index 0000000000..92c8cd1da4 --- /dev/null +++ b/src/main/java/command/EditCommand.java @@ -0,0 +1,99 @@ +package command; + +import storage.Storage; +import task.TaskList; +import task.NotesList; +import ui.Ui; +import exception.DukeException; +import task.Task; +import task.Notes; + +/** + * Represents an EditCommand that inherits from + * the abstract class Command. + */ +public class EditCommand extends Command { + protected String commandLine; + + /** + * Constructor for this EditCommand that takes in a + * commandLine as a String. + * + * @param commandLine Command from the user. + */ + public EditCommand(String commandLine) { + this.commandLine = commandLine; + } + + /** + * Returns a boolean false to show that this + * is not the last command. + * + * @return false. + */ + @Override + public boolean isExit() { + return false; + } + + /** + * Executes the command depending on which action the user + * wants to do and prints a string if it is executed successfully. + * + * @param taskList The ArrayList that contains all the tasks. + * @param ui The Ui that interacts with the next command from the user. + * @param storage The Storage used to store the tasks. + * @throws DukeException If there is no such task. + */ + @Override + public String execute(TaskList taskList, NotesList notesList, Ui ui, Storage storage) { + String response = ""; + assert !taskList.isEmpty(); + assert !notesList.isEmpty(); + if (commandLine.startsWith("mark")) { + int index = Integer.parseInt(commandLine.substring(5)) - 1; + try { + if (index > taskList.size() - 1 || index < 0) { + throw new DukeException("You have no such tasks."); + } else { + Task task = taskList.get(index); + if (task instanceof Notes) { + response = "Sorry, you can't mark a note."; + } else { + task.isMark(true); + response = "Nice! I've marked this task as done:\n" + + " " + task + "\n"; + } + storage.updateData(taskList, notesList); + System.out.println(response); + return response; + } + } catch (DukeException e) { + System.out.println(e.toString()); + return e.toString(); + } + } else { + int index = Integer.parseInt(commandLine.substring(7)) - 1; + try { + if (index > taskList.size() - 1 || index < 0) { + throw new DukeException("You have no such tasks."); + } else { + Task task = taskList.get(index); + if (task instanceof Notes) { + response = "Sorry, you can't unmark a note."; + } else { + task.isMark(false); + storage.updateData(taskList, notesList); + response = "OK, I've marked this task as not done yet:\n" + + " " + task + "\n"; + } + System.out.println(response); + return response; + } + } catch (DukeException e) { + System.out.println(e.toString()); + return e.toString(); + } + } + } +} diff --git a/src/main/java/command/FalseCommand.java b/src/main/java/command/FalseCommand.java new file mode 100644 index 0000000000..19a013d973 --- /dev/null +++ b/src/main/java/command/FalseCommand.java @@ -0,0 +1,55 @@ +package command; + +import storage.Storage; +import task.NotesList; +import task.TaskList; +import ui.Ui; +import exception.DukeException; + +/** + * Represents a FalseCommand that inherits from + * the abstract class Command. + */ +public class FalseCommand extends Command { + protected String commandLine; + + /** + * Constructor for this FalseCommand that takes in a + * commandLine as a String. + * + * @param commandLine Command from the user. + */ + public FalseCommand(String commandLine) { + this.commandLine = commandLine; + } + + /** + * Returns a boolean false to show that this + * is not the last command. + * + * @return false. + */ + @Override + public boolean isExit() { + return false; + } + + /** + * Throws a DukeException to tell the user that the command is + * invalid. + * + * @param taskList The ArrayList that contains all the tasks. + * @param ui The Ui that interacts with the next command from the user. + * @param storage The Storage used to store the tasks. + * @throws DukeException Always. + */ + @Override + public String execute(TaskList taskList, NotesList notesList, Ui ui, Storage storage) throws DukeException { + try { + throw new DukeException("I'm sorry, but I don't know what that means :-(\n"); + } catch (DukeException e) { + System.out.println(e.toString()); + return e.toString(); + } + } +} diff --git a/src/main/java/command/FindCommand.java b/src/main/java/command/FindCommand.java new file mode 100644 index 0000000000..e41bb8b819 --- /dev/null +++ b/src/main/java/command/FindCommand.java @@ -0,0 +1,91 @@ +package command; + +import storage.Storage; +import task.TaskList; +import task.NotesList; +import ui.Ui; +import exception.DukeException; +import task.Task; + +import java.util.ArrayList; + +public class FindCommand extends Command { + protected String fullCommand; + + public FindCommand(String fullCommand) { + this.fullCommand = fullCommand; + } + + /** + * Returns a boolean false to show that this + * is not the last command. + * + * @return false. + */ + @Override + public boolean isExit() { + return false; + } + + /** + * Executes the command depending on which type of + * task it is and prints a string to tell the user that + * the task has been added. + * + * @param taskList The ArrayList that contains all the tasks. + * @param ui The Ui that interacts with the next command from the user. + * @param storage The Storage used to store the tasks. + * @throws DukeException If the description of task is empty. + */ + @Override + public String execute(TaskList taskList, NotesList notesList, Ui ui, Storage storage) throws DukeException { + String response = ""; + try { + assert !taskList.isEmpty(); + assert !notesList.isEmpty(); + if (taskList.size() == 0) { + throw new DukeException("There are no tasks in your list. :)"); + } else { + String taskToFind = this.fullCommand.substring(5); + ArrayList tasksFound = new ArrayList<>(taskList.size()); + for (int i = 0; i < taskList.size(); i++) { + Task currTask = taskList.get(i); + String currTaskString = currTask.toString(); + if (currTaskString.contains(taskToFind)) { + tasksFound.add(currTask); + } + } + if (!notesList.isEmpty()) { + for (int j = 0; j < taskList.size(); j++) { + Task currNote = notesList.get(j); + String currNoteString = currNote.toString(); + if (currNoteString.contains(taskToFind)) { + tasksFound.add(currNote); + } + } + } + if (tasksFound.isEmpty()) { + throw new DukeException("There is nothing that matches the task."); + } else { + System.out.println("Here are the matching tasks in your list:"); + for (int l = 0; l < tasksFound.size(); l++) { + Task currTask = tasksFound.get(l); + String currTaskString = currTask.toString(); + System.out.println(currTaskString); + } + System.out.println(); + response = "Here are the matching tasks in your list:\n"; + for (int k = 0; k < tasksFound.size(); k++) { + Task currTaskFound = tasksFound.get(k); + String currTaskFoundString = currTaskFound.toString() + "\n"; + response += currTaskFoundString; + } + return response; + } + } + } catch (DukeException e) { + System.out.println(e.toString()); + return e.toString(); + } + } +} diff --git a/src/main/java/command/ListCommand.java b/src/main/java/command/ListCommand.java new file mode 100644 index 0000000000..405de469a7 --- /dev/null +++ b/src/main/java/command/ListCommand.java @@ -0,0 +1,80 @@ +package command; + +import storage.Storage; +import task.Task; +import task.TaskList; +import task.NotesList; +import ui.Ui; +import exception.DukeException; + +/** + * Represents a ListCommand that inherits from + * the abstract class Command. + */ +public class ListCommand extends Command { + protected String commandLine; + + /** + * Constructor for this ListCommand that takes in a + * commandLine as a String. + * + * @param commandLine Command from the user. + */ + public ListCommand(String commandLine) { + this.commandLine = commandLine; + } + + /** + * Returns a boolean false to show that this + * is not the last command. + * + * @return false. + */ + @Override + public boolean isExit() { + return false; + } + + /** + * Prints out all the tasks from the taskList if successful. + * + * @param taskList The ArrayList that contains all the tasks. + * @param ui The Ui that interacts with the next command from the user. + * @param storage The Storage used to store the tasks. + * @throws DukeException If the taskList is empty. + */ + @Override + public String execute(TaskList taskList, NotesList notesList, Ui ui, Storage storage) { + String response = ""; + try { + assert !taskList.isEmpty(); + assert !notesList.isEmpty(); + if (taskList.size() == 0) { + throw new DukeException("There are no tasks in your list. :)"); + } else { + System.out.println("Here are the tasks in your list:"); + taskList.forEach(); + System.out.println(); + System.out.println("Here are the notes in your list:"); + notesList.forEach(); + System.out.println(); + response = "Here are the tasks in your list:\n"; + for (int i = 0; i < taskList.size(); i++) { + Task currTask = taskList.get(i); + String currTaskString = currTask.toString(); + response += currTaskString + "\n"; + } + + for (int j = 0; j < notesList.size(); j++) { + Task currNote = notesList.get(j); + String currNoteString = currNote.toString(); + response += currNoteString + "\n"; + } + return response; + } + } catch (DukeException e) { + System.out.println(e.toString()); + return e.toString(); + } + } +} diff --git a/src/main/java/dateformat/DateFormat.java b/src/main/java/dateformat/DateFormat.java new file mode 100644 index 0000000000..ece0e4ec9a --- /dev/null +++ b/src/main/java/dateformat/DateFormat.java @@ -0,0 +1,396 @@ +package dateformat; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.util.HashMap; +import java.util.Locale; + +/** + * Represents DateFormat to format date and time. + */ +public class DateFormat { + protected String date; + protected LocalDate dateFormatted; + protected String afterBy; + protected LocalTime timeFormatted; + protected String stringDate; + protected String stringTime; + protected LocalDateTime dateAndTime; + protected static HashMap months = new HashMap<>(); + + /** + * Constructor for DateFormat that takes in a date + * as a String. + * + * @param date Date in the format of a String. + */ + public DateFormat(String date) { + this.afterBy = date; + this.date = date; + this.dateFormatted = null; + this.timeFormatted = null; + + months.put("JAN", "1"); + months.put("FEB", "2"); + months.put("MAR", "3"); + months.put("APR", "4"); + months.put("MAY", "5"); + months.put("JUN", "6"); + months.put("JUL", "7"); + months.put("AUG", "8"); + months.put("SEP", "9"); + months.put("OCT", "10"); + months.put("NOV", "11"); + months.put("DEC", "12"); + + dateAndTimeFormatter(); + } + + /** + * A formatter to format the date and time + * into a readable String for the DateTimeFormatterBuilder. + */ + public void dateAndTimeFormatter() { + String day; + String month; + String year; + String hour; + String minutes; + String time = ""; + if (this.afterBy.contains("/")) { + if (this.afterBy.indexOf("/") <= 2) { + int afterDaySlashIndex = afterBy.indexOf("/"); + String afterDay; + if (afterDaySlashIndex == 1) { + day = "0" + afterBy.charAt(0); + afterDay = afterBy.substring(afterDaySlashIndex + 1); + } else { + day = afterBy.substring(0, 2); + afterDay = afterBy.substring(afterDaySlashIndex + 1); + } + int afterMonthSlashIndex = afterDay.indexOf("/"); + String afterMonth; + if (afterMonthSlashIndex == 1) { + month = "0" + afterDay.charAt(0); + afterMonth = afterDay.substring(afterMonthSlashIndex + 1); + } else { + month = afterDay.substring(0, 2); + afterMonth = afterDay.substring(afterMonthSlashIndex + 1); + } + year = afterMonth.substring(0, 4); + if (afterMonth.length() > 5) { + if (afterMonth.charAt(7) == ':') { + time = afterMonth.substring(5, 7) + afterMonth.substring(8, 10); + } else { + time = afterMonth.substring(5); + } + } + + } else if (afterBy.indexOf("/") == 3) { + month = afterBy.substring(0, 3); + int afterMonthSlashIndex = afterBy.indexOf("/"); + String afterMonth = afterBy.substring(afterMonthSlashIndex + 1); + int afterDaySlashIndex = afterMonth.indexOf("/"); + String afterDay; + if (afterDaySlashIndex == 1) { + day = "0" + afterMonth.charAt(0); + afterDay = afterMonth.substring(afterMonthSlashIndex + 1); + } else { + day = afterMonth.substring(0, 2); + afterDay = afterMonth.substring(afterMonthSlashIndex + 1); + } + year = afterDay.substring(0, 4); + if (afterDay.length() > 5) { + if (afterDay.charAt(7) == ':') { + time = afterDay.substring(5, 7) + afterDay.substring(8, 10); + } else { + time = afterDay.substring(5); + } + } + } else { + year = afterBy.substring(0, 4); + int afterYearSlashIndex = afterBy.indexOf("/"); + String afterYear = afterBy.substring(afterYearSlashIndex + 1); + int afterMonthSlashIndex = afterYear.indexOf("/"); + String afterMonth; + if (afterMonthSlashIndex == 1) { + month = "0" + afterYear.charAt(0); + afterMonth = afterYear.substring(afterMonthSlashIndex + 1); + } else { + month = afterYear.substring(0, 2); + afterMonth = afterYear.substring(afterMonthSlashIndex + 1); + } + String afterDay; + if (afterMonth.charAt(1) == ' ') { + day = "0" + afterMonth.charAt(0); + afterDay = afterMonth.substring(afterMonthSlashIndex + 1); + } else { + day = afterMonth.substring(0, 2); + afterDay = afterMonth.substring(afterMonthSlashIndex + 1); + } + if (afterDay.length() > 5) { + if (afterDay.charAt(7) == ':') { + time = afterDay.substring(5, 7) + afterDay.substring(8, 10); + } else { + time = afterDay.substring(5); + } + } + } + } else if (this.afterBy.contains("-")) { + if (this.afterBy.indexOf("-") <= 2) { + int afterDayDashIndex = afterBy.indexOf("-"); + String afterDay; + if (afterDayDashIndex == 1) { + day = "0" + afterBy.charAt(0); + afterDay = afterBy.substring(afterDayDashIndex + 1); + } else { + day = afterBy.substring(0, 2); + afterDay = afterBy.substring(afterDayDashIndex + 1); + } + int afterMonthDashIndex = afterDay.indexOf("-"); + String afterMonth; + if (afterMonthDashIndex == 1) { + month = "0" + afterDay.charAt(0); + afterMonth = afterDay.substring(afterMonthDashIndex + 1); + } else { + month = afterDay.substring(0, 2); + afterMonth = afterDay.substring(afterMonthDashIndex + 1); + } + year = afterMonth.substring(0, 4); + if (afterMonth.length() > 5) { + if (afterMonth.charAt(7) == ':') { + time = afterMonth.substring(5, 7) + afterMonth.substring(8, 10); + } else { + time = afterMonth.substring(5); + } + } + } else if (afterBy.indexOf("-") == 3) { + month = afterBy.substring(0, 3); + int afterMonthSlashIndex = afterBy.indexOf("-"); + String afterMonth = afterBy.substring(afterMonthSlashIndex + 1); + int afterDaySlashIndex = afterMonth.indexOf("-"); + String afterDay; + if (afterDaySlashIndex == 1) { + day = "0" + afterMonth.charAt(0); + afterDay = afterMonth.substring(afterMonthSlashIndex + 1); + } else { + day = afterMonth.substring(0, 2); + afterDay = afterMonth.substring(afterMonthSlashIndex + 1); + } + year = afterDay.substring(0, 4); + if (afterDay.length() > 5) { + if (afterDay.charAt(7) == ':') { + time = afterDay.substring(5, 7) + afterDay.substring(8, 10); + } else { + time = afterDay.substring(5); + } + } + } else { + year = afterBy.substring(0, 4); + int afterYearDashIndex = afterBy.indexOf("-"); + String afterYear = afterBy.substring(afterYearDashIndex + 1); + int afterMonthSpaceIndex = afterYear.indexOf("-"); + String afterMonth; + if (afterMonthSpaceIndex == 1) { + month = "0" + afterYear.charAt(0); + afterMonth = afterYear.substring(afterMonthSpaceIndex + 1); + } else { + month = afterYear.substring(0, 2); + afterMonth = afterYear.substring(afterMonthSpaceIndex + 1); + } + String afterDay; + if (afterMonth.charAt(1) == ' ') { + day = "0" + afterMonth.charAt(0); + afterDay = afterMonth.substring(afterMonthSpaceIndex + 1); + } else { + day = afterMonth.substring(0, 2); + afterDay = afterMonth.substring(afterMonthSpaceIndex + 1); + } + if (afterDay.length() > 2) { + if (afterDay.charAt(7) == ':') { + time = afterDay.substring(5, 7) + afterDay.substring(8, 10); + } else { + time = afterDay.substring(5); + } + } + } + } else { + afterBy = afterBy.substring(1); // When read from text file, it has an extra ":". + if (this.afterBy.indexOf(" ") <= 2) { + if (this.afterBy.indexOf(" ") == 0) { + afterBy = afterBy.substring(1); + } + System.out.println(afterBy); + int afterDaySpaceIndex = afterBy.indexOf(" "); + String afterDay; + if (afterDaySpaceIndex == 1) { + day = "0" + afterBy.charAt(0); + afterDay = afterBy.substring(afterDaySpaceIndex + 1); + } else { + day = afterBy.substring(0, 2); + afterDay = afterBy.substring(afterDaySpaceIndex + 1); + } + System.out.println(day); + int afterMonthSpaceIndex = afterDay.indexOf(" "); + String afterMonth; + if (afterMonthSpaceIndex == 1) { + month = "0" + afterDay.charAt(0); + afterMonth = afterDay.substring(afterMonthSpaceIndex + 1); + } else if (afterMonthSpaceIndex == 2) { + month = afterDay.substring(0, 2); + afterMonth = afterDay.substring(afterMonthSpaceIndex + 1); + } else { + month = afterDay.substring(0, 3); + afterMonth = afterDay.substring(afterMonthSpaceIndex + 1); + } + System.out.println(month); + year = afterMonth.substring(0, 4); + System.out.println(afterMonth); + if (afterMonth.length() > 5) { + if (afterMonth.charAt(7) == ':') { + time = afterMonth.substring(5, 7) + afterMonth.substring(8, 10); + } else { + time = afterMonth.substring(5); + } + } + if (!month.contains("1") && !month.contains("0")) { + month = months.get(month.toUpperCase()); + } + } else if (afterBy.indexOf(" ") == 3) { + month = afterBy.substring(0, 3); + int afterMonthSpaceIndex = afterBy.indexOf(" "); + String afterMonth = afterBy.substring(afterMonthSpaceIndex + 1); + int afterDaySpaceIndex = afterMonth.indexOf(" "); + String afterDay; + if (afterDaySpaceIndex == 1) { + day = "0" + afterMonth.charAt(0); + afterDay = afterMonth.substring(afterDaySpaceIndex + 1); + } else { + day = afterMonth.substring(0, 2); + afterDay = afterMonth.substring(afterDaySpaceIndex + 1); + } + year = afterDay.substring(0, 4); + if (afterDay.length() > 5) { + if (afterDay.charAt(7) == ':') { + time = afterDay.substring(5, 7) + afterDay.substring(8, 10); + } else { + time = afterDay.substring(5); + } + } + if (!month.contains("1") && !month.contains("0")) { + month = months.get(month.toUpperCase()); + } + + } else { + year = afterBy.substring(0, 4); + int afterYearSpaceIndex = afterBy.indexOf(" "); + String afterYear = afterBy.substring(afterYearSpaceIndex + 1); + int afterMonthSpaceIndex = afterYear.indexOf(" "); + String afterMonth; + if (afterMonthSpaceIndex == 1) { + month = "0" + afterYear.charAt(0); + afterMonth = afterYear.substring(afterMonthSpaceIndex + 1); + } else if (afterMonthSpaceIndex == 2) { + month = afterYear.substring(0, 2); + afterMonth = afterYear.substring(afterMonthSpaceIndex + 1); + } else { + month = afterYear.substring(0, 3); + afterMonth = afterYear.substring(afterMonthSpaceIndex + 1); + } + String afterDay; + if (afterMonth.charAt(1) == ' ') { + day = "0" + afterMonth.charAt(0); + afterDay = afterMonth.substring(afterMonthSpaceIndex + 1); + } else { + day = afterMonth.substring(0, 2); + afterDay = afterMonth.substring(afterMonthSpaceIndex + 1); + } + if (afterDay.length() > 2) { + if (afterDay.charAt(7) == ':') { + time = afterDay.substring(5, 7) + afterDay.substring(8, 10); + } else { + time = afterDay.substring(5); + } + } + if (!month.contains("1") && !month.contains("0")) { + month = months.get(month.toUpperCase()); + } + } + } + if (month.length() == 1) { + month = "0" + month; + } + this.stringDate = year + "-" + month + "-" + day; + this.dateFormatted = LocalDate.parse(year + "-" + month + "-" + day); + if (date.length() > 10 && time.length() != 0) { + if (time.length() <= 3) { + hour = "0" + time.charAt(0); + minutes = time.substring(1, 3); + } else { + hour = time.substring(0, 2); + minutes = time.substring(2, 4); + } + this.stringTime = hour + ":" + minutes + ":00"; + boolean hourRange = Integer.parseInt(hour) >= 0 && Integer.parseInt(hour) < 24; + boolean minuteRange = Integer.parseInt(minutes) >= 0 && Integer.parseInt(minutes) < 60; + if (hourRange && minuteRange) { + this.timeFormatted = LocalTime.parse(hour + ":" + minutes + ":" + "00"); + } else { + System.out.println("You retarded? Your time is out of range!"); + } + } + if (this.timeFormatted != null) { + this.dateAndTime = LocalDateTime.parse(this.stringDate + "T" + this.stringTime); + } + } + + + /** + * Formats the date in the form of a String into + * a date in the form of LocalDate. + * + * @param pattern The pattern in which the date will be formatted to. + * @return Returns the String version of the date after it has been + * formatted. + */ + public String formatDate(String pattern) { + DateTimeFormatter df = new DateTimeFormatterBuilder().parseCaseInsensitive() + .appendPattern(pattern).toFormatter(Locale.ENGLISH); + return this.dateFormatted.format(df); + } + + /** + * Formats the time in the form of a String into + * a time in the form of LocalTime. + * + * @return Returns the String version of the time after it has + * been formatted. + */ + public String formatTime() { + return this.timeFormatted.format(DateTimeFormatter.ISO_TIME); + } + + /** + * Returns the string representation of the formatted date + * and time. + * + * @return The string representation of the formatted date + * and time. + */ + @Override + public String toString() { + if (this.timeFormatted == null) { + return this.formatDate("MMM d yyyy"); + } else { + return this.formatDate("MMM d yyyy") + " " + this.formatTime(); + } + } + + public static void main(String args[]) { + DateFormat d4 = new DateFormat("12 jun 2022"); + System.out.println(d4.formatDate("MMM d yyyy")); + } +} diff --git a/src/main/java/duke/Duke.java b/src/main/java/duke/Duke.java new file mode 100644 index 0000000000..7b06cea243 --- /dev/null +++ b/src/main/java/duke/Duke.java @@ -0,0 +1,61 @@ +package duke; + +import storage.Storage; +import task.TaskList; +import task.NotesList; +import ui.Ui; +import exception.DukeException; +import parser.Parser; +import command.Command; + +public class Duke { + + private Storage storage; + private TaskList tasks; + private NotesList notes; + private Ui ui; + + public Duke(String filePath) { + System.out.println("Hello! I'm Duke.Duke\nWhat can I do for you?\n"); + storage = new Storage(filePath); + try { + tasks = new TaskList(storage.loadTasks()); + notes = new NotesList(storage.loadNotes()); + ui = new Ui(); + } catch (DukeException e) { + ui.showLoadingError(); + tasks = new TaskList(); + } + } + + public void run() { + boolean isExit = false; + while (!isExit) { + try { + String fullCommand = ui.readCommand(); + ui.showLine(); // show the divider line ("_______") + Parser parser = new Parser(fullCommand); + Command c = parser.parse(fullCommand); + c.execute(tasks, notes, ui, storage); + isExit = c.isExit(); + if (!isExit) { + ui.changeCommand(); + } + } catch (DukeException e) { + ui.showError(e.getMessage()); + } + } + } + + public String getResponse(String input) { + Parser parser = new Parser(input); + Command c = parser.parse(input); + String response = c.execute(tasks, notes, ui, storage); + return response; + } + + public static void main(String[] args) { + new Duke("tasks.txt").run(); + } +} + diff --git a/src/main/java/duke/Main.java b/src/main/java/duke/Main.java new file mode 100644 index 0000000000..e07910993b --- /dev/null +++ b/src/main/java/duke/Main.java @@ -0,0 +1,36 @@ +package duke; + +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; + +import GUI.MainWindow; +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("tasks.txt"); + + @Override + public void start(Stage stage) { + try { + Path path = Paths.get("MainWindow.fxml"); + FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("/view/MainWindow.fxml")); + AnchorPane ap = fxmlLoader.load(); + Scene scene = new Scene(ap); + stage.setTitle("DuckWifaKnife"); + stage.setScene(scene); + fxmlLoader.getController().setDuke(duke); + stage.show(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/main/java/exception/DukeException.java b/src/main/java/exception/DukeException.java new file mode 100644 index 0000000000..1bc1cb36e5 --- /dev/null +++ b/src/main/java/exception/DukeException.java @@ -0,0 +1,14 @@ +package exception; + +public class DukeException extends IllegalArgumentException { + protected String message; + + public DukeException(String message) { + this.message = message; + } + + @Override + public String toString() { + return "☹ OOPS!!! " + this.message + "\n"; + } +} diff --git a/src/main/java/filedata/FileData.java b/src/main/java/filedata/FileData.java new file mode 100644 index 0000000000..184c1d8319 --- /dev/null +++ b/src/main/java/filedata/FileData.java @@ -0,0 +1,147 @@ +package filedata; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Scanner; + +import task.Task; +import task.Todo; +import task.Deadline; +import task.Event; +import task.Notes; + +public class FileData { + protected String fileName; + protected File file; + protected ArrayList tasks; + + + public FileData(String fileName) { + String home = System.getProperty("user.dir"); + java.nio.file.Path path = java.nio.file.Paths.get(home, "data", "duckwifaknife.txt"); + this.fileName = String.valueOf(path); + this.file = new File(String.valueOf(path)); + this.tasks = this.storeArray(); + } + + public boolean exists() { + return this.file.exists(); + } + + private static void writeToFile(String filePath, String textToAdd) throws IOException { + FileWriter fw = new FileWriter(filePath); + fw.write(textToAdd); + fw.close(); + } + + private static void appendToFile(String filePath, String textToAppend) throws IOException { + FileWriter fw = new FileWriter(filePath, true); // create a FileWriter in append mode + fw.write(textToAppend); + fw.close(); + } + + public void updateData(ArrayList tasks, ArrayList notes) { + try { + assert !tasks.isEmpty(); + assert !notes.isEmpty(); + for (int i = 0; i < tasks.size(); i++) { + if (i == 0) { + writeToFile(this.fileName, tasks.get(i).toString() + System.lineSeparator()); + } + + if (i > 0) { + storeData(tasks.get(i).toString()); + } + } + + for (int j = 0; j < notes.size(); j++) { + if (tasks.isEmpty()) { + writeToFile(this.fileName, notes.get(j).toString() + System.lineSeparator()); + } else { + storeData(notes.get(j).toString()); + } + } + } catch (IOException e) { + System.out.println("Something went wrong: " + e.getMessage()); + } + } + + public ArrayList allTasks() { + return this.tasks; + } + + public ArrayList storeArray() { + ArrayList tasksAndNotes = new ArrayList<>(100); + try { + if (!this.file.exists()) { + throw new FileNotFoundException(); + } else { + assert this.file.exists(); + Scanner s = new Scanner(this.file); + while (s.hasNext()) { + String currTask = s.nextLine(); + char currType = currTask.charAt(1); + if (currType == 'T') { + tasksAndNotes.add(new Todo(currTask.substring(7))); + } else if (currType == 'D') { + int bracketIndex = currTask.indexOf("("); + String taskDate = currTask.substring(bracketIndex + 4); + tasksAndNotes.add(new Deadline(currTask.substring(7, bracketIndex - 1), taskDate)); + } else if (currType == 'E') { + int bracketIndex = currTask.indexOf("("); + String taskDate = currTask.substring(bracketIndex + 4); + tasksAndNotes.add(new Event(currTask.substring(7, bracketIndex - 1), taskDate)); + } else { + tasksAndNotes.add(new Notes(currTask.substring(7))); + } + } + System.out.println(); + } + } catch (FileNotFoundException e) { + System.out.println("File not found!"); + System.out.println(); + } + return tasksAndNotes; + } + + public void storeData(String textToStore) { + String file = this.fileName; + try { + appendToFile(file, textToStore + System.lineSeparator()); + } catch (IOException e) { + System.out.println("Something went wrong: " + e.getMessage()); + } + } + + public void toPrint() { + try { + if (!this.file.exists()) { + throw new FileNotFoundException(); + } else { + assert this.file.exists(); + Scanner d = new Scanner(this.file); + while (d.hasNext()) { + System.out.println(d.nextLine()); + } + System.out.println(); + } + } catch (FileNotFoundException e) { + System.out.println("File not found!"); + System.out.println(); + } + } + + + public static void main(String[] args) { + File f = new File("data/duke.txt"); + File f1 = new File("data/tempDuke.txt"); + System.out.println("full path: " + f.getAbsolutePath()); + System.out.println("full path: " + f1.getAbsolutePath()); + System.out.println("file exists?: " + f.exists()); + System.out.println("is Directory?: " + f.isDirectory()); + } + +} diff --git a/src/main/java/parser/Parser.java b/src/main/java/parser/Parser.java new file mode 100644 index 0000000000..c52280f7bb --- /dev/null +++ b/src/main/java/parser/Parser.java @@ -0,0 +1,58 @@ +package parser; + +import command.Command; +import command.AddCommand; +import command.ByeCommand; +import command.DeleteCommand; +import command.EditCommand; +import command.FalseCommand; +import command.FindCommand; +import command.ListCommand; + +/** + * Represents a parser to parse commands from + * the user. + */ +public class Parser { + protected String fullCommand; + + /** + * Constructor for this Parser that takes in + * a command as a string. + * + * @param fullCommand Command from the user. + */ + public Parser(String fullCommand) { + this.fullCommand = fullCommand; + } + + /** + * Returns different types of commands depending on what + * command the user input. + * + * @param fullCommand Command from the user. + * @return Different types of commands depending on the + * user input. + */ + public Command parse(String fullCommand) { + boolean taskCheck = fullCommand.startsWith("todo") + || fullCommand.startsWith("deadline") + || fullCommand.startsWith("event") + || fullCommand.startsWith("notes"); + if (fullCommand.isEmpty() || fullCommand.equals("bye")) { + return new ByeCommand(fullCommand); + } else if (fullCommand.equals("list")) { + return new ListCommand(fullCommand); + } else if (fullCommand.startsWith("delete")) { + return new DeleteCommand(fullCommand); + } else if (fullCommand.startsWith("mark") || fullCommand.startsWith("unmark")) { + return new EditCommand(fullCommand); + } else if (taskCheck) { + return new AddCommand(fullCommand); + } else if (fullCommand.startsWith("find")) { + return new FindCommand(fullCommand); + } else { + return new FalseCommand(fullCommand); + } + } +} diff --git a/src/main/java/storage/Storage.java b/src/main/java/storage/Storage.java new file mode 100644 index 0000000000..1e27c01689 --- /dev/null +++ b/src/main/java/storage/Storage.java @@ -0,0 +1,97 @@ +package storage; + +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; + +import exception.DukeException; +import filedata.FileData; +import task.Task; +import task.TaskList; +import task.NotesList; + +public class Storage { + protected String filePath; + protected FileData fileData; + protected TaskList tasksAndNotes; + protected TaskList tasks; + protected NotesList notes; + + public Storage(String filePath) { + this.filePath = filePath; + this.fileData = new FileData(filePath); + this.tasksAndNotes = new TaskList(this.fileData.storeArray()); + } + + public ArrayList loadTasks() throws DukeException { + this.fileData.toPrint(); + this.tasks = new TaskList(); + for (int i = 0; i < this.tasksAndNotes.size(); i++) { + Task currTask = this.tasksAndNotes.get(i); + char currTaskType = currTask.toString().charAt(1); + if (currTaskType != 'N') { + this.tasks.add(currTask); + } + } + return tasks.toArray(); + } + + public ArrayList loadNotes() throws DukeException { + this.notes = new NotesList(); + for (int i = 0; i < this.tasksAndNotes.size(); i++) { + Task currTask = this.tasksAndNotes.get(i); + char currTaskType = currTask.toString().charAt(1); + if (currTaskType == 'N') { + this.notes.add(currTask); + } + } + return notes.toArray(); + } + + private static void writeToFile(String filePath, String textToAdd) throws IOException { + FileWriter fw = new FileWriter(filePath); + fw.write(textToAdd); + fw.close(); + } + + private static void appendToFile(String filePath, String textToAppend) throws IOException { + FileWriter fw = new FileWriter(filePath, true); // create a FileWriter in append mode + fw.write(textToAppend); + fw.close(); + } + + public void storeData(String textToStore) { + String file = this.filePath; + try { + appendToFile(file, textToStore + System.lineSeparator()); + } catch (IOException e) { + System.out.println("Something went wrong: " + e.getMessage()); + } + } + + public void updateData(TaskList taskList, NotesList notesList) { + ArrayList taskListArray = taskList.toArray(); + ArrayList notesListArray = notesList.toArray(); + fileData.updateData(taskListArray, notesListArray); + } + + public void save() throws DukeException { + if (!this.fileData.exists()) { + throw new DukeException("The file does not exist!"); + } else { + assert this.fileData.exists(); + for (int i = 0; i < tasks.size(); i++) { + try { + if (i == 0) { + writeToFile(this.filePath, tasks.get(i).toString() + System.lineSeparator()); + } else { + storeData(tasks.get(i).toString()); + } + } catch (IOException e) { + System.out.println("Something went wrong: " + e.getMessage()); + } + } + } + } + +} diff --git a/src/main/java/task/Deadline.java b/src/main/java/task/Deadline.java new file mode 100644 index 0000000000..04b209aa37 --- /dev/null +++ b/src/main/java/task/Deadline.java @@ -0,0 +1,57 @@ +package task; + +import dateformat.DateFormat; + +/** + * Represents a Deadline task that inherits + * from Task. + */ +public class Deadline extends Task { + protected String description; + protected boolean isDone; + protected DateFormat date; + + /** + * Constructor for this Deadline task. + * + * @param description The Deadline task. + * @param date The date for the Deadline task. + */ + public Deadline(String description, String date) { + this.description = description; + this.date = new DateFormat(date); + } + + /** + * Changes the boolean isDone depending on whether the user + * wants to mark or unmark the task. + * + * @param bool The boolean for whether the task is marked + * or unmarked. + */ + public void isMark(boolean bool) { + this.isDone = bool; + } + + /** + * Returns a string representation of whether + * the Deadline task is done or undone. + * + * @return Returns a string representation of whether + * the Deadline task is done or undone. + */ + public String getStatusIcon() { + return (isDone ? "X" : " "); // mark done task with X + } + + /** + * Returns the string representation of the Deadline task. + * + * @return Returns the string representation of the Deadline task. + */ + @Override + public String toString() { + return "[D][" + this.getStatusIcon() + "] " + + this.description + " (by: " + this.date.toString() + ")"; + } +} diff --git a/src/main/java/task/Event.java b/src/main/java/task/Event.java new file mode 100644 index 0000000000..1b08f041af --- /dev/null +++ b/src/main/java/task/Event.java @@ -0,0 +1,57 @@ +package task; + +import dateformat.DateFormat; + +/** + * Represents an Event task that inherits + * from Task. + */ +public class Event extends Task { + protected String description; + protected boolean isDone; + protected DateFormat date; + + /** + * Constructor for this Event task. + * + * @param description The Event task. + * @param date The date for the Event task. + */ + public Event(String description, String date) { + this.description = description; + this.date = new DateFormat(date); + } + + /** + * Changes the boolean isDone depending on whether the user + * wants to mark or unmark the Event task. + * + * @param bool The boolean for whether the Event task is marked + * or unmarked. + */ + public void isMark(boolean bool) { + this.isDone = bool; + } + + /** + * Returns a string representation of whether + * the Event task is done or undone. + * + * @return Returns a string representation of whether + * the Event task is done or undone. + */ + public String getStatusIcon() { + return (isDone ? "X" : " "); // mark done task with X + } + + /** + * Returns the string representation of the Event task. + * + * @return Returns the string representation of the Event task. + */ + @Override + public String toString() { + return "[E][" + this.getStatusIcon() + "] " + + this.description + " (at: " + this.date.toString() + ")"; + } +} diff --git a/src/main/java/task/Notes.java b/src/main/java/task/Notes.java new file mode 100644 index 0000000000..145691d4a5 --- /dev/null +++ b/src/main/java/task/Notes.java @@ -0,0 +1,46 @@ +package task; + +public class Notes extends Task { + protected String description; + protected final boolean IS_DONE = false; + + /** + * Constructor for this Notes task. + * + * @param description The Notes task. + */ + public Notes(String description) { + this.description = description; + } + + /** + * Changes the boolean isDone depending on whether the user + * wants to mark or unmark the Notes task. + * + * @param bool The boolean for whether the Notes task is marked + * or unmarked. + */ + public void isMark(boolean bool) {} + + /** + * Returns a string representation of whether + * the Notes task is done or undone. + * + * @return Returns a string representation of whether + * the Notes task is done or undone. + */ + public String getStatusIcon() { + return (IS_DONE ? "X" : " "); // mark done task with X + } + + /** + * Returns the string representation of the Notes task. + * + * @return Returns the string representation of the Notes task. + */ + @Override + public String toString() { + return "[N][" + this.getStatusIcon() + "] " + + this.description; + } +} diff --git a/src/main/java/task/NotesList.java b/src/main/java/task/NotesList.java new file mode 100644 index 0000000000..5f19e55ed8 --- /dev/null +++ b/src/main/java/task/NotesList.java @@ -0,0 +1,86 @@ +package task; + +import java.util.ArrayList; + +public class NotesList extends TaskList { + protected ArrayList notesList; + + /** + * Constructor for NotesList if there is a ArrayList. + * + * @param notes ArrayList of the tasks. + */ + public NotesList(ArrayList notes) { + this.notesList = notes; + } + + /** + * Constructor for NotesList if there is no ArrayList. + */ + public NotesList() { + this.notesList = new ArrayList<>(100); + } + + /** + * Returns the note at the index provided. + * + * @param index The index of the note to be returned. + * @return Returns the note at the index provided. + */ + public Task get(int index) { + return this.notesList.get(index); + } + + /** + * Adds the note to the notesList. + * + * @param note Note to be added to the notesList. + */ + public void add(Task note) { + this.notesList.add(note); + } + + /** + * Prints out all the tasks in the taskList. + */ + public void forEach() { + notesList.forEach(n -> System.out.println((notesList.indexOf(n) + 1) + "." + + n.toString())); + } + + /** + * Removes the note at the index provided. + * + * @param index The index of the note to be removed. + */ + public void remove(int index) { + notesList.remove(index); + } + + public boolean isEmpty() { + if (taskList.isEmpty()) { + return true; + } else { + return false; + } + } + + /** + * Changes the notesList to an ArrayList. + * + * @return An ArrayList containing all the notes in the + * notesList. + */ + public ArrayList toArray() { + return this.notesList; + } + + /** + * Returns the size of the notesList. + * + * @return Returns the size of the notesList. + */ + public int size() { + return this.notesList.size(); + } +} diff --git a/src/main/java/task/Task.java b/src/main/java/task/Task.java new file mode 100644 index 0000000000..2dc0f0f9c6 --- /dev/null +++ b/src/main/java/task/Task.java @@ -0,0 +1,59 @@ +package task; + +/** + * Represents all the tasks. + */ +public class Task { + protected String description; + protected boolean isDone; + protected String date; + + /** + * Changes the boolean isDone depending on whether the user + * wants to mark or unmark the task. + * + * @param bool The boolean for whether the task is marked + * or unmarked. + */ + public void isMark(boolean bool) { + this.isDone = bool; + } + + /** + * Returns the description of the task. + * + * @return Returns the description of the task. + */ + public String getDescription() { + return this.description; + } + + /** + * Sets the date for the task. + * + * @param str The date of the task. + */ + public void setDate(String str) { + this.date = str; + } + + /** + * Returns a string representation of whether + * the task is done or undone. + * + * @return Returns a string representation of whether + * the task is done or undone. + */ + public String getStatusIcon() { + return (isDone ? "X" : " "); // mark done task with X + } + + /** + * Returns the string representation of the task. + * + * @return Returns the string representation of the task. + */ + public String toString() { + return this.description; + } +} diff --git a/src/main/java/task/TaskList.java b/src/main/java/task/TaskList.java new file mode 100644 index 0000000000..81067e71f8 --- /dev/null +++ b/src/main/java/task/TaskList.java @@ -0,0 +1,92 @@ +package task; + +import exception.DukeException; + +import java.util.ArrayList; + +/** + * Represents the TaskList. + */ +public class TaskList { + protected Task task; + protected ArrayList taskList; + + /** + * Constructor for TaskList if there is a ArrayList. + * + * @param tasks ArrayList of the tasks. + */ + public TaskList(ArrayList tasks) { + this.taskList = tasks; + } + + /** + * Constructor for TaskList if there is no ArrayList. + */ + public TaskList() { + this.taskList = new ArrayList<>(100); + } + + /** + * Returns the task at the index provided. + * + * @param index The index of the task to be returned. + * @return Returns the task at the index provided. + */ + public Task get(int index) { + return this.taskList.get(index); + } + + /** + * Adds the task to the taskList. + * + * @param task Task to be added to the taskList. + */ + public void add(Task task) { + taskList.add(task); + } + + /** + * Prints out all the tasks in the taskList. + */ + public void forEach() { + taskList.forEach(n -> System.out.println((taskList.indexOf(n) + 1) + "." + + n.toString())); + } + + public boolean isEmpty() { + if (taskList.isEmpty()) { + return true; + } else { + return false; + } + } + + /** + * Removes the task at the index provided. + * + * @param index The index of the task to be removed. + */ + public void remove(int index) { + taskList.remove(index); + } + + /** + * Changes the taskList to an ArrayList. + * + * @return An ArrayList containing all the tasks in the + * taskList. + */ + public ArrayList toArray() { + return this.taskList; + } + + /** + * Returns the size of the taskList. + * + * @return Returns the size of the taskList. + */ + public int size() { + return this.taskList.size(); + } +} diff --git a/src/main/java/task/Todo.java b/src/main/java/task/Todo.java new file mode 100644 index 0000000000..d80cc3bf5b --- /dev/null +++ b/src/main/java/task/Todo.java @@ -0,0 +1,52 @@ +package task; + +/** + * Represents a Todo task that inherits + * from Task. + */ +public class Todo extends Task { + protected String description; + protected boolean isDone; + + /** + * Constructor for this Todo task. + * + * @param description The Todo task. + */ + public Todo(String description) { + this.description = description; + } + + /** + * Changes the boolean isDone depending on whether the user + * wants to mark or unmark the Todo task. + * + * @param bool The boolean for whether the Todo task is marked + * or unmarked. + */ + public void isMark(boolean bool) { + this.isDone = bool; + } + + /** + * Returns a string representation of whether + * the Todo task is done or undone. + * + * @return Returns a string representation of whether + * the Todo task is done or undone. + */ + public String getStatusIcon() { + return (isDone ? "X" : " "); // mark done task with X + } + + /** + * Returns the string representation of the Todo task. + * + * @return Returns the string representation of the Todo task. + */ + @Override + public String toString() { + return "[T][" + this.getStatusIcon() + "] " + + this.description; + } +} diff --git a/src/main/java/ui/Ui.java b/src/main/java/ui/Ui.java new file mode 100644 index 0000000000..4efe4ef403 --- /dev/null +++ b/src/main/java/ui/Ui.java @@ -0,0 +1,52 @@ +package ui; + +import exception.DukeException; + +import java.util.Scanner; + +public class Ui { + protected Scanner in; + protected String nextCommand; + + public Ui() { + System.out.println("Hello! I'm Duke.\nWhat can I do for you?\n"); + this.in = new Scanner(System.in); + } + + public void showWelcome() { + System.out.println("Hello! I'm Duke.Duke\nWhat can I do for you?\n"); + } + + public void showGoodbye() { + System.out.println("Bye. Hope to see you again soon!"); + } + + public String readCommand() { + return this.in.nextLine(); + } + + public void changeCommand() { + this.nextCommand = this.in.nextLine(); + } + + public void nextCommand() { + this.in.nextLine(); + } + + public void showLoadingError() throws DukeException { + try { + throw new DukeException("The file is empty!"); + } catch (DukeException e) { + System.out.println(e.toString()); + } + } + + public void showError(String error) { + System.out.println(error); + } + + public void showLine() { + System.out.println("---------------------------------"); + } + +} diff --git a/src/main/resources/images/DaDuke.png b/src/main/resources/images/DaDuke.png new file mode 100644 index 0000000000..91883d1f3d Binary files /dev/null and b/src/main/resources/images/DaDuke.png differ diff --git a/src/main/resources/images/DaUser.png b/src/main/resources/images/DaUser.png new file mode 100644 index 0000000000..6c48a5cf2f Binary files /dev/null and b/src/main/resources/images/DaUser.png differ diff --git a/src/main/resources/view/DialogBox.fxml b/src/main/resources/view/DialogBox.fxml new file mode 100644 index 0000000000..ede775d4f9 --- /dev/null +++ b/src/main/resources/view/DialogBox.fxml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml new file mode 100644 index 0000000000..6c4613298f --- /dev/null +++ b/src/main/resources/view/MainWindow.fxml @@ -0,0 +1,19 @@ + + + + + + + + + + + +