diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000000..6aed9daea2 --- /dev/null +++ b/build.gradle @@ -0,0 +1,63 @@ +plugins { + id 'java' + id 'application' + id 'checkstyle' + id 'com.github.johnrengelman.shadow' version '5.1.0' + id 'org.openjfx.javafxplugin' version '0.0.10' +} + +javafx { + version = "11.0.2" + modules = [ 'javafx.controls' ] +} + +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' +} +test { + useJUnitPlatform() + + testLogging { + events "passed", "skipped", "failed" + + showExceptions true + exceptionFormat "full" + showCauses true + showStackTraces true + showStandardStreams = false + } +} + +application { + mainClassName = "seedu.duke.Duke" +} + +shadowJar { + archiveBaseName = "duke" + archiveClassifier = null +} + +checkstyle { + toolVersion = '8.29' +} + +run{ + standardInput = System.in +} diff --git a/data/duke.txt b/data/duke.txt new file mode 100644 index 0000000000..76f8f0695c --- /dev/null +++ b/data/duke.txt @@ -0,0 +1,11 @@ +D | 1 | clean | 20-02-2022 1500 | 21-02-2022 1500 +T | 0 | read | 22-02-2022 1600 +T | 1 | run errands | 16-02-2022 1800 +T | 0 | run somewhere | 24-02-2022 1600 +E | 0 | party | 10-01-2022 1200 | 10-01-2022 1200 | 10-01-2022 1400 +E | 0 | congress | 23-01-2022 1200 | 10-01-2022 1200 | 10-01-2022 1400 +E | 0 | war | 26-02-2022 1200 | 10-01-2022 1200 | 10-01-2022 1400 +D | 1 | homework | 19-02-2022 1500 | 21-02-2022 1500 +D | 1 | App Project | 21-02-2022 1200 | 21-02-2022 1500 +D | 1 | Web project | 25-02-2022 1500 | 26-02-2022 1500 +T | 0 | call | 03-04-2022 1552 diff --git a/docs/README.md b/docs/README.md index 8077118ebe..4d06fda18c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,29 +1,135 @@ -# User Guide +# User Guide for Duke ## Features -### Feature-ABC +### List - `list` -Description of the feature. +Lists all available tasks saved. -### Feature-XYZ +**Usage**: -Description of the feature. +`list` -## Usage +``` +returns a list of all tasks. eg + +List: +1. T | [X] Run + +``` -### `Keyword` - Describe action +### Tasks -Describe the action and its outcome. +Duke accepts various types of tasks! These include -Example of usage: +#### Todo - `todo` +* A Todo task is a task with no given date or deadline...its just something to do. -`keyword (optional arguments)` +**Usage**: -Expected outcome: +`todo [task description]` -Description of the outcome. +``` +creates a todo task. Eg: +T | [ ] Run ``` -expected output + +#### Event - `event` +* Event tasks are tasks that are associated with a specific day or time. + +**Usage**: + +`event [task description] [/at] [dd-MM-yyyy HHmm]_to_[dd-MM-yyyy HHmm]` + +``` +creates an event task. Eg: +E | [ ] Run (at: 31-01-2022 1800 to 31-01-2022 21000) + +``` + +#### Deadline - `deadline` +* Deadline tasks are tasks that need to be completed by a certain date or time. + +**Usage**: + +`deadline [task description] [/by] [dd-MM-yyyy HHmm]` + +``` +creates a deadline task. Eg: +D | [ ] Run (by: 24-04-2022 1400) + +``` + + +### Mark and Unmark - `mark` and `unmark` + +Mark and Unmark allows users to moniter task completeness. + +**Usage**: + +`mark [task index]` + +``` +Marks a task as complete. Eg: +T | [X] Run + +``` + +`unmark [task index]` + +``` +Marks a task as incomplete. Eg: +T | [ ] Run + +``` + +### Find - `find` + +Find allows users to narrow the search for a task by their specified keyword. + +**Usage**: + +`find [task description]` + +``` +Finds tasks containing the specified task description. Eg: +'find run' returns + +List: +1. T | [X] run +2. T | [ ] run errands +3. T | [ ] run away + +``` + +### Statistics - `stats` + +Statistics allow users to see their completed tasks over a given period of time. + +`stats [day index]` + +``` +Lists tasks completed [day index] days before the current day. Eg: +'stats 7' returns all the tasks completed in the past 7 days. + +List: +1. T | [X] run + +``` + +### Delete - `delete` + +Delete allows users to delete tasks. + +`delete [task index]` + +``` +Deletes selected task index. Eg: +'delete 1' deletes the first task + +List: +1. T | [ ] run errands +2. T | [ ] run away + ``` diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 0000000000..3397c9a492 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-architect \ 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..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/Duke/DeadlineTask.java b/src/main/java/Duke/DeadlineTask.java new file mode 100644 index 0000000000..19dbea5293 --- /dev/null +++ b/src/main/java/Duke/DeadlineTask.java @@ -0,0 +1,32 @@ +package Duke; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +class DeadlineTask extends Task{ + LocalDateTime byDate; + private final static DateTimeFormatter fm = DateTimeFormatter.ofPattern("MMM dd yyyy hh:mma"); + public DeadlineTask(String description, boolean isCompleted, LocalDateTime byDate){ + super(description, isCompleted); + this.byDate = byDate; + } + + public DeadlineTask(String description, boolean isCompleted, + LocalDateTime createdDate, LocalDateTime byDate){ + super(description, isCompleted, createdDate); + this.byDate = byDate; + } + + @Override + public String toString() { + return "[D]"+super.toString() + "(by: " + byDate.format(fm) + ")"; + } + + /** + * Generates Deadline string to be stored in the file. + */ + @Override + public String toFileString(){ + return "D" + super.toFileString() + " | " + byDate.format(Parser.dtFormat); + } +} \ No newline at end of file diff --git a/src/main/java/Duke/DialogBox.java b/src/main/java/Duke/DialogBox.java new file mode 100644 index 0000000000..f72f29165a --- /dev/null +++ b/src/main/java/Duke/DialogBox.java @@ -0,0 +1,62 @@ +package Duke; + +import java.io.IOException; + import java.util.Collections; + + import javafx.collections.FXCollections; + import javafx.collections.ObservableList; + import javafx.fxml.FXML; + import javafx.fxml.FXMLLoader; + import javafx.geometry.Pos; + import javafx.scene.Node; + import javafx.scene.control.Label; + import javafx.scene.image.Image; + import javafx.scene.image.ImageView; + import javafx.scene.layout.HBox; + +/** + * An example of a custom control using FXML. + * This control represents a dialog box consisting of an ImageView to represent the speaker's face and a label + * containing text from the speaker. + */ +public class DialogBox extends HBox { + @FXML + private Label dialog; + @FXML + private ImageView displayPicture; + + + private DialogBox(String text, Image img) { + try { + FXMLLoader fxmlLoader = new FXMLLoader(MainWindow.class.getResource("/view/DialogBox.fxml")); + fxmlLoader.setController(this); + fxmlLoader.setRoot(this); + fxmlLoader.load(); + } catch (IOException e) { + e.printStackTrace(); + } + + dialog.setText(text); + 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; + } +} diff --git a/src/main/java/Duke/Duke.java b/src/main/java/Duke/Duke.java new file mode 100644 index 0000000000..1c41447fd7 --- /dev/null +++ b/src/main/java/Duke/Duke.java @@ -0,0 +1,185 @@ +package Duke; + + +import javafx.application.Application; +import javafx.scene.Scene; +import javafx.scene.control.Label; +import javafx.stage.Stage; + +import javafx.scene.control.Button; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.TextField; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.VBox; +import javafx.scene.layout.Region; +import javafx.scene.image.Image; + +public class Duke extends Application { + + private Storage storage; + private TaskList taskList; + private Ui uiPrinter; + private Parser commandParser = new Parser(); + + private ScrollPane scrollPane; + private VBox dialogContainer; + private TextField userInput; + private Button sendButton; + private Scene scene; + + private Image user = new Image(this.getClass().getResourceAsStream("/images/DaUser.png")); + private Image duke = new Image(this.getClass().getResourceAsStream("/images/DaDuke.png")); + + public Duke() { + } + + public Duke(String filePath) { + uiPrinter = new Ui(); + storage = new Storage(filePath); + try { + taskList = new TaskList(storage.loadTaskListFromFile()); + } catch (DukeException e) { + e.getMessage(); + taskList = new TaskList(); + } + } + + public static void main(String[] args) { + new Duke("data/duke.txt").run(); + } + + public void run(){ + System.out.println(uiPrinter.showWelcomeMessage()); + boolean isRunning = true; + while(isRunning) { + String userInput = uiPrinter.readUserInput(); + try { + String dukeHears = commandParser.parseCommand(userInput, taskList, uiPrinter, storage); + if (dukeHears.equals(uiPrinter.byeMsg)) { + isRunning = false; + } else { + continue; + } + } + catch(DukeException e){ + e.getMessage(); + } + } + + } + + + @Override + public void start(Stage stage) { + + scrollPane = new ScrollPane(); + dialogContainer = new VBox(); + scrollPane.setContent(dialogContainer); + + userInput = new TextField(); + sendButton = new Button("Send"); + + AnchorPane mainLayout = new AnchorPane(); + mainLayout.getChildren().addAll(scrollPane, userInput, sendButton); + + scene = new Scene(mainLayout); + + stage.setScene(scene); + stage.show(); + + stage.setTitle("Duke"); + stage.setResizable(false); + stage.setMinHeight(600.0); + stage.setMinWidth(400.0); + + mainLayout.setPrefSize(400.0, 600.0); + + scrollPane.setPrefSize(385, 535); + scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.ALWAYS); + + scrollPane.setVvalue(1.0); + scrollPane.setFitToWidth(true); + + dialogContainer.setPrefHeight(Region.USE_COMPUTED_SIZE); + + userInput.setPrefWidth(325.0); + + sendButton.setPrefWidth(55.0); + + AnchorPane.setTopAnchor(scrollPane, 1.0); + + AnchorPane.setBottomAnchor(sendButton, 1.0); + AnchorPane.setRightAnchor(sendButton, 1.0); + + AnchorPane.setLeftAnchor(userInput , 1.0); + AnchorPane.setBottomAnchor(userInput, 1.0); + + sendButton.setOnMouseClicked((event) -> { + dialogContainer.getChildren().add(getDialogLabel(userInput.getText())); + userInput.clear(); + }); + + userInput.setOnAction((event) -> { + dialogContainer.getChildren().add(getDialogLabel(userInput.getText())); + userInput.clear(); + }); + + dialogContainer.heightProperty().addListener((observable) -> scrollPane.setVvalue(1.0)); + + sendButton.setOnMouseClicked((event) -> { + try { + handleUserInput(); + } catch (DukeException e) { + e.printStackTrace(); + } + }); + + userInput.setOnAction((event) -> { + try { + handleUserInput(); + } catch (DukeException e) { + e.printStackTrace(); + } + }); + } + + private Label getDialogLabel(String text) { + Label textToAdd = new Label(text); + textToAdd.setWrapText(true); + + return textToAdd; + } + + private void handleUserInput() throws DukeException { + String userText = userInput.getText(); + String dukeText = commandParser.parseCommand(userText, taskList, uiPrinter, storage); + dialogContainer.getChildren().addAll( + DialogBox.getUserDialog(userText, user), + DialogBox.getDukeDialog(dukeText, duke) + ); + userInput.clear(); + } + /** + * You should have your own function to generate a response to user input. + * Replace this stub with your completed method. + */ + public String getResponse(String input) { + + uiPrinter = new Ui(); + storage = new Storage("data/duke.txt"); + try { + taskList = new TaskList(storage.loadTaskListFromFile()); + } catch (DukeException e) { + e.getMessage(); + taskList = new TaskList(); + } + + try { + String dukeOutput = commandParser.parseCommand(input, taskList, uiPrinter, storage); + return dukeOutput; + } catch (DukeException e) { + return e.getMessage(); + } + } +} \ No newline at end of file diff --git a/src/main/java/Duke/DukeException.java b/src/main/java/Duke/DukeException.java new file mode 100644 index 0000000000..73009c1613 --- /dev/null +++ b/src/main/java/Duke/DukeException.java @@ -0,0 +1,7 @@ +package Duke; + +class DukeException extends Exception{ + DukeException(String errorMessage){ + super(errorMessage); + } +} \ No newline at end of file diff --git a/src/main/java/Duke/DukeInvalidCommandDataInput.java b/src/main/java/Duke/DukeInvalidCommandDataInput.java new file mode 100644 index 0000000000..00087225d9 --- /dev/null +++ b/src/main/java/Duke/DukeInvalidCommandDataInput.java @@ -0,0 +1,4 @@ +package Duke; + +public class DukeInvalidCommandDataInput extends Exception{ +} \ No newline at end of file diff --git a/src/main/java/Duke/EventTask.java b/src/main/java/Duke/EventTask.java new file mode 100644 index 0000000000..43f7cc7944 --- /dev/null +++ b/src/main/java/Duke/EventTask.java @@ -0,0 +1,41 @@ +package Duke; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +class EventTask extends Task{ + private LocalDateTime atStartDT; + private LocalDateTime atEndDT; + private final static DateTimeFormatter dtFm = DateTimeFormatter.ofPattern("MMM dd yyyy hh:mma"); + + public EventTask(String description, boolean isCompleted, + LocalDateTime atStartDT, LocalDateTime atEndDT){ + super(description, isCompleted); + this.atStartDT = atStartDT; + this.atEndDT = atEndDT; + } + + public EventTask(String description, boolean isCompleted, + LocalDateTime createdDate, LocalDateTime atStartDT, LocalDateTime atEndDT){ + super(description, isCompleted, createdDate); + this.atStartDT = atStartDT; + this.atEndDT = atEndDT; + } + + @Override + public String toString() { + return "[E]"+super.toString() + "(at: " + atStartDT.format(dtFm) + + " to " + atEndDT.format(dtFm) + ")"; + } + + /** + * Generates Event string to be stored in the file. + */ + //E | 0 | project meeting | Aug 6th 2-4pm + @Override + public String toFileString(){ + + return "E" + super.toFileString() + " | " + atStartDT.format(Parser.dtFormat) + " | " + + atEndDT.format(Parser.dtFormat); + } +} \ No newline at end of file diff --git a/src/main/java/Duke/Launcher.java b/src/main/java/Duke/Launcher.java new file mode 100644 index 0000000000..0c67d1ce77 --- /dev/null +++ b/src/main/java/Duke/Launcher.java @@ -0,0 +1,15 @@ +package Duke; + +import javafx.application.Application; + +/** + * A launcher class to workaround classpath issues. + */ +public class Launcher { + public static void main(String[] args) { + System.out.println("hello start"); + +// Application.launch(Duke.class, args); + Application.launch(Main.class, args); + } +} \ No newline at end of file diff --git a/src/main/java/Duke/Main.java b/src/main/java/Duke/Main.java new file mode 100644 index 0000000000..061a8f47b1 --- /dev/null +++ b/src/main/java/Duke/Main.java @@ -0,0 +1,30 @@ +package Duke; +import java.io.IOException; + +import javafx.application.Application; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.scene.layout.AnchorPane; +import javafx.stage.Stage; + +/** + * A GUI for Duke using FXML. + */ +public class Main extends Application { + + private Duke duke = new Duke(); + + @Override + public void start(Stage stage) { + try { + FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("/view/MainWindow.fxml")); + AnchorPane ap = fxmlLoader.load(); + Scene scene = new Scene(ap); + stage.setScene(scene); + fxmlLoader.getController().setDuke(duke); + stage.show(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} \ No newline at end of file diff --git a/src/main/java/Duke/MainWindow.java b/src/main/java/Duke/MainWindow.java new file mode 100644 index 0000000000..eb6cc30b1c --- /dev/null +++ b/src/main/java/Duke/MainWindow.java @@ -0,0 +1,53 @@ +package Duke; +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; +/** + * Controller for MainWindow. Provides the layout for the other controls. + */ +public class MainWindow extends AnchorPane { + @FXML + private ScrollPane scrollPane; + @FXML + private VBox dialogContainer; + @FXML + private TextField userInput; + @FXML + private Button sendButton; + + private Duke duke; + + private Image userImage = new Image(this.getClass().getResourceAsStream("/images/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("Hi! My name is Duke and I will be your task manager for today :)\n" + + "checkout https://prgj.github.io/ip/ for a list of commands I can manage", 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) + ); + userInput.clear(); + } +} \ No newline at end of file diff --git a/src/main/java/Duke/Parser.java b/src/main/java/Duke/Parser.java new file mode 100644 index 0000000000..0342700c7c --- /dev/null +++ b/src/main/java/Duke/Parser.java @@ -0,0 +1,184 @@ +package Duke; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.LocalDateTime; +import java.util.ArrayList; + +/** + * Parses user input and delegates tasks accordingly. + */ +class Parser { + + private TaskList taskList; + + public final static String bye = "bye"; + public final static String list = "list"; + public final static String todo = "todo"; + public final static String deadline = "deadline"; + public final static String event = "event"; + public final static String delete = "delete"; + public final static String mark = "mark"; + public final static String unmark = "unmark"; + public final static String find = "find"; + public final static String showStats = "stats"; + public final static DateTimeFormatter dtFormat = DateTimeFormatter.ofPattern("dd-MM-yyyy HHmm"); + + + + public void checkCommandData(String[] taskInfo, int expectedInfoNum) throws DukeInvalidCommandDataInput{ + if(taskInfo.length != expectedInfoNum){ + throw new DukeInvalidCommandDataInput(); + } + } + + + /** + * Parses the input specified by the user + */ + public String parseCommand(String userinput, TaskList taskList, + Ui uiPrinter, Storage storage) throws DukeException{ + Task newTask = null; + boolean requiredSaveToFile = false; + String returnValue = ""; + boolean taskSuccess = false; + + if (userinput.equals(bye)) { + returnValue = uiPrinter.byeMsg; + } + else if (userinput.startsWith(todo)){ + String taskStr = userinput.substring(todo.length()); + taskStr = taskStr.trim(); + newTask = taskList.processTodo(taskStr); + } + else if (userinput.startsWith(deadline)){ + newTask = processDeadlineCommand(userinput, taskList); + } + else if (userinput.startsWith(event)){ + newTask = processEventCommand(userinput, taskList); + } + else if (userinput.equals(list)) { + returnValue = taskList.processPrintList(uiPrinter); //printlist + } + else if (userinput.startsWith(delete)){ + String taskStr = userinput.substring(delete.length()); + taskStr = taskStr.trim(); + returnValue = taskList.processDelete(taskStr, uiPrinter); +// if (taskSuccess == true) { +// returnValue = uiPrinter.getDeleteTaskInListMsg(deleteTask, taskList.size()); +// requiredSaveToFile = true; +// } else { +// returnValue = "Fail to delete Task!"; +// requiredSaveToFile = false; +// } + if (!returnValue.equals("Fail to delete Task!")) { + requiredSaveToFile = true; + } else { + requiredSaveToFile = false; + } + } + else if (userinput.startsWith(mark)){ + String taskStr = userinput.substring(mark.length()); + taskStr = taskStr.trim(); + returnValue = taskList.processMarkingTask(taskStr, true, uiPrinter); + if (!returnValue.equals("Fail to set task complete status!")) { + requiredSaveToFile = true; + } else { + requiredSaveToFile = false; + } + } + else if (userinput.startsWith(unmark)) { + String taskStr = userinput.substring(unmark.length()); + taskStr = taskStr.trim(); + returnValue = taskList.processMarkingTask(taskStr, false, uiPrinter); + if (!returnValue.equals("Fail to set task complete status!")) { + requiredSaveToFile = true; + } else { + requiredSaveToFile = false; + } + } + else if (userinput.startsWith(find)) { + String findStr = userinput.substring(find.length()).trim(); + returnValue = taskList.processFind(findStr, uiPrinter); //needs to be un-voided + } + else if (userinput.startsWith(showStats)) { + String numDayStr = userinput.substring(showStats.length()); + numDayStr = numDayStr.trim(); + returnValue = taskList.processStats(numDayStr, uiPrinter); //needs to be un-voided + } + else { + throw new DukeException(Ui.invalidCommandMsg); + } + + if(newTask != null){ + taskList.addTask(newTask); + uiPrinter.printMessage(Ui.getTaskInListMsg(newTask, taskList.getNumTasks())); + returnValue = uiPrinter.getTaskInListMsg(newTask, taskList.getNumTasks()); + requiredSaveToFile = true; + } + + if(requiredSaveToFile){ + storage.saveTaskToFile(taskList.getTaskList(), uiPrinter); + } + return returnValue; + } + + /** + * Processes instance where user input specifies an Event task. + */ + private Task processEventCommand(String command, TaskList taskList) throws DukeException { + String taskStr = command.substring(event.length()); + taskStr = taskStr.trim(); + // event Ed Sheeran Concert /at 2-12-2019 1800_to_2300 + String[] taskInfo = taskStr.split("/at"); + try{ + checkCommandData(taskInfo, 2); + } + catch(DukeInvalidCommandDataInput e){ + throw new DukeException(Ui.invalidCommandMsg + "\n" + command); + } + + String description = taskInfo[0].trim(); + String[] fromToDateStr = taskInfo[1].trim().split("_to_"); // 2-12-2019 1800_to_2-12-2019 2300 + String fromDateStr = fromToDateStr[0].trim(); + String toDateStr = fromToDateStr[1].trim(); + LocalDateTime fromDt = null; + LocalDateTime toDt = null; + try{ + fromDt = LocalDateTime.parse(fromDateStr, dtFormat); + toDt = LocalDateTime.parse(toDateStr, dtFormat); + } + catch(Exception e){ + throw new DukeException(Ui.invalidCommandMsg + command + "\n" + Ui.expectedEvent); + } + + return taskList.processEvent(description, fromDt, toDt); + } + + /** + * Processes instance where user input specifies an Event task. + */ + private Task processDeadlineCommand(String command, TaskList taskList) throws DukeException { + // deadline return book /by 2-12-2019 1800 + String taskStr = command.substring(deadline.length()); + taskStr = taskStr.trim(); + String[] taskInfo = taskStr.split("/by"); + try{ + checkCommandData(taskInfo, 2); + } + catch(DukeInvalidCommandDataInput e){ + throw new DukeException(Ui.invalidCommandMsg + "\n" +command + "\n" + Ui.expectedDeadline); + } + String description = taskInfo[0].trim(); + String dateStr = taskInfo[1].trim(); + LocalDateTime dt = null; + try{ + dt = LocalDateTime.parse(dateStr, dtFormat); + } + catch(Exception e){ + throw new DukeException(Ui.invalidCommandMsg + "\n" +command + "\n" + Ui.expectedDeadline); + } + + return taskList.processDeadline(description, dt); + } +} \ No newline at end of file diff --git a/src/main/java/Duke/Storage.java b/src/main/java/Duke/Storage.java new file mode 100644 index 0000000000..15395be03f --- /dev/null +++ b/src/main/java/Duke/Storage.java @@ -0,0 +1,93 @@ +package Duke; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Scanner; + +class Storage { + String filePath; + public Storage(String filePath){ + this.filePath = filePath; + } + + /** + * loads and formats tasks from file into arraylist + */ + public ArrayList loadTaskListFromFile() throws DukeException { + ArrayList taskList = new ArrayList<>(); + File f = new File(filePath); + try { + Scanner scanFile = new Scanner(f); + while(scanFile.hasNext()){ + String lineData = scanFile.nextLine(); + String[] taskData = lineData.split("\\|"); + String taskType = taskData[0].trim(); + boolean isCompleted = taskData[1].trim().equals("1"); + String desc = taskData[2].trim(); + String createdDateStr = taskData[3].trim(); + LocalDateTime createdDt = LocalDateTime.parse(createdDateStr, Parser.dtFormat); + Task newTask = null; + switch(taskType){ + case "T": + newTask = new ToDoTask(desc, isCompleted, createdDt); + break; + case "D": + String byDateStr = taskData[4].trim(); + LocalDateTime dt = LocalDateTime.parse(byDateStr, Parser.dtFormat); + newTask = new DeadlineTask(desc, isCompleted, createdDt, dt); + break; + case "E": + String fromDateStr = taskData[4].trim(); + LocalDateTime fDt = LocalDateTime.parse(fromDateStr, Parser.dtFormat); + String toDateStr = taskData[5].trim(); + LocalDateTime tDt = LocalDateTime.parse(toDateStr, Parser.dtFormat); + newTask = new EventTask(desc, isCompleted, createdDt, fDt, tDt); + break; + } + if(newTask != null){ + taskList.add(newTask); + } + } + scanFile.close(); + return taskList; + } + catch(FileNotFoundException e){ + // do nothing, no file no load + throw new DukeException("No file available for loading."); + } + + + } + + /** + * saves the tasks in arraylist to file. + */ + public void saveTaskToFile(ArrayList taskList, Ui uiPrinter){ + File f = new File(filePath); + try{ + if(!f.exists()) { + // create data folder if not exist + f.getParentFile().mkdirs(); + // create duke.txt + f.createNewFile(); + } + + FileWriter fw = new FileWriter(f); + for(Task t: taskList){ + fw.write(t.toFileString()+"\n"); + } + + fw.close(); + } + catch(SecurityException se){ + se.getMessage(); + } + catch(IOException e){ + uiPrinter.printMessage("Unable to save to filepath data/duke.txt"); + } + } +} \ No newline at end of file diff --git a/src/main/java/Duke/Task.java b/src/main/java/Duke/Task.java new file mode 100644 index 0000000000..e33ced594e --- /dev/null +++ b/src/main/java/Duke/Task.java @@ -0,0 +1,53 @@ +package Duke; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +abstract class Task { + private String description; + private boolean isCompleted; + LocalDateTime createdDate; + private final static DateTimeFormatter fm = DateTimeFormatter.ofPattern("MMM dd yyyy hh:mma"); + + public Task(String description, boolean isCompleted){ + this.description = description; + this.isCompleted = isCompleted; + this.createdDate = LocalDateTime.now(); + } + + public Task(String description, boolean isCompleted, LocalDateTime createdDate){ + this.description = description; + this.isCompleted = isCompleted; + this.createdDate = createdDate; + } + + public boolean isCompleted() { + return isCompleted; + } + + public void setCompleted(boolean completed) { isCompleted = completed; } + + public String getDescription() { + return description; + } + + public LocalDateTime getCreatedDate() { + return createdDate; + } + + + @Override + public String toString() { + // [X] study + return "[" + ((isCompleted)?"X":" ") + "] " + description; + } + + /** + * Generates parent task string to be stored in the file. + */ + // T | 1 | read book + public String toFileString(){ + return " | "+((isCompleted)?"1 | ":"0 | ") + description + + " | " + createdDate.format(Parser.dtFormat); + } +} \ No newline at end of file diff --git a/src/main/java/Duke/TaskList.java b/src/main/java/Duke/TaskList.java new file mode 100644 index 0000000000..9a7d92c8c3 --- /dev/null +++ b/src/main/java/Duke/TaskList.java @@ -0,0 +1,156 @@ +package Duke; + +import java.time.LocalDateTime; +import java.util.ArrayList; + +class TaskList { + public ArrayList taskList; + + public TaskList(){ + this.taskList = new ArrayList(); + } + public TaskList(ArrayList taskList){ + this.taskList = taskList; + } + + public ArrayList getTaskList(){ + return this.taskList; + } + + public void addTask(Task task){ + this.taskList.add(task); + } + + public int getNumTasks(){ + return taskList.size(); + } + + /** + * Process the printing of a task. + */ + public String processPrintList(Ui uiPrinter){ + System.out.println("I got here"); + String fullListMessage = ""; + fullListMessage = uiPrinter.listMsg; + fullListMessage += uiPrinter.listMsg; + fullListMessage += uiPrinter.printTasks(taskList); + return fullListMessage; + } + + /** + * Process the marking status of a task. + */ + public String processMarkingTask(String taskIndexStr, boolean isCompleted, + Ui uiPrinter) throws DukeException{ + int markingIndex = getExistingIndex(taskIndexStr); + String returnMarkingTask = ""; + if(markingIndex != -1) { + taskList.get(markingIndex).setCompleted(isCompleted); + returnMarkingTask = uiPrinter.getCompleteMessage(isCompleted); + processPrintList(uiPrinter); + return returnMarkingTask; + } + else{ + returnMarkingTask = "Fail to set task complete status!"; + return returnMarkingTask; + } + } + + /** + * Processes a todo task from the user input provided. + */ + public Task processTodo(String description) { + return new ToDoTask(description, false); + } + + public String processStats(String numDayStr, Ui uiPrinter)throws DukeException{ + checkIfNumber(numDayStr); + LocalDateTime pastDays = LocalDateTime.now().minusDays(Integer.parseInt(numDayStr)); + ArrayList filterList = new ArrayList<>(); + for(Task task: taskList){ + if(!task.isCompleted()){ continue; } + if(task.getCreatedDate().isBefore(pastDays)){ continue; } + filterList.add(task); + } + String returnStats = ""; + returnStats = uiPrinter.printTasks(filterList); + return returnStats; + } + + /** + * Processes deletion of a task. + */ + public String processDelete(String delStrIndex, Ui uiPrinter) throws DukeException{ + int delIndex = getExistingIndex(delStrIndex); + String deleteReturn = ""; + if(delIndex != -1) { + Task deleteTask = taskList.get(delIndex); + taskList.remove(delIndex); + deleteReturn = uiPrinter.getDeleteTaskInListMsg(deleteTask, taskList.size()); + return deleteReturn; + } + else{ + deleteReturn = "Fail to delete Task!"; + return deleteReturn; + } + } + + /** + * Check if in put is a valid number. + */ + public void checkIfNumber(String numStr) throws DukeException { + try{ + Integer.parseInt(numStr); + } + catch(Exception e){ + throw new DukeException(numStr+" is not a number!"); + } + } + + /** + * Processes an Event task from the user input provided. + */ + public Task processEvent(String description, LocalDateTime fromDt, LocalDateTime toDt ) { + return new EventTask(description, false, fromDt, toDt); + } + + /** + * Processes a Deadline task from the user input provided. + */ + public Task processDeadline(String description, LocalDateTime dt) { + return new DeadlineTask(description,false, dt); + } + + /** + * Ensures number selected is within the range of values the tasklist has. + */ + public int getExistingIndex(String findStrIndex) throws DukeException{ + if(taskList.size() == 0){ + throw new DukeException("Task list is empty!"); + } + + checkIfNumber(findStrIndex); + + int findIndex = Integer.parseInt(findStrIndex)-1; + if(findIndex >= 0 && findIndex < taskList.size()){ + return findIndex; + } + + throw new DukeException("Invalid task number selected!"); + } + + /** + * Finds tasks containing specified keyword. + */ + public String processFind(String keyword, Ui uiPrinter) { + String returnFind = ""; + returnFind = uiPrinter.getTaskMsg; + for (int i = 0; i < taskList.size(); i++) { + if (taskList.get(i).getDescription().contains(keyword)) { + String temp = (i + 1) + ". " + taskList.get(i).toString() + "\n"; + returnFind += temp; + } + } + return returnFind; + } +} \ No newline at end of file diff --git a/src/main/java/Duke/ToDoTask.java b/src/main/java/Duke/ToDoTask.java new file mode 100644 index 0000000000..6992f960c1 --- /dev/null +++ b/src/main/java/Duke/ToDoTask.java @@ -0,0 +1,27 @@ +package Duke; + +import java.time.LocalDateTime; + +class ToDoTask extends Task{ + public ToDoTask(String description, boolean isCompleted){ + super(description, isCompleted); + } + + public ToDoTask(String description, boolean isCompleted, LocalDateTime createdDate){ + super(description, isCompleted, createdDate); + } + + @Override + public String toString() { + return "[T]"+super.toString(); + } + + /** + * Generates ToDo string to be stored in the file. + */ + // T | 1 | read book + @Override + public String toFileString(){ + return "T" + super.toFileString(); + } +} \ No newline at end of file diff --git a/src/main/java/Duke/Ui.java b/src/main/java/Duke/Ui.java new file mode 100644 index 0000000000..efc70fea20 --- /dev/null +++ b/src/main/java/Duke/Ui.java @@ -0,0 +1,78 @@ +package Duke; + +import java.util.ArrayList; +import java.util.Scanner; + +class Ui { + public final static String welcomeMsg = "Hello! I am Duke\nWhat can I do for you?"; + public final static String horizontalLine = "________________________________"; + public final static String byeMsg = "Bye! hope to see you again soon!"; + public final static String listMsg = "Here are a list of your tasks!"; + public final static String deleteMsg = "Alright! Let me delete this task:\n"; + public final static String invalidCommandMsg = "I do not understand your command!"; + public final static String addedTaskMsg = "Got it. I've added this task:\n"; + public final static String completedTaskMsg = "Task has been marked as completed.\n"; + public final static String notCompletedTaskMsg = "Task has been marked as not completed."; + public final static String expectedDeadline = "Try typing it in the following format:\n " + + "deadline /by 31-01-2022 1800"; + public final static String expectedEvent = "Try typing it in the following format:\n " + + "event /at 31-01-2022 1800_to_31-01-2022 2100"; + public final static String getTaskMsg = "Here are the tasks containing the keyword"; + + + /** + * Prints out the number of items in the list of tasks after adding in a new one. + */ + public static String getTaskInListMsg(Task task, int numTask){ + return addedTaskMsg + "\t" + task + "\nNow you have " + numTask + " tasks in the list"; + } + + /** + * Prints out the number of items in the list of tasks after deleting one. + */ + public static String getDeleteTaskInListMsg(Task task, int numTask){ + return deleteMsg + "\t" + task + "\nNow you have " + numTask + " tasks in the list"; + } + + /** + * Return completion status of task. + */ + public static String getCompleteMessage(boolean isCompleted){ + return (isCompleted)?completedTaskMsg:notCompletedTaskMsg; + } + + /** + * Print the tasks present in the arraylist. + */ + public String printTasks(ArrayList taskList){ + String listReturn = ""; + int i = 1; + for(Task t: taskList){ + String temp = i++ + ". " + t + "\n"; + listReturn += temp; + } + return listReturn; + } + + /** + * Format print messages. + */ + public String showWelcomeMessage() { + return "Hi! My name is Duke and I will be your task manager for today :)" + + "checkout https://prgj.github.io/ip/ for a list of commands I can manage"; + } + + public String readUserInput() { + Scanner sc = new Scanner(System.in); + return sc.nextLine(); + } + + /** + * Format print messages. + */ + public void printMessage(String msg) { + System.out.println(horizontalLine); + System.out.println(msg); + System.out.println(horizontalLine); + } +} \ 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..76381b3097 --- /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/resources/Images/DaDuke.png b/src/main/resources/Images/DaDuke.png new file mode 100644 index 0000000000..d893658717 Binary files /dev/null and b/src/main/resources/Images/DaDuke.png differ diff --git a/src/main/resources/Images/DaUser.png b/src/main/resources/Images/DaUser.png new file mode 100644 index 0000000000..3c82f45461 Binary files /dev/null and b/src/main/resources/Images/DaUser.png differ diff --git a/src/main/resources/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..1081620572 --- /dev/null +++ b/src/main/resources/view/MainWindow.fxml @@ -0,0 +1,19 @@ + + + + + + + + + + + +