diff --git a/README.md b/README.md index 0dd8f7fb21..f742d8165d 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,17 @@ -# Duke project template +# Duke bot project template This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it. -## Setting up in Intellij +Setting up in Intellij Prerequisites: JDK 11, update Intellij to the most recent version. -1. Open Intellij (if you are not in the welcome screen, click `File` > `Close Project` to close the existing project first) -1. Open the project into Intellij as follows: - 1. Click `Open`. - 1. Select the project directory, and click `OK`. - 1. If there are any further prompts, accept the defaults. -1. Configure the project to use **JDK 11** (not other versions) as explained in [here](https://www.jetbrains.com/help/idea/sdk.html#set-up-jdk). -1. After that, locate the `src/main/java/Duke.java` file, right-click it, and choose `Run Duke.main()`. If the setup is correct, you should see something like the below: - ``` - Hello from - ____ _ - | _ \ _ _| | _____ - | | | | | | | |/ / _ \ - | |_| | |_| | < __/ - |____/ \__,_|_|\_\___| - ``` +Open Intellij (if you are not in the welcome screen, click File > Close Project to close the existing project dialog first) +Set up the correct JDK version, as follows: +Click Configure > Structure for New Projects and then Project Settings > Project > Project SDK +If JDK 11 is listed in the drop down, select it. If it is not, click New... and select the directory where you installed JDK 11 +Click OK +Import the project into Intellij as follows: +Click Open or Import. +Select the project directory, and click OK +If there are any further prompts, accept the defaults. diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000000..e098eaf471 --- /dev/null +++ b/build.gradle @@ -0,0 +1,56 @@ +plugins { + id 'java' + id 'application' + id 'checkstyle' + id "com.github.johnrengelman.shadow" version "6.0.0" +} + +group 'org.example' +version '1.0-SNAPSHOT' + +repositories { + mavenCentral() +} +sourceSets { + main { + java { + srcDirs = ['src'] + } + } + +} + + +dependencies { + compile 'junit:junit:4.12' +} +run { + enableAssertions = true +} +test { + useJUnitPlatform() +} + +dependencies { + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.4.0' + testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.4.0' + implementation 'org.junit.jupiter:junit-jupiter-api:5.5.1' + 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' +} +checkstyle { + toolVersion = '8.23' +} +mainClassName ="main.duke.gui.Launcher" \ No newline at end of file diff --git a/data/duke.txt b/data/duke.txt new file mode 100644 index 0000000000..1f5bf42c82 --- /dev/null +++ b/data/duke.txt @@ -0,0 +1,2 @@ +E~1~tosleep~2020-01-01 2401 +T~0~sample diff --git a/docs/Help.PNG b/docs/Help.PNG new file mode 100644 index 0000000000..ad521ae81e Binary files /dev/null and b/docs/Help.PNG differ diff --git a/docs/README.md b/docs/README.md index fd44069597..e8e0febc4b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,20 +1,126 @@ # User Guide +Duke bot is a chat bot designed to be used via a command line interface(CLI) with the benefits of using a graphical user interface(GUI). ## Features +>list : prints you the list of store tasks
+bye : terminates the program
+help : prints descriptions and samples of each feature
+todo [your task input] : adds a todo type task
+event [your task input] /at [YYYY-MM-DD hhmm]: adds an event type task
+deadline [your task input] /by [YYYY-MM-DD hhmm]: adds a deadline type task
+delete[number] : deletes the selected task
+done[number] : make the selected task done
+find [search string] : finds tasks that matches the string description
-### Feature 1 -Description of feature. +### `list` - prints you the list of store tasks + + +Example of usage: + +`list` + +Expected outcome: + +`These are the tasks in your list: + 1.[T] [X] sample` + +### `bye` - terminates the program + + +Example of usage: + +`bye` + +Expected outcome: + +`Goodbye!` + +### `help` - prints descriptions and samples of each feature + + +Example of usage: + +`help` + +Expected outcome: + +![Duke_Interface](Help.PNG) +### `todo` - adds a todo type task + + + +Example of usage: + +`todo sleep` + +Expected outcome: + +>Added the following task:
+> [T][X] sleep
+>You now have 1 tasks in your list + +### `event` - adds an event type task -## Usage -### `Keyword` - Describe action + +Example of usage: + +`event tosleep /at 2020-01-01 1111` + +Expected outcome: + +>Added the following task:
+> [E][X] tosleep 2020-01-01 1111 +>You now have 1 tasks in your list + +### `deadline` - adds a deadline type task + + +Example of usage: + +`deadline wakeup /by 2020-01-01 1111` + +Expected outcome: + +>Added the following task:
+> [D][X] wakeup 2020-01-01 1111 +>You now have 1 tasks in your list + +### `delete` - deletes the selected task + + +Example of usage: + +`delete 1` + +Expected outcome: + +>The following task has been removed:
+> [T][X] sample +>You now have 0 tasks in your list + +### `done` - make the selected task done Describe action and its outcome. Example of usage: -`keyword (optional arguments)` +`done 1` + +Expected outcome: + +>Following task has been marked done:
+>[T][O] sample + +### `find` - finds tasks that matches the string description + + +Example of usage: + +`find sample` Expected outcome: -`outcome` +>Here are the tasks you asked for:
+>1. [T][X] sample + diff --git a/docs/Ui.png.PNG b/docs/Ui.png.PNG new file mode 100644 index 0000000000..94b26bed59 Binary files /dev/null and b/docs/Ui.png.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/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000..62d4c05355 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..7dcdbdde07 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue Feb 23 16:47:37 SGT 2021 +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-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 100644 index 0000000000..fbd7c51583 --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + 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..5093609d51 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,104 @@ +@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/duke/Duke.java b/src/main/duke/Duke.java new file mode 100644 index 0000000000..a001afff6e --- /dev/null +++ b/src/main/duke/Duke.java @@ -0,0 +1,36 @@ +package main.duke; + +import main.duke.io.Storage; +import main.duke.io.Parser; +import main.duke.DukeList; +import main.duke.command.ICommand; +public class Duke { + private Storage storage; + private DukeList dukeList; + private Ui ui; + + /** + * Constructor for duke + * @param filePath contains file where the task list is being saved + */ + public Duke(String filePath){ + ui = new Ui(); + storage = new Storage(filePath); + dukeList = storage.load(); + } + + public String getReply (String input){ + Parser parser = new Parser(); + try{ + ICommand command = parser.parse(input); + String reply = command.run(ui,dukeList, storage); + storage.writeFile(); + assert(reply!=null); + return reply; + } + catch (DukeException e) + { + return e.getMessage(); + } + } +} diff --git a/src/main/duke/DukeException.java b/src/main/duke/DukeException.java new file mode 100644 index 0000000000..7bd578dfcc --- /dev/null +++ b/src/main/duke/DukeException.java @@ -0,0 +1,11 @@ +package main.duke; + +public class DukeException extends Exception{ + /** + * + * @param message Exception message being passed + */ + public DukeException (String message){ + super(message); + } +} \ No newline at end of file diff --git a/src/main/duke/DukeList.java b/src/main/duke/DukeList.java new file mode 100644 index 0000000000..b3db9f9c48 --- /dev/null +++ b/src/main/duke/DukeList.java @@ -0,0 +1,25 @@ +package main.duke; + +import java.util.ArrayList; +import java.util.List; +import main.duke.tasktype.Task; + +public class DukeList { + private List taskList; + + /** + * Constructor for Duke list + */ + public DukeList(){ + taskList = new ArrayList<>(); + } + + public DukeList(List taskList){ + this.taskList = taskList; + } + + public List getTaskList(){ + return taskList; + } + +} diff --git a/src/main/duke/Ui.java b/src/main/duke/Ui.java new file mode 100644 index 0000000000..15d237ba06 --- /dev/null +++ b/src/main/duke/Ui.java @@ -0,0 +1,126 @@ +package main.duke; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.function.Predicate; +import java.lang.StringBuffer; +import main.duke.tasktype.Task; + +public class Ui { + /** + * Done command in UI + * @param task the current task's status + * @return string including task name + */ + public String makeDone(String task){ + assert(task!= null); + return String.format("Following task has been marked done: \n" + task); + } + + /** + * Show the added task + * @param task Status of the task being operated on + * @param taskList Collection of current list + * @return string including the added task name and total task number + */ + public String showTaskAdded(String task , List taskList){ + assert(task != null && taskList != null); + return String.format( "Added the following task : \n" + + "%s\n" + "You now have %d tasks in your list.\n", task, taskList.size()); + } + + /** + * Show the deleted task + * @param task Status of the task being operated on + * @param taskList Collection of current list + * @return string including the deleted task name and total task number + */ + public String showTaskDeleted(String task , List taskList){ + assert(task != null && taskList != null); + return String.format("The following task has been removed:\n " + + "%s\n" + " You now have %d tasks in your list.\n", task, taskList.size()); + } + + /** + * + * @param taskList Collection of current list + * @return All of tasks in the tasklist + */ + public String showList(List taskList){ + assert(taskList != null); + int counter = 1; + StringBuffer showList = new StringBuffer(); + showList.append(" These are the tasks in your list:\n"); + for (Task task : taskList){ + showList.append(" " + counter + ". " + task.getStatus() + "\n"); + counter++; + } + return showList.toString(); + } + + /** + * Goodbye command in UI + * + */ + public String sayGoodbye(){ + return "Goodbye!"; + } + + /** + * Help command in UI + * + */ + public String giveHelp(){ + String helpString = "Try one of these:\n" + + "list : prints you the list of store tasks\n" + + "bye : terminates the program\n" + + "todo [your task input] : adds a todo type task\n" + + "event [your task input] /at [YYYY-MM-DD hhmm]: adds an event type task\n" + + "deadline [your task input] /by [YYYY-MM-DD hhmm]: adds a deadline type task\n" + + "delete[number] : deletes the selected task\n" + + "done[number] : mark the selected task as done(notation will be 0 for done and X for not done)\n" + + "find [search string] : finds tasks that matches the string description\n" + + "\nExamples\n" + + "todo sleep : adds a todo type task of description sleep\n" + + "event toSleep /at 2020-01-01 0000 : adds an event type task of description toSleep " + + "with dateTime 2020-01-01 0000\n" + + "deadline wakeup /by 2020-01-01 0001 : adds a deadline type task of description wakeup " + + "with dateTime 2020-01-01 0001\n" + + "delete[1] : deletes the task with index 1 (will only work if the task with your index exists\n" + + "done[1] : marks the task with index 1 to done\n" + + "find[sleep] : finds task descriptions that starts with sleep\n" + + "[IMPORTANT] Note that the number inputted for done and delete should be equals to or " + + "less than the total number of tasks in your list!"; + return helpString; + } + + /** + * Show list of tasks with given keyword + * @param input Keyword used for find command + * @param taskList Collection of current list + * @throws DukeException Throws exception if search string is empty + */ + public String showTasks(String input, List taskList) throws DukeException{ + assert (input != null && taskList != null); + if(input.length() <= "find ".length()){ + throw new DukeException("Please add what you want to find."); + } + String find = input.substring("find ".length()); + + if (find.trim().equals("")){ + throw new DukeException("Search string is empty"); + } + Predicate stringPredicate = x -> x.contains(find); + StringBuffer tasks = new StringBuffer(); + tasks.append("Here are the tasks you asked for: \n"); + int counter =1; + for(Task t : taskList){ + if(t.getName() != null && stringPredicate.test(t.getName())){ + tasks.append(counter + ". " + t.getStatus() + "\n"); + counter++; + } + } + return tasks.toString(); + } + +} diff --git a/src/main/duke/command/CBye.java b/src/main/duke/command/CBye.java new file mode 100644 index 0000000000..5f07b75cd6 --- /dev/null +++ b/src/main/duke/command/CBye.java @@ -0,0 +1,27 @@ +package main.duke.command; + +import main.duke.DukeList; +import main.duke.Ui; +import main.duke.io.Storage; + +public class CBye implements ICommand { + /** + * Check if it is the bye command + * @return true as it is the bye command + */ + @Override + public boolean isBye() { + return true; + } + + /** + * + * @param ui UI object that deal with the program output + * @param dukeList Collection of tasks in list form + * @param storage Storage object that deal with the file system + */ + @Override + public String run(Ui ui, DukeList dukeList, Storage storage) { + return ui.sayGoodbye(); + } +} diff --git a/src/main/duke/command/CDeadline.java b/src/main/duke/command/CDeadline.java new file mode 100644 index 0000000000..f64c845b8a --- /dev/null +++ b/src/main/duke/command/CDeadline.java @@ -0,0 +1,44 @@ +package main.duke.command; +import java.util.List; +import main.duke.DukeException; +import main.duke.DukeList; +import main.duke.Ui; +import main.duke.io.Storage; +import main.duke.tasktype.Task; +import main.duke.tasktype.Deadline; +public class CDeadline implements ICommand { + private String input; + public CDeadline(String command){ + this.input = command; + } + + /** + * Check if it is the bye command + * @return false as it is not the bye command + */ + @Override + public boolean isBye() { + return false; + } + /** + * + * @param ui UI object that deal with the program output + * @param dukeList Collection of tasks in list form + * @param storage Storage object that deal with the file system + */ + @Override + public String run(Ui ui, DukeList dukeList, Storage storage) throws DukeException{ + List taskList = dukeList.getTaskList(); + int endPoint = input.indexOf("/") - 1; + String text = input.substring("deadline".length() + 1, endPoint); + String dateTime = input.substring(endPoint + 5); + Task deadline = new Deadline(text, dateTime); + taskList.add(deadline); + + storage.addText(deadline.convertToFile()); + return ui.showTaskAdded(deadline.getStatus(), taskList); + + } + + +} \ No newline at end of file diff --git a/src/main/duke/command/CDelete.java b/src/main/duke/command/CDelete.java new file mode 100644 index 0000000000..a1bc1ad64e --- /dev/null +++ b/src/main/duke/command/CDelete.java @@ -0,0 +1,43 @@ +package main.duke.command; + +import main.duke.DukeException; +import main.duke.DukeList; +import main.duke.Ui; +import main.duke.io.Storage; +import main.duke.tasktype.Task; +import java.util.List; + +public class CDelete implements ICommand { + private String input; + public CDelete(String command){ + this.input = command; + } + /** + * Check if it is the bye command + * @return false as it is not the bye command + */ + @Override + public boolean isBye() { + return false; + } + /** + * + * @param ui UI object that deal with the program output + * @param dukeList Collection of tasks in list form + * @param storage Storage object that deal with the file system + */ + @Override + public String run(Ui ui, DukeList dukeList, Storage storage) throws DukeException{ + List taskList = dukeList.getTaskList(); + int index = Integer.parseInt(input.substring(7)) -1; + if(index+1 == 0 || index>= taskList.size() +1){ + throw new DukeException("This task does not exist"); + } + Task removedTask = taskList.remove(index); + storage.removeTask(removedTask.convertToFile()); + return ui.showTaskDeleted(removedTask.getStatus(), taskList); + + } + + +} diff --git a/src/main/duke/command/CDone.java b/src/main/duke/command/CDone.java new file mode 100644 index 0000000000..c4990b146e --- /dev/null +++ b/src/main/duke/command/CDone.java @@ -0,0 +1,49 @@ +package main.duke.command; +import java.util.List; +import main.duke.DukeException; +import main.duke.DukeList; +import main.duke.Ui; +import main.duke.io.Storage; +import main.duke.tasktype.Task; +public class CDone implements ICommand{ + private String input; + public CDone(String command){ + this.input = command; + } + /** + * Check if it is the bye command + * @return false as it is not the bye command + */ + + @Override + public boolean isBye() { + return false; + } + /** + * + * @param ui UI object that deal with the program output + * @param dukeList Collection of tasks in list form + * @param storage Storage object that deal with the file system + */ + @Override + public String run(Ui ui, DukeList dukeList, Storage storage) throws DukeException { + List taskList = dukeList.getTaskList(); + int index = Integer.parseInt(input.substring(5))-1; + Task task = taskList.get(index); + if(task == null){ + throw new DukeException("No such task"); + } + String oldLine = task.convertToFile(); + task.setDone(); + String newLine = task.convertToFile(); + try{ + storage.changeText(oldLine,newLine); + } + catch (StringIndexOutOfBoundsException e){ + System.out.println("Line to replace cannot be found" + e.getMessage()); + }catch (NumberFormatException e){ + System.out.println("You have an illegal character" + e.getMessage()); + } + return ui.makeDone(task.getStatus()); + } +} diff --git a/src/main/duke/command/CEvent.java b/src/main/duke/command/CEvent.java new file mode 100644 index 0000000000..ba7a19b6f4 --- /dev/null +++ b/src/main/duke/command/CEvent.java @@ -0,0 +1,42 @@ +package main.duke.command; + +import main.duke.DukeException; +import main.duke.DukeList; +import main.duke.Ui; +import main.duke.io.Storage; +import main.duke.tasktype.Event; +import main.duke.tasktype.Task; +import java.util.List; + +public class CEvent implements ICommand { + private String input; + public CEvent(String command){ + this.input = command; + } + /** + * Check if it is the bye command + * @return false as it is not the bye command + */ + @Override + public boolean isBye() { + return false; + } + /** + * + * @param ui UI object that deal with the program output + * @param dukeList Collection of tasks in list form + * @param storage Storage object that deal with the file system + */ + @Override + public String run(Ui ui, DukeList dukeList, Storage storage) throws DukeException { + List taskList = dukeList.getTaskList(); + int endPoint = input.indexOf("/") - 1; + String text = input.substring("event".length() + 1, endPoint); + String dateTime = input.substring(endPoint + 5); + Task event = new Event(text, dateTime); + taskList.add(event); + + storage.addText(event.convertToFile()); + return ui.showTaskAdded(event.getStatus(), taskList); + } +} diff --git a/src/main/duke/command/CFind.java b/src/main/duke/command/CFind.java new file mode 100644 index 0000000000..a67021066f --- /dev/null +++ b/src/main/duke/command/CFind.java @@ -0,0 +1,35 @@ +package main.duke.command; + +import main.duke.DukeException; +import main.duke.DukeList; +import main.duke.Ui; +import main.duke.io.Storage; +import main.duke.tasktype.Task; +import java.util.List; + +public class CFind implements ICommand{ + private String input; + public CFind(String command){ + this.input = command; + } + /** + * Check if it is the bye command + * @return false as it is not the bye command + */ + + @Override + public boolean isBye() { + return false; + } + /** + * + * @param ui UI object that deal with the program output + * @param dukeList Collection of tasks in list form + * @param storage Storage object that deal with the file system + */ + @Override + public String run(Ui ui, DukeList dukeList, Storage storage) throws DukeException { + List taskList = dukeList.getTaskList(); + return ui.showTasks(input,taskList); + } +} diff --git a/src/main/duke/command/CHelp.java b/src/main/duke/command/CHelp.java new file mode 100644 index 0000000000..52a581f88f --- /dev/null +++ b/src/main/duke/command/CHelp.java @@ -0,0 +1,25 @@ +package main.duke.command; +import main.duke.DukeList; +import main.duke.Ui; +import main.duke.io.Storage; +public class CHelp implements ICommand{ + /** + * Check if it is the bye command + * @return false as it is not the bye command + */ + @Override + public boolean isBye() { + return false; + } + + /** + * + * @param ui UI object that deal with the program output + * @param dukeList Collection of tasks in list form + * @param storage Storage object that deal with the file system + */ + @Override + public String run(Ui ui, DukeList dukeList, Storage storage) { + return ui.giveHelp(); + } +} diff --git a/src/main/duke/command/CList.java b/src/main/duke/command/CList.java new file mode 100644 index 0000000000..57c1a40176 --- /dev/null +++ b/src/main/duke/command/CList.java @@ -0,0 +1,30 @@ +package main.duke.command; +import main.duke.DukeException; +import main.duke.DukeList; +import main.duke.Ui; +import main.duke.io.Storage; +import main.duke.tasktype.Task; +import java.util.List; + +public class CList implements ICommand { + /** + * Check if it is the bye command + * @return false as it is not the bye command + */ + @Override + public boolean isBye() { + return false; + } + + /** + * + * @param ui UI object that deal with the program output + * @param dukeList Collection of tasks in list form + * @param storage Storage object that deal with the file system + */ + @Override + public String run(Ui ui, DukeList dukeList, Storage storage) { + List taskList = dukeList.getTaskList(); + return ui.showList(taskList); + } +} diff --git a/src/main/duke/command/CTodo.java b/src/main/duke/command/CTodo.java new file mode 100644 index 0000000000..1c17daa864 --- /dev/null +++ b/src/main/duke/command/CTodo.java @@ -0,0 +1,39 @@ +package main.duke.command; +import main.duke.DukeException; +import main.duke.DukeList; +import main.duke.Ui; +import main.duke.io.Storage; +import main.duke.tasktype.Todo; +import main.duke.tasktype.Task; +import java.util.List; + +public class CTodo implements ICommand { + private String input; + public CTodo(String command){ + this.input = command; + } + /** + * Check if it is the bye command + * @return false as it is not the bye command + */ + + @Override + public boolean isBye() { + return false; + } + /** + * + * @param ui UI object that deal with the program output + * @param dukeList Collection of tasks in list form + * @param storage Storage object that deal with the file system + */ + @Override + public String run(Ui ui, DukeList dukeList, Storage storage) throws DukeException { + List taskList = dukeList.getTaskList(); + String name = input.substring(4); + Task todo = new Todo(name.trim()); + taskList.add(todo); + storage.addText(todo.convertToFile()); + return ui.showTaskAdded(todo.getStatus(), taskList); + } +} diff --git a/src/main/duke/command/ICommand.java b/src/main/duke/command/ICommand.java new file mode 100644 index 0000000000..045d08ff1b --- /dev/null +++ b/src/main/duke/command/ICommand.java @@ -0,0 +1,9 @@ +package main.duke.command; +import main.duke.DukeList; +import main.duke.Ui; +import main.duke.DukeException; +import main.duke.io.Storage; +public interface ICommand { + public boolean isBye(); + public String run(Ui ui, DukeList dukeList, Storage storage) throws DukeException; +} diff --git a/src/main/duke/gui/DialogBox.java b/src/main/duke/gui/DialogBox.java new file mode 100644 index 0000000000..101cc11764 --- /dev/null +++ b/src/main/duke/gui/DialogBox.java @@ -0,0 +1,54 @@ +package main.duke.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; +import javafx.scene.text.Text; + +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); + } + + 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 getBotDialog(String text, Image img) { + var db = new DialogBox(text, img); + db.flip(); + return db; + } +} diff --git a/src/main/duke/gui/Launcher.java b/src/main/duke/gui/Launcher.java new file mode 100644 index 0000000000..d435b2040c --- /dev/null +++ b/src/main/duke/gui/Launcher.java @@ -0,0 +1,14 @@ +package main.duke.gui; + +import javafx.application.Application; + +public class Launcher { + /** + * Launch javafx application + * @param args Args to initialize main method + */ + public static void main(String[] args){ + + Application.launch(Main.class,args); + } +} \ No newline at end of file diff --git a/src/main/duke/gui/Main.java b/src/main/duke/gui/Main.java new file mode 100644 index 0000000000..1faf764124 --- /dev/null +++ b/src/main/duke/gui/Main.java @@ -0,0 +1,31 @@ +package main.duke.gui; + +import main.duke.Duke; +import javafx.application.Application; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.stage.Stage; +import javafx.scene.layout.AnchorPane; +import java.io.IOException; + +import java.io.IOException; + +public class Main extends Application { + + private Duke duke = new Duke("data/duke.txt"); + @Override + public void start(Stage stage){ + try { + FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("/view/MainWindow.fxml")); + AnchorPane anchorPane = fxmlLoader.load(); + Scene scene = new Scene(anchorPane); + stage.setScene(scene); + stage.setTitle("Duke bot"); + fxmlLoader.getController().makeDuke(duke); + stage.show(); + } + catch (IOException e){ + e.printStackTrace(); + } + } +} diff --git a/src/main/duke/gui/MainWindow.java b/src/main/duke/gui/MainWindow.java new file mode 100644 index 0000000000..d9c9ef7801 --- /dev/null +++ b/src/main/duke/gui/MainWindow.java @@ -0,0 +1,74 @@ +package main.duke.gui; + +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 java.io.IOException; +import java.util.concurrent.CompletableFuture; + +import main.duke.Duke; + +/** + * Controller of the MainWindow + */ +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/User.png")); + private Image botImage = new Image(this.getClass().getResourceAsStream("/images/Bot.png")); + private final String startMessage = "Hello, I am duke bot.\n" + + "If you require any assistance with what I accept use my command help\n"; + + public MainWindow(){ } + + /** + * Initialize the MainWindow with a startMessage + */ + @FXML + public void initialize(){ + this.scrollPane.vvalueProperty().bind(this.dialogContainer.heightProperty()); + dialogContainer.getChildren().add(DialogBox.getUserDialog(startMessage,botImage)); + } + public void makeDuke(Duke d){ + duke = d; + } + + /** + * Makes two dialogBoxes, one which echos the user input and the other contains the reply. + * Both are appended to the dialog container and cleared after. + */ + @FXML + private void handleUserInput() { + String input = userInput.getText().trim(); + String response = duke.getReply(input); + dialogContainer.getChildren().addAll(DialogBox.getUserDialog(input, userImage), + DialogBox.getBotDialog(response, botImage)); + userInput.clear(); + CompletableFuture.runAsync(() -> { + try{ + if(input.equals("bye")){ + Thread.sleep(3000); + System.exit(0); + } + } + catch (InterruptedException e){ + Thread.currentThread().interrupt(); + System.exit(1); + } + } + ); + assert (userInput.getText().equals("")); + } +} diff --git a/src/main/duke/io/Parser.java b/src/main/duke/io/Parser.java new file mode 100644 index 0000000000..2dcc7a9b2f --- /dev/null +++ b/src/main/duke/io/Parser.java @@ -0,0 +1,91 @@ +package main.duke.io; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + +import main.duke.command.*; +import main.duke.DukeException; + +public class Parser { + /** + * + * @param input the whole user console input command + * @return Command for execution + * @throws DukeException thrown when an invalid message is inputted + */ + public ICommand parse(String input) throws DukeException{ + String[] splitString = input.split(" "); + assert (splitString.length > 0); + String first = splitString[0]; + ICommand iCommand; + switch (first){ + case"bye": + checkLength(1,splitString); + iCommand = new CBye(); + break; + case"done": + checkLength(2,splitString); + iCommand = new CDone(input); + break; + case"delete": + checkLength(2,splitString); + iCommand = new CDelete(input); + break; + case"deadline": + checkMessage(first,input); + checkDateTime(splitString); + checkBreakExist("/by", input, "deadline"); + iCommand = new CDeadline(input); + break; + case"find": + checkMessage(first, input); + iCommand = new CFind(input); + break; + case"event": + checkMessage(first, input); + checkDateTime(splitString); + checkBreakExist("/at", input, "event"); + iCommand = new CEvent(input); + break; + case"list": + checkLength(1, splitString); + iCommand = new CList(); + break; + case"todo": + checkMessage(first, input); + iCommand = new CTodo(input); + break; + case"help": + checkLength(1,splitString); + iCommand = new CHelp(); + break; + default: + throw new DukeException("The request is not valid"); + } + return iCommand; + } + public void checkLength(int length, String[] input) throws DukeException{ + if(length != input.length){ + throw new DukeException("Your message is not the right length"); + } + } + public void checkMessage(String command, String wholeInput) throws DukeException{ + if(command.length() + 1 >= wholeInput.length()){ + throw new DukeException(command + " cannot be empty!"); + } + } + public void checkBreakExist(String type, String wholeInput, String command) throws DukeException{ + if(!wholeInput.contains(type)){ + throw new DukeException(command + " is not complete. You are missing " + type); + } + } + public void checkDateTime(String[] command) throws DukeException { + String dateTime = command[command.length - 2] + " " + command[command.length -1]; + try{ + LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern("yyyy-MM-dd kkmm")); + } + catch (DateTimeParseException e){ + throw new DukeException("You have the wrong date time format. I require YYYY-MM-DD 0000"); + } + } +} diff --git a/src/main/duke/io/Storage.java b/src/main/duke/io/Storage.java new file mode 100644 index 0000000000..0151256678 --- /dev/null +++ b/src/main/duke/io/Storage.java @@ -0,0 +1,161 @@ +package main.duke.io; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.DataInputStream; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import main.duke.DukeException; +import main.duke.tasktype.Task; +import main.duke.tasktype.Event; +import main.duke.tasktype.Deadline; +import main.duke.tasktype.Todo; +import java.util.List; + +import main.duke.DukeList; + +public class Storage { + private StringBuffer stringBufferOfTasks = new StringBuffer(); + private String filename; + + /** + * Constructor for the Storage Object + * @param filename path of the file being accessed + */ + public Storage(String filename) { + this.filename = filename; + getTaskListInFile(getDirectory()); + } + + + private void getTaskListInFile(String current) { + String[] parents = filename.split("/"); + String parent = parents[0]; + Path directPath = Paths.get(current, parent); + Path filePath = Paths.get(current, filename); + boolean directoryExist = Files.exists(directPath); + boolean fileExist = Files.exists(filePath); + try { + if (!directoryExist) { + Files.createDirectories(directPath); + } + if (!fileExist) { + Files.createFile(filePath); + } + } catch (IOException e) { + System.out.println(e.getMessage()); + } + } + + /** + * + * @return the current directory + */ + private String getDirectory() { + return System.getProperty("user.dir"); + } + + public void removeTask(String toRemove) { + String newLine = System.getProperty("line.separator"); + toRemove = toRemove + newLine; + setReplacing(toRemove, "", stringBufferOfTasks); + } + + public void setReplacing(String toReplace, String replacement, StringBuffer stringBuffer) throws StringIndexOutOfBoundsException { + int start = stringBuffer.indexOf(toReplace); + int end = start + toReplace.length(); + stringBuffer.replace(start, end, replacement); + } + + public void changeText(String toChange, String changeTo) { + setReplacing(toChange, changeTo, stringBufferOfTasks); + } + + public void addText(String toAdd) { + String newLine = System.getProperty("line.separator"); + toAdd = toAdd + newLine; + stringBufferOfTasks.append(toAdd); + } + + /** + * Creates task objects based on the file information + * @return List of task objects + */ + public DukeList load() { + DukeList dukeList = new DukeList(); + stringBufferOfTasks = new StringBuffer(); + try { + BufferedReader reader = new BufferedReader(new InputStreamReader(new DataInputStream( + new FileInputStream(this.filename)))); + String line = reader.readLine(); + while (line != null) { + runCommands(line,dukeList); + line = reader.readLine(); + } + reader.close(); + + } catch (IOException e) { + System.out.println(filename + " could not be opened" + e.getMessage()); + } catch (ArrayIndexOutOfBoundsException e){ + System.out.println((e.getMessage())); + } + return dukeList; + } + public void convertFromFile(String[] input, DukeList dukeList){ + List taskList = dukeList.getTaskList(); + String type = input[0]; + int done = Integer.parseInt(input[1]); + String name = input[2]; + int counter = dukeList.getTaskList().size(); + switch(type) { + case ("E"): + String dateTime = input[3]; + Task E = new Event(name, dateTime); + if(done == 1){ + E.setDone(); + } + taskList.add(counter, E); + break; + case("D"): + dateTime = input[3]; + Task D = new Deadline(name, dateTime); + if(done == 1){ + D.setDone(); + } + taskList.add(counter, D); + break; + case("T"): + Task T = new Todo(name); + if(done == 1){ + T.setDone(); + } + taskList.add(counter, T); + break; + default: + break; + } + } + public void runCommands(String line, DukeList dukeList){ + String[] input = line.split("~"); + String type = input[0]; + convertFromFile(input,dukeList); + stringBufferOfTasks.append(input).append("\r\n"); + } + + public void writeFile(){ + try{ + BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(filename)); + bufferedWriter.write(stringBufferOfTasks.toString()); + bufferedWriter.close(); + } + catch(Exception e){ + System.out.println("Error when writing to File: " + e.getMessage()); + } + } +} diff --git a/src/main/duke/tasktype/Deadline.java b/src/main/duke/tasktype/Deadline.java new file mode 100644 index 0000000000..b7c8d5e445 --- /dev/null +++ b/src/main/duke/tasktype/Deadline.java @@ -0,0 +1,22 @@ +package main.duke.tasktype; + +public class Deadline extends Task { + /** + * Constructor for basic deadline + * @param name task information + */ + public Deadline (String name){ + super(name); + this.type = "D"; + } + + /** + * Constructor for deadline with date time format + * @param name task information + * @param dateTime Date time format + */ + public Deadline(String name, String dateTime){ + super(name,dateTime); + this.type = "D"; + } +} diff --git a/src/main/duke/tasktype/Event.java b/src/main/duke/tasktype/Event.java new file mode 100644 index 0000000000..2bbc5fcd78 --- /dev/null +++ b/src/main/duke/tasktype/Event.java @@ -0,0 +1,22 @@ +package main.duke.tasktype; + +public class Event extends Task { + /** + * Constructor for basic event + * @param name task information + */ + public Event(String name){ + super(name); + this.type = "E"; + } + + /** + * Constructor for event with date time format + * @param name task information + * @param dateTime Date time format + */ + public Event(String name, String dateTime){ + super(name, dateTime); + this.type = "E"; + } +} diff --git a/src/main/duke/tasktype/Task.java b/src/main/duke/tasktype/Task.java new file mode 100644 index 0000000000..c2ab565ec5 --- /dev/null +++ b/src/main/duke/tasktype/Task.java @@ -0,0 +1,81 @@ +package main.duke.tasktype; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class Task { + protected String name; + protected boolean isDone; + protected String type; + protected LocalDateTime due; + + /** + * Constructor for task + * @param name task information + */ + public Task(String name){ + this.name = name; + this.isDone = false; + } + + /** + * Constructor for task with date time format + * @param name task information + * @param dateTime Date time format + */ + public Task(String name, String dateTime){ + this.name = name; + this.isDone = false; + this.due = LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern("yyyy-MM-dd kkmm")); + } + + /** + * Set task as done + */ + public void setDone(){ + isDone = true; + } + + /** + * @return Get task information + */ + public String getName(){ + return name; + } + + /** + * @return Get the status of task in symbol form + */ + public String getStatusIcon(){ + return (isDone ? "O" : "X"); + } + + /** + * Get the current status of task + * @return current status of task + */ + public String getStatus(){ + if(due == null){ + return " [" + type + "] " + " [" + getStatusIcon() + "] " + getName(); + } + else{ + return " [" + type + "] " + " [" + getStatusIcon() + "] " + getName() + " " + + due.format(DateTimeFormatter.ofPattern("yyyy-MM-dd kkmm")); + } + } + public LocalDateTime getDue(){ + return due; + } + + /** + * Changes task information to the suitable format for a file + * @return String containing the suitable format + */ + public String convertToFile(){ + if(due==null){ + return String.format("%s~%s~%s", type, isDone ? 1:0, getName()); + } + return String.format("%s~%s~%s~%s", type, isDone ? 1:0, getName(), + due.format(DateTimeFormatter.ofPattern("yyyy-MM-dd kkmm"))); + } +} diff --git a/src/main/duke/tasktype/Todo.java b/src/main/duke/tasktype/Todo.java new file mode 100644 index 0000000000..8197282b71 --- /dev/null +++ b/src/main/duke/tasktype/Todo.java @@ -0,0 +1,12 @@ +package main.duke.tasktype; + +public class Todo extends Task { + /** + * Constructor for Todo + * @param name task information + */ + public Todo (String name){ + super(name); + this.type = "T"; + } +} 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/resources/images/Bot.png b/src/main/resources/images/Bot.png new file mode 100644 index 0000000000..03b1d48bfa Binary files /dev/null and b/src/main/resources/images/Bot.png differ diff --git a/src/main/resources/images/User.png b/src/main/resources/images/User.png new file mode 100644 index 0000000000..f6ac09cc2d Binary files /dev/null and b/src/main/resources/images/User.png differ diff --git a/src/main/resources/view/DialogBox.fxml b/src/main/resources/view/DialogBox.fxml new file mode 100644 index 0000000000..0ef8333993 --- /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..be1a1d49d5 --- /dev/null +++ b/src/main/resources/view/MainWindow.fxml @@ -0,0 +1,19 @@ + + + + + + + + + + + +