From 68c58c12c1d631736a4b25500248a2956171496f Mon Sep 17 00:00:00 2001 From: damithc Date: Mon, 25 May 2020 00:58:18 +0800 Subject: [PATCH 001/105] Add Gradle support --- build.gradle | 41 +++++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 58695 bytes gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 183 +++++++++++++++++++++++ gradlew.bat | 103 +++++++++++++ text-ui-test/runtest.sh | 0 6 files changed, 332 insertions(+) create mode 100644 build.gradle create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat mode change 100644 => 100755 text-ui-test/runtest.sh diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000000..885198fcfa --- /dev/null +++ b/build.gradle @@ -0,0 +1,41 @@ +plugins { + id 'java' + id 'application' + id 'com.github.johnrengelman.shadow' version '5.1.0' +} + +repositories { + mavenCentral() +} + +dependencies { + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0' + testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.0' +} + +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 +} + +run{ + standardInput = System.in +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..f3d88b1c2faf2fc91d853cd5d4242b5547257070 GIT binary patch literal 58695 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 literal 0 HcmV?d00001 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/text-ui-test/runtest.sh b/text-ui-test/runtest.sh old mode 100644 new mode 100755 From 03523ec89e823ff5457b647df22a4e395641da7a Mon Sep 17 00:00:00 2001 From: lzq Date: Sat, 5 Aug 2023 15:24:02 +0800 Subject: [PATCH 002/105] Bump gradle and lib version --- build.gradle | 9 +- gradle/wrapper/gradle-wrapper.jar | Bin 58695 -> 63375 bytes gradle/wrapper/gradle-wrapper.properties | 4 +- gradlew | 281 ++++++++++++++--------- gradlew.bat | 195 ++++++++-------- 5 files changed, 273 insertions(+), 216 deletions(-) diff --git a/build.gradle b/build.gradle index 885198fcfa..a388517ae1 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ plugins { id 'java' id 'application' - id 'com.github.johnrengelman.shadow' version '5.1.0' + id 'com.github.johnrengelman.shadow' version '7.1.2' } repositories { @@ -9,8 +9,8 @@ repositories { } dependencies { - testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.0' - testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.5.0' + testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.10.0' + testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.10.0' } test { @@ -28,12 +28,13 @@ test { } application { - mainClassName = "seedu.duke.Duke" + mainClass.set("seedu.duke.Duke") } shadowJar { archiveBaseName = "duke" archiveClassifier = null + dependsOn("distZip", "distTar") } run{ diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index f3d88b1c2faf2fc91d853cd5d4242b5547257070..033e24c4cdf41af1ab109bc7f253b2b887023340 100644 GIT binary patch delta 43723 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 delta 38942 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b7c8c5dbf5..66c01cfeba 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.2-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 2fe81a7d95..fcb6fca147 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ -#!/usr/bin/env sh +#!/bin/sh # -# Copyright 2015 the original author or authors. +# Copyright © 2015-2021 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -17,78 +17,110 @@ # ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # 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 +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac 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"' +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # 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 - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -97,87 +129,120 @@ 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. + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + 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 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 +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac 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 +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. # 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 +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + # 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\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=`expr $i + 1` + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg 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" +# 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"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index 62bd9b9cce..6689b85bee 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,103 +1,92 @@ -@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 +@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=. +@rem This is normally unused +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% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 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! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega From 81a9c537afe8492675eb253968939364d65db091 Mon Sep 17 00:00:00 2001 From: aureliony <39163684+aureliony@users.noreply.github.com> Date: Tue, 16 Jul 2024 23:35:06 +0800 Subject: [PATCH 003/105] build.gradle: Prevent generating a second JAR file In build.gradle, the dependencies on distZip and/or distTar causes the shadowJar task to generate a second JAR file for which the mainClass.set("seedu.duke.Duke") does not take effect. Hence, this additional JAR file cannot be run. For this product, there is no need to generate a second JAR file to begin with. Let's remove this dependency from the build.gradle to prevent the shadowJar task from generating the extra JAR file. --- build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle b/build.gradle index a388517ae1..c361f9811e 100644 --- a/build.gradle +++ b/build.gradle @@ -34,7 +34,6 @@ application { shadowJar { archiveBaseName = "duke" archiveClassifier = null - dependsOn("distZip", "distTar") } run{ From edaa9706015ad73308af113eecb1b7f3b7d7f2d1 Mon Sep 17 00:00:00 2001 From: izruff Date: Wed, 21 Aug 2024 11:48:23 +0800 Subject: [PATCH 004/105] Rename main class --- src/main/java/{Duke.java => Mittens.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/main/java/{Duke.java => Mittens.java} (93%) diff --git a/src/main/java/Duke.java b/src/main/java/Mittens.java similarity index 93% rename from src/main/java/Duke.java rename to src/main/java/Mittens.java index 5d313334cc..c53704a847 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Mittens.java @@ -1,4 +1,4 @@ -public class Duke { +public class Mittens { public static void main(String[] args) { String logo = " ____ _ \n" + "| _ \\ _ _| | _____ \n" From 2f4d559cbac131f1ebf34971d42238e87c7a6103 Mon Sep 17 00:00:00 2001 From: izruff Date: Wed, 21 Aug 2024 19:30:56 +0800 Subject: [PATCH 005/105] Modify greeting message --- src/main/java/Mittens.java | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/main/java/Mittens.java b/src/main/java/Mittens.java index c53704a847..9cc75d69c3 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/Mittens.java @@ -1,10 +1,25 @@ public class Mittens { + private final static String GREETING_MESSAGE = " ██ ██ ____________________\n" + + " ██░░██ ██░░██ / Hi, I'm Mittens! \\\n" + + " ██░░░░██████░░░░██ | I'm a cat! Meow :3 |\n" + + "██░░░░░░░░░░░░░░░░░░██ | |\n" + + "██░░░░░░░░░░░░░░░░░░██ \\ Bye-bye! :3 /\n" + + "██░░██░░░░░░░░██░░░░██ --------------------\n" + + "██░░██░░░░░░░░██░░░░██ ████ \n" + + "██░░░░░░░░░░░░░░░░░░██ ██ ██ \n" + + " ████▒▒▒▒▒▒▒▒▒▒████ ██ ██ \n" + + " ██░░▒▒▒▒░░░░░░██ ██ ██\n" + + " ██░░██░░████░░░░██ ██░░░░██\n" + + " ██░░████░░░░██░░██ ██░░░░██\n" + + " ██ ████░░░░░░░░████▒▒▒▒▒▒██\n" + + " ██ ██ ░░░░░░██▒▒▒▒████ \n" + + " ██████████████████████ \n"; + + public static void greet() { + System.out.println(GREETING_MESSAGE); + } + public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); + greet(); } } From dd1abfc7e0df0e4af0077b6d26e1282d23db1a98 Mon Sep 17 00:00:00 2001 From: izruff Date: Wed, 21 Aug 2024 19:51:29 +0800 Subject: [PATCH 006/105] Use code blocks for multi-line string --- src/main/java/Mittens.java | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/main/java/Mittens.java b/src/main/java/Mittens.java index 9cc75d69c3..1983e98572 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/Mittens.java @@ -1,19 +1,21 @@ public class Mittens { - private final static String GREETING_MESSAGE = " ██ ██ ____________________\n" + - " ██░░██ ██░░██ / Hi, I'm Mittens! \\\n" + - " ██░░░░██████░░░░██ | I'm a cat! Meow :3 |\n" + - "██░░░░░░░░░░░░░░░░░░██ | |\n" + - "██░░░░░░░░░░░░░░░░░░██ \\ Bye-bye! :3 /\n" + - "██░░██░░░░░░░░██░░░░██ --------------------\n" + - "██░░██░░░░░░░░██░░░░██ ████ \n" + - "██░░░░░░░░░░░░░░░░░░██ ██ ██ \n" + - " ████▒▒▒▒▒▒▒▒▒▒████ ██ ██ \n" + - " ██░░▒▒▒▒░░░░░░██ ██ ██\n" + - " ██░░██░░████░░░░██ ██░░░░██\n" + - " ██░░████░░░░██░░██ ██░░░░██\n" + - " ██ ████░░░░░░░░████▒▒▒▒▒▒██\n" + - " ██ ██ ░░░░░░██▒▒▒▒████ \n" + - " ██████████████████████ \n"; + private final static String GREETING_MESSAGE = """ + ██ ██ ____________________ + ██░░██ ██░░██ / Hi, I'm Mittens! \\ + ██░░░░██████░░░░██ | I'm a cat! Meow :3 | + ██░░░░░░░░░░░░░░░░░░██ | | + ██░░░░░░░░░░░░░░░░░░██ \\ Bye-bye! :3 / + ██░░██░░░░░░░░██░░░░██ -------------------- + ██░░██░░░░░░░░██░░░░██ ████ + ██░░░░░░░░░░░░░░░░░░██ ██ ██ + ████▒▒▒▒▒▒▒▒▒▒████ ██ ██ + ██░░▒▒▒▒░░░░░░██ ██ ██ + ██░░██░░████░░░░██ ██░░░░██ + ██░░████░░░░██░░██ ██░░░░██ + ██ ████░░░░░░░░████▒▒▒▒▒▒██ + ██ ██ ░░░░░░██▒▒▒▒████ + ██████████████████████ + """; public static void greet() { System.out.println(GREETING_MESSAGE); From 5c2c82191cb0750e1d35cafefdde43373fdd20af Mon Sep 17 00:00:00 2001 From: izruff Date: Wed, 21 Aug 2024 20:04:33 +0800 Subject: [PATCH 007/105] Add exit message and modify greeting --- src/main/java/Mittens.java | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/main/java/Mittens.java b/src/main/java/Mittens.java index 1983e98572..92383c55dd 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/Mittens.java @@ -1,11 +1,31 @@ public class Mittens { private final static String GREETING_MESSAGE = """ + ██ ██ ____________________ ██░░██ ██░░██ / Hi, I'm Mittens! \\ ██░░░░██████░░░░██ | I'm a cat! Meow :3 | - ██░░░░░░░░░░░░░░░░░░██ | | - ██░░░░░░░░░░░░░░░░░░██ \\ Bye-bye! :3 / - ██░░██░░░░░░░░██░░░░██ -------------------- + ██░░░░░░░░░░░░░░░░░░██ \\ How can I help? / + ██░░░░░░░░░░░░░░░░░░██ -------------------- + ██░░██░░░░░░░░██░░░░██ + ██░░██░░░░░░░░██░░░░██ ████ + ██░░░░░░░░░░░░░░░░░░██ ██ ██ + ████▒▒▒▒▒▒▒▒▒▒████ ██ ██ + ██░░▒▒▒▒░░░░░░██ ██ ██ + ██░░██░░████░░░░██ ██░░░░██ + ██░░████░░░░██░░██ ██░░░░██ + ██ ████░░░░░░░░████▒▒▒▒▒▒██ + ██ ██ ░░░░░░██▒▒▒▒████ + ██████████████████████ + """; + + private final static String EXIT_MESSAGE = """ + + ██ ██ _____________ + ██░░██ ██░░██ ( Bye-bye! :3 ) + ██░░░░██████░░░░██ ------------- + ██░░░░░░░░░░░░░░░░░░██ + ██░░░░░░░░░░░░░░░░░░██ + ██░░██░░░░░░░░██░░░░██ ██░░██░░░░░░░░██░░░░██ ████ ██░░░░░░░░░░░░░░░░░░██ ██ ██ ████▒▒▒▒▒▒▒▒▒▒████ ██ ██ @@ -21,7 +41,12 @@ public static void greet() { System.out.println(GREETING_MESSAGE); } + public static void exit() { + System.out.println(EXIT_MESSAGE); + } + public static void main(String[] args) { greet(); + exit(); } } From d83548d6992fba2b0300bdc1a53a5d126a0023bf Mon Sep 17 00:00:00 2001 From: izruff Date: Wed, 21 Aug 2024 20:16:28 +0800 Subject: [PATCH 008/105] Add echo feature --- src/main/java/Mittens.java | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/main/java/Mittens.java b/src/main/java/Mittens.java index 92383c55dd..6201c1839d 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/Mittens.java @@ -41,6 +41,32 @@ public static void greet() { System.out.println(GREETING_MESSAGE); } + public static void echo(String command) { + int len = command.length(); + String message = """ + + ██ ██ %s + ██░░██ ██░░██ ( %s ) + ██░░░░██████░░░░██ %s + ██░░░░░░░░░░░░░░░░░░██ + ██░░░░░░░░░░░░░░░░░░██ + ██░░██░░░░░░░░██░░░░██ + ██░░██░░░░░░░░██░░░░██ ████ + ██░░░░░░░░░░░░░░░░░░██ ██ ██ + ████▒▒▒▒▒▒▒▒▒▒████ ██ ██ + ██░░▒▒▒▒░░░░░░██ ██ ██ + ██░░██░░████░░░░██ ██░░░░██ + ██░░████░░░░██░░██ ██░░░░██ + ██ ████░░░░░░░░████▒▒▒▒▒▒██ + ██ ██ ░░░░░░██▒▒▒▒████ + ██████████████████████ + """ + .formatted("_".repeat(len + 2), + command, "-".repeat(len + 2)); + + System.out.println(message); + } + public static void exit() { System.out.println(EXIT_MESSAGE); } @@ -48,5 +74,6 @@ public static void exit() { public static void main(String[] args) { greet(); exit(); + echo("Testing"); } } From bdecfd1491dc3ecb0fcd4c1a60e9b85f9de0ee02 Mon Sep 17 00:00:00 2001 From: izruff Date: Wed, 21 Aug 2024 20:21:22 +0800 Subject: [PATCH 009/105] Create main loop for receiving user input --- src/main/java/Mittens.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/main/java/Mittens.java b/src/main/java/Mittens.java index 6201c1839d..8dc9dff8e0 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/Mittens.java @@ -1,3 +1,5 @@ +import java.util.Scanner; + public class Mittens { private final static String GREETING_MESSAGE = """ @@ -72,8 +74,21 @@ public static void exit() { } public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + greet(); + + while (true) { + System.out.print("> "); + String input = scanner.nextLine(); + + if (input.equals("bye")) { + break; + } else { + echo(input); + } + } + exit(); - echo("Testing"); } } From 729d3fd01e3be7ecbb50011f4a2b8b3b0f463d46 Mon Sep 17 00:00:00 2001 From: izruff Date: Wed, 21 Aug 2024 21:29:53 +0800 Subject: [PATCH 010/105] Implement add task and list tasks --- src/main/java/Mittens.java | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/main/java/Mittens.java b/src/main/java/Mittens.java index 8dc9dff8e0..363a941785 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/Mittens.java @@ -1,3 +1,4 @@ +import java.util.ArrayList; import java.util.Scanner; public class Mittens { @@ -39,6 +40,8 @@ public class Mittens { ██████████████████████ """; + private static ArrayList tasks = new ArrayList<>(); + public static void greet() { System.out.println(GREETING_MESSAGE); } @@ -69,6 +72,19 @@ public static void echo(String command) { System.out.println(message); } + public static void addTask(String task) { + tasks.add(task); + System.out.printf("\nI've added \"%s\" to your list :3\n\n", task); + } + + public static void listTasks() { + System.out.println("\nHere are the tasks in your list :3"); + for (int i = 0; i < tasks.size(); i++) { + System.out.printf("%d. %s\n", i + 1, tasks.get(i)); + } + System.out.print("\n"); + } + public static void exit() { System.out.println(EXIT_MESSAGE); } @@ -84,8 +100,10 @@ public static void main(String[] args) { if (input.equals("bye")) { break; + } else if (input.equals("list")) { + listTasks(); } else { - echo(input); + addTask(input); } } From 5b35bb3dcb9cb0b5eb6f5f15eb624a9db3de54f3 Mon Sep 17 00:00:00 2001 From: izruff Date: Wed, 21 Aug 2024 21:38:54 +0800 Subject: [PATCH 011/105] Add Task class --- src/main/java/Task.java | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/main/java/Task.java diff --git a/src/main/java/Task.java b/src/main/java/Task.java new file mode 100644 index 0000000000..71d0d2c36c --- /dev/null +++ b/src/main/java/Task.java @@ -0,0 +1,25 @@ +public class Task { + protected String description; + protected boolean isDone; + + public Task(String description) { + this.description = description; + this.isDone = false; + } + + public String getDescription() { + return description; + } + + public String getStatusIcon() { + return (isDone ? "X" : " "); + } + + public void markAsDone() { + this.isDone = true; + } + + public void markAsNotDone() { + this.isDone = false; + } +} From e5cbbebf363fa8015c0244aaf254e7207c15facf Mon Sep 17 00:00:00 2001 From: izruff Date: Wed, 21 Aug 2024 21:42:25 +0800 Subject: [PATCH 012/105] Task.java: Add toString method --- src/main/java/Task.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/Task.java b/src/main/java/Task.java index 71d0d2c36c..f9b1207e04 100644 --- a/src/main/java/Task.java +++ b/src/main/java/Task.java @@ -22,4 +22,8 @@ public void markAsDone() { public void markAsNotDone() { this.isDone = false; } + + public String toString() { + return "[" + this.getStatusIcon() + "] " + this.description; + } } From 857012cedd378ed3a997e8b1b473b6d921cc132b Mon Sep 17 00:00:00 2001 From: izruff Date: Wed, 21 Aug 2024 21:44:14 +0800 Subject: [PATCH 013/105] Replace string-based tasks with Task instances --- src/main/java/Mittens.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/Mittens.java b/src/main/java/Mittens.java index 363a941785..c3f85aefd6 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/Mittens.java @@ -40,7 +40,7 @@ public class Mittens { ██████████████████████ """; - private static ArrayList tasks = new ArrayList<>(); + private static ArrayList tasks = new ArrayList<>(); public static void greet() { System.out.println(GREETING_MESSAGE); @@ -72,15 +72,16 @@ public static void echo(String command) { System.out.println(message); } - public static void addTask(String task) { + public static void addTask(Task task) { tasks.add(task); - System.out.printf("\nI've added \"%s\" to your list :3\n\n", task); + System.out.printf("\nI've added \"%s\" to your list :3\n\n", task.getDescription()); } public static void listTasks() { System.out.println("\nHere are the tasks in your list :3"); for (int i = 0; i < tasks.size(); i++) { - System.out.printf("%d. %s\n", i + 1, tasks.get(i)); + Task task = tasks.get(i); + System.out.printf("%d. %s\n", i + 1, task.toString()); } System.out.print("\n"); } @@ -103,7 +104,8 @@ public static void main(String[] args) { } else if (input.equals("list")) { listTasks(); } else { - addTask(input); + Task newTask = new Task(input); + addTask(newTask); } } From c93d0cf40cf2e5ab6eb2c61a81f5e18112bab079 Mon Sep 17 00:00:00 2001 From: izruff Date: Wed, 21 Aug 2024 21:51:58 +0800 Subject: [PATCH 014/105] Add mark and unmark feature --- src/main/java/Mittens.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/main/java/Mittens.java b/src/main/java/Mittens.java index c3f85aefd6..6aef8ab047 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/Mittens.java @@ -86,6 +86,18 @@ public static void listTasks() { System.out.print("\n"); } + public static void markTaskAsDone(int index) { + Task task = tasks.get(index - 1); + task.markAsDone(); + System.out.printf("\nMeow, I scratched the check box for you:\n%s\n\n", task.toString()); + } + + public static void markTaskAsNotDone(int index) { + Task task = tasks.get(index - 1); + task.markAsNotDone(); + System.out.printf("\nMeow, I unscratched the check box for you:\n%s\n\n", task.toString()); + } + public static void exit() { System.out.println(EXIT_MESSAGE); } @@ -103,6 +115,12 @@ public static void main(String[] args) { break; } else if (input.equals("list")) { listTasks(); + } else if (input.startsWith("mark")) { + int index = Integer.parseInt(input.split(" ")[1]); + markTaskAsDone(index); + } else if (input.startsWith("unmark")) { + int index = Integer.parseInt(input.split(" ")[1]); + markTaskAsNotDone(index); } else { Task newTask = new Task(input); addTask(newTask); From 55e872b791115d29f76eebbf4bff6a659e2be0a5 Mon Sep 17 00:00:00 2001 From: izruff Date: Thu, 22 Aug 2024 13:15:47 +0800 Subject: [PATCH 015/105] Make Task abstract and improve code quality --- src/main/java/Task.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/Task.java b/src/main/java/Task.java index f9b1207e04..998a1e43d4 100644 --- a/src/main/java/Task.java +++ b/src/main/java/Task.java @@ -1,4 +1,4 @@ -public class Task { +public abstract class Task { protected String description; protected boolean isDone; @@ -8,11 +8,11 @@ public Task(String description) { } public String getDescription() { - return description; + return this.description; } public String getStatusIcon() { - return (isDone ? "X" : " "); + return (this.isDone ? "X" : " "); } public void markAsDone() { @@ -23,6 +23,7 @@ public void markAsNotDone() { this.isDone = false; } + @Override public String toString() { return "[" + this.getStatusIcon() + "] " + this.description; } From 8a7b166bd61374d5afeda8898f9a3c93319fd036 Mon Sep 17 00:00:00 2001 From: izruff Date: Thu, 22 Aug 2024 13:16:24 +0800 Subject: [PATCH 016/105] Add Todo, Deadline, and Event subclasses --- src/main/java/Deadline.java | 13 +++++++++++++ src/main/java/Event.java | 15 +++++++++++++++ src/main/java/Todo.java | 10 ++++++++++ 3 files changed, 38 insertions(+) create mode 100644 src/main/java/Deadline.java create mode 100644 src/main/java/Event.java create mode 100644 src/main/java/Todo.java diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java new file mode 100644 index 0000000000..d4d9d00e5e --- /dev/null +++ b/src/main/java/Deadline.java @@ -0,0 +1,13 @@ +public class Deadline extends Task { + protected String by; + + public Deadline(String description, String by) { + super(description); + this.by = by; + } + + @Override + public String toString() { + return "[D]" + super.toString() + " (due " + this.by + ")"; + } +} diff --git a/src/main/java/Event.java b/src/main/java/Event.java new file mode 100644 index 0000000000..a02ae02d5d --- /dev/null +++ b/src/main/java/Event.java @@ -0,0 +1,15 @@ +public class Event extends Task { + protected String from; + protected String to; + + public Event(String description, String from, String to) { + super(description); + this.from = from; + this.to = to; + } + + @Override + public String toString() { + return "[E]" + super.toString() + " (" + this.from + " -- " + this.to + ")"; + } +} diff --git a/src/main/java/Todo.java b/src/main/java/Todo.java new file mode 100644 index 0000000000..eabef3ab8f --- /dev/null +++ b/src/main/java/Todo.java @@ -0,0 +1,10 @@ +public class Todo extends Task { + public Todo(String description) { + super(description); + } + + @Override + public String toString() { + return "[T]" + super.toString(); + } +} From 75cdc3023a0429b5ea2eeba8d627d2a667bfa59f Mon Sep 17 00:00:00 2001 From: izruff Date: Sun, 25 Aug 2024 00:22:09 +0800 Subject: [PATCH 017/105] Add functionality to new task types --- src/main/java/Mittens.java | 35 +++++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/main/java/Mittens.java b/src/main/java/Mittens.java index 6aef8ab047..dab23b27c4 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/Mittens.java @@ -78,7 +78,11 @@ public static void addTask(Task task) { } public static void listTasks() { - System.out.println("\nHere are the tasks in your list :3"); + if (tasks.size() == 0) { + System.out.println("\nMeow?! Your list is empty!\n"); + return; + } + System.out.printf("\nYou have %d tasks in your list, here they are :3\n", tasks.size()); for (int i = 0; i < tasks.size(); i++) { Task task = tasks.get(i); System.out.printf("%d. %s\n", i + 1, task.toString()); @@ -121,9 +125,32 @@ public static void main(String[] args) { } else if (input.startsWith("unmark")) { int index = Integer.parseInt(input.split(" ")[1]); markTaskAsNotDone(index); - } else { - Task newTask = new Task(input); - addTask(newTask); + } else if (input.startsWith("todo")) { + String description = input.substring(5); + + Todo newTodo = new Todo(description); + addTask(newTodo); + } else if (input.startsWith("deadline")) { + // Separate the inputs so that the first element contains the description while + // the rest contains flags. + String[] inputs = input.split(" /"); + String description = inputs[0].substring(9); + // Assuming order of flags are: by + String by = inputs[1].substring(3); + + Deadline newDeadline = new Deadline(description, by); + addTask(newDeadline); + } else if (input.startsWith("event")) { + // Separate the inputs so that the first element contains the description while + // the rest contains flags. + String[] inputs = input.split(" /"); + String description = inputs[0].substring(6); + // Assuming order of flags are: from, to + String from = inputs[1].substring(5); + String to = inputs[2].substring(3); + + Event newEvent = new Event(description, from, to); + addTask(newEvent); } } From 7b2770cb3e2e894c11c38f64734a7dd191d27ee9 Mon Sep 17 00:00:00 2001 From: izruff Date: Sun, 25 Aug 2024 01:26:02 +0800 Subject: [PATCH 018/105] Replace cat ASCII art --- src/main/java/Mittens.java | 65 ++++++++++---------------------------- 1 file changed, 17 insertions(+), 48 deletions(-) diff --git a/src/main/java/Mittens.java b/src/main/java/Mittens.java index dab23b27c4..d8fe6c2d9c 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/Mittens.java @@ -2,42 +2,23 @@ import java.util.Scanner; public class Mittens { + + // Unfortunately we were unable to use the initial cat ASCII art due to the + // Unicode characters interfering with the UI tests. private final static String GREETING_MESSAGE = """ - ██ ██ ____________________ - ██░░██ ██░░██ / Hi, I'm Mittens! \\ - ██░░░░██████░░░░██ | I'm a cat! Meow :3 | - ██░░░░░░░░░░░░░░░░░░██ \\ How can I help? / - ██░░░░░░░░░░░░░░░░░░██ -------------------- - ██░░██░░░░░░░░██░░░░██ - ██░░██░░░░░░░░██░░░░██ ████ - ██░░░░░░░░░░░░░░░░░░██ ██ ██ - ████▒▒▒▒▒▒▒▒▒▒████ ██ ██ - ██░░▒▒▒▒░░░░░░██ ██ ██ - ██░░██░░████░░░░██ ██░░░░██ - ██░░████░░░░██░░██ ██░░░░██ - ██ ████░░░░░░░░████▒▒▒▒▒▒██ - ██ ██ ░░░░░░██▒▒▒▒████ - ██████████████████████ + /\\_/\\ ____________________ + >^,^< / Hi, I'm Mittens! \\ + / \\ \\ I'm a cat! Meow :3 / + (___)_/ -------------------- """; private final static String EXIT_MESSAGE = """ - ██ ██ _____________ - ██░░██ ██░░██ ( Bye-bye! :3 ) - ██░░░░██████░░░░██ ------------- - ██░░░░░░░░░░░░░░░░░░██ - ██░░░░░░░░░░░░░░░░░░██ - ██░░██░░░░░░░░██░░░░██ - ██░░██░░░░░░░░██░░░░██ ████ - ██░░░░░░░░░░░░░░░░░░██ ██ ██ - ████▒▒▒▒▒▒▒▒▒▒████ ██ ██ - ██░░▒▒▒▒░░░░░░██ ██ ██ - ██░░██░░████░░░░██ ██░░░░██ - ██░░████░░░░██░░██ ██░░░░██ - ██ ████░░░░░░░░████▒▒▒▒▒▒██ - ██ ██ ░░░░░░██▒▒▒▒████ - ██████████████████████ + /\\_/\\ _____________ + >^,^< ( Bye-bye! :3 ) + / \\ ------------- + (___)_/ """; private static ArrayList tasks = new ArrayList<>(); @@ -50,24 +31,12 @@ public static void echo(String command) { int len = command.length(); String message = """ - ██ ██ %s - ██░░██ ██░░██ ( %s ) - ██░░░░██████░░░░██ %s - ██░░░░░░░░░░░░░░░░░░██ - ██░░░░░░░░░░░░░░░░░░██ - ██░░██░░░░░░░░██░░░░██ - ██░░██░░░░░░░░██░░░░██ ████ - ██░░░░░░░░░░░░░░░░░░██ ██ ██ - ████▒▒▒▒▒▒▒▒▒▒████ ██ ██ - ██░░▒▒▒▒░░░░░░██ ██ ██ - ██░░██░░████░░░░██ ██░░░░██ - ██░░████░░░░██░░██ ██░░░░██ - ██ ████░░░░░░░░████▒▒▒▒▒▒██ - ██ ██ ░░░░░░██▒▒▒▒████ - ██████████████████████ - """ - .formatted("_".repeat(len + 2), - command, "-".repeat(len + 2)); + /\\_/\\ %s + >^,^< ( %s ) + / \\ %s + (___)_/ + """.formatted("_".repeat(len + 2), + command, "-".repeat(len + 2)); System.out.println(message); } From d13673b087c33323378e4069f01c1d2793518896 Mon Sep 17 00:00:00 2001 From: izruff Date: Sun, 25 Aug 2024 01:26:13 +0800 Subject: [PATCH 019/105] Add text UI testing --- text-ui-test/EXPECTED.TXT | 59 +++++++++++++++++++++++++++++++++++---- text-ui-test/input.txt | 11 ++++++++ text-ui-test/runtest.bat | 2 +- 3 files changed, 65 insertions(+), 7 deletions(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 657e74f6e7..bd96aa78dd 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,7 +1,54 @@ -Hello from - ____ _ -| _ \ _ _| | _____ -| | | | | | | |/ / _ \ -| |_| | |_| | < __/ -|____/ \__,_|_|\_\___| + + /\_/\ ____________________ + >^,^< / Hi, I'm Mittens! \ + / \ \ I'm a cat! Meow :3 / + (___)_/ -------------------- + +> +Meow?! Your list is empty! + +> +I've added "read book" to your list :3 + +> +I've added "submit assignment" to your list :3 + +> +I've added "watch movie" to your list :3 + +> +You have 3 tasks in your list, here they are :3 +1. [T][ ] read book +2. [D][ ] submit assignment (due today 3pm) +3. [E][ ] watch movie (1 Sep, 1pm -- 1 Sep, 4pm) + +> +Meow, I scratched the check box for you: +[D][X] submit assignment (due today 3pm) + +> +Meow, I scratched the check box for you: +[T][X] read book + +> +You have 3 tasks in your list, here they are :3 +1. [T][X] read book +2. [D][X] submit assignment (due today 3pm) +3. [E][ ] watch movie (1 Sep, 1pm -- 1 Sep, 4pm) + +> +Meow, I unscratched the check box for you: +[D][ ] submit assignment (due today 3pm) + +> +You have 3 tasks in your list, here they are :3 +1. [T][X] read book +2. [D][ ] submit assignment (due today 3pm) +3. [E][ ] watch movie (1 Sep, 1pm -- 1 Sep, 4pm) + +> + /\_/\ _____________ + >^,^< ( Bye-bye! :3 ) + / \ ------------- + (___)_/ diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index e69de29bb2..3820f94e0b 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -0,0 +1,11 @@ +list +todo read book +deadline submit assignment /by today 3pm +event watch movie /from 1 Sep, 1pm /to 1 Sep, 4pm +list +mark 2 +mark 1 +list +unmark 2 +list +bye diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat index 0873744649..6c400ff47b 100644 --- a/text-ui-test/runtest.bat +++ b/text-ui-test/runtest.bat @@ -15,7 +15,7 @@ IF ERRORLEVEL 1 ( REM no error here, errorlevel == 0 REM run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT -java -classpath ..\bin Duke < input.txt > ACTUAL.TXT +java -classpath ..\bin Mittens < input.txt > ACTUAL.TXT REM compare the output to the expected output FC ACTUAL.TXT EXPECTED.TXT From b838af659492de4c8d4b179bb1ce1cf60ccde9f9 Mon Sep 17 00:00:00 2001 From: izruff Date: Sun, 25 Aug 2024 07:25:18 +0800 Subject: [PATCH 020/105] Add exception classes --- src/main/java/BadInputException.java | 9 +++++++ src/main/java/MittensException.java | 35 ++++++++++++++++++++++++++++ src/main/java/UnknownException.java | 8 +++++++ 3 files changed, 52 insertions(+) create mode 100644 src/main/java/BadInputException.java create mode 100644 src/main/java/MittensException.java create mode 100644 src/main/java/UnknownException.java diff --git a/src/main/java/BadInputException.java b/src/main/java/BadInputException.java new file mode 100644 index 0000000000..7b7dc39d00 --- /dev/null +++ b/src/main/java/BadInputException.java @@ -0,0 +1,9 @@ +public class BadInputException extends MittensException { + private static final String MITTENS_MESSAGE = "Meow?! What does that mean?"; + private static final String HELP_MESSAGE = "Type 'help' to see a list of commands," + + "or 'help ' to see more about a specific command."; + + public BadInputException(String message) { + super(message, MITTENS_MESSAGE, HELP_MESSAGE); + } +} diff --git a/src/main/java/MittensException.java b/src/main/java/MittensException.java new file mode 100644 index 0000000000..ff261afeec --- /dev/null +++ b/src/main/java/MittensException.java @@ -0,0 +1,35 @@ +public class MittensException extends Exception { + private final String mittensMessage; + private final String helpMessage; + + public MittensException(String message, String mittensMessage, String helpMessage) { + super(message); + this.mittensMessage = mittensMessage; + this.helpMessage = helpMessage; + } + + public String getMittensMessage() { + return this.mittensMessage; + } + + public String getHelpMessage() { + return this.helpMessage; + } + + public void echo() { + String message = """ + + /\\_/\\ %s + >x.x< ( %s ) + / \\ %s + (___)_/ + + Error: %s + %s + """.formatted("_".repeat(this.getMittensMessage().length() + 2), + this.getMittensMessage(), "-".repeat(this.getMittensMessage().length() + 2), + this.getMessage(), this.helpMessage); + + System.out.println(message); + } +} diff --git a/src/main/java/UnknownException.java b/src/main/java/UnknownException.java new file mode 100644 index 0000000000..cd911a07b7 --- /dev/null +++ b/src/main/java/UnknownException.java @@ -0,0 +1,8 @@ +public class UnknownException extends MittensException { + private static final String MITTENS_MESSAGE = "Meow?! Something went wrong..."; + private static final String HELP_MESSAGE = "You can try again, or type 'help' to see a list of commands."; + + public UnknownException(String message) { + super(message, MITTENS_MESSAGE, HELP_MESSAGE); + } +} From 4fc57738926ed1d230239c548f0f0d37a78090fe Mon Sep 17 00:00:00 2001 From: izruff Date: Sun, 25 Aug 2024 22:34:20 +0800 Subject: [PATCH 021/105] Add basic error handling Certain errors can occur when user gives an incorrect or badly formatted input, causing the program to exit. Let's handle some of these possibilities, including, * unknown command names, flags, or arguments * missing or duplicated flags, arguments * type validation for arguments * out-of-range errors when accessing task list through `mark` or `unmark` --- src/main/java/BadInputException.java | 2 +- src/main/java/Mittens.java | 141 +++++++++++++++++++-------- src/main/java/UnknownException.java | 3 +- 3 files changed, 106 insertions(+), 40 deletions(-) diff --git a/src/main/java/BadInputException.java b/src/main/java/BadInputException.java index 7b7dc39d00..760248572a 100644 --- a/src/main/java/BadInputException.java +++ b/src/main/java/BadInputException.java @@ -1,7 +1,7 @@ public class BadInputException extends MittensException { private static final String MITTENS_MESSAGE = "Meow?! What does that mean?"; private static final String HELP_MESSAGE = "Type 'help' to see a list of commands," + - "or 'help ' to see more about a specific command."; + " or 'help ' to see more about a specific command."; public BadInputException(String message) { super(message, MITTENS_MESSAGE, HELP_MESSAGE); diff --git a/src/main/java/Mittens.java b/src/main/java/Mittens.java index d8fe6c2d9c..dfd430b128 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/Mittens.java @@ -59,13 +59,19 @@ public static void listTasks() { System.out.print("\n"); } - public static void markTaskAsDone(int index) { + public static void markTaskAsDone(int index) throws BadInputException { + if (index > tasks.size()) { + throw new BadInputException("Task index is out of range"); + } Task task = tasks.get(index - 1); task.markAsDone(); System.out.printf("\nMeow, I scratched the check box for you:\n%s\n\n", task.toString()); } - public static void markTaskAsNotDone(int index) { + public static void markTaskAsNotDone(int index) throws BadInputException { + if (index > tasks.size()) { + throw new BadInputException("Task index is out of range"); + } Task task = tasks.get(index - 1); task.markAsNotDone(); System.out.printf("\nMeow, I unscratched the check box for you:\n%s\n\n", task.toString()); @@ -84,42 +90,101 @@ public static void main(String[] args) { System.out.print("> "); String input = scanner.nextLine(); - if (input.equals("bye")) { - break; - } else if (input.equals("list")) { - listTasks(); - } else if (input.startsWith("mark")) { - int index = Integer.parseInt(input.split(" ")[1]); - markTaskAsDone(index); - } else if (input.startsWith("unmark")) { - int index = Integer.parseInt(input.split(" ")[1]); - markTaskAsNotDone(index); - } else if (input.startsWith("todo")) { - String description = input.substring(5); - - Todo newTodo = new Todo(description); - addTask(newTodo); - } else if (input.startsWith("deadline")) { - // Separate the inputs so that the first element contains the description while - // the rest contains flags. - String[] inputs = input.split(" /"); - String description = inputs[0].substring(9); - // Assuming order of flags are: by - String by = inputs[1].substring(3); - - Deadline newDeadline = new Deadline(description, by); - addTask(newDeadline); - } else if (input.startsWith("event")) { - // Separate the inputs so that the first element contains the description while - // the rest contains flags. - String[] inputs = input.split(" /"); - String description = inputs[0].substring(6); - // Assuming order of flags are: from, to - String from = inputs[1].substring(5); - String to = inputs[2].substring(3); - - Event newEvent = new Event(description, from, to); - addTask(newEvent); + try { + if (input.equals("bye")) { + break; + } else if (input.equals("list")) { + listTasks(); + } else if (input.startsWith("mark")) { + try { + int index = Integer.parseInt(input.split(" ")[1]); + markTaskAsDone(index); + } catch (NumberFormatException e) { + throw new BadInputException("Argument for command 'mark' must be a number"); + } + } else if (input.startsWith("unmark")) { + try { + int index = Integer.parseInt(input.split(" ")[1]); + markTaskAsNotDone(index); + } catch (NumberFormatException e) { + throw new BadInputException("Argument for command 'mark' must be a number"); + } + } else if (input.startsWith("todo")) { + String description = input.substring(5); + + Todo newTodo = new Todo(description); + addTask(newTodo); + } else if (input.startsWith("deadline")) { + // Separate the inputs so that the first element contains the description while + // the rest contains flags. + String[] inputs = input.split(" /"); + String description = inputs[0].substring(9); + + String by = null; + for (int i = 1; i < inputs.length; i++) { + String[] flagWords = inputs[i].split(" "); + if (flagWords[0].equals("by")) { + if (by == null) { + by = inputs[i].substring(3); + } else { + throw new BadInputException("Found duplicate of 'by' flag"); + } + } else { + throw new BadInputException("'%s' is not a known flag".formatted(flagWords[0])); + } + } + + if (by == null) { + throw new BadInputException("Command 'deadline' must have a 'by' flag"); + } + + Deadline newDeadline = new Deadline(description, by); + addTask(newDeadline); + } else if (input.startsWith("event")) { + // Separate the inputs so that the first element contains the description while + // the rest contains flags. + String[] inputs = input.split(" /"); + String description = inputs[0].substring(6); + + String from = null; + String to = null; + for (int i = 1; i < inputs.length; i++) { + String[] flagWords = inputs[i].split(" "); + if (flagWords[0].equals("from")) { + if (from == null) { + from = inputs[i].substring(5); + } else { + throw new BadInputException("Found duplicate of 'from' flag"); + } + } else if (flagWords[0].equals("to")) { + if (to == null) { + to = inputs[i].substring(3); + } else { + throw new BadInputException("Found duplicate of 'to' flag"); + } + } else { + throw new BadInputException("'%s' is not a known flag".formatted(flagWords[0])); + } + } + + if (from == null) { + throw new BadInputException("Command 'event' must have a 'from' flag"); + } + + if (to == null) { + throw new BadInputException("Command 'event' must have a 'to' flag"); + } + + Event newEvent = new Event(description, from, to); + addTask(newEvent); + } else { + throw new BadInputException("'%s' is not a known command".formatted(input)); + } + } catch (MittensException e) { + e.echo(); + } catch (Exception e) { + UnknownException newException = new UnknownException(e.getMessage()); + newException.echo(); } } diff --git a/src/main/java/UnknownException.java b/src/main/java/UnknownException.java index cd911a07b7..4cb8d36171 100644 --- a/src/main/java/UnknownException.java +++ b/src/main/java/UnknownException.java @@ -1,6 +1,7 @@ public class UnknownException extends MittensException { private static final String MITTENS_MESSAGE = "Meow?! Something went wrong..."; - private static final String HELP_MESSAGE = "You can try again, or type 'help' to see a list of commands."; + private static final String HELP_MESSAGE = "I'm not sure what went wrong. You can try again," + + " or type 'help' to see a list of commands."; public UnknownException(String message) { super(message, MITTENS_MESSAGE, HELP_MESSAGE); From 972b076dbc0fcf17ccae0c3d7500731e057004e3 Mon Sep 17 00:00:00 2001 From: izruff Date: Mon, 26 Aug 2024 00:50:54 +0800 Subject: [PATCH 022/105] Add delete task feature --- src/main/java/Mittens.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/Mittens.java b/src/main/java/Mittens.java index dfd430b128..d1fede9337 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/Mittens.java @@ -76,6 +76,14 @@ public static void markTaskAsNotDone(int index) throws BadInputException { task.markAsNotDone(); System.out.printf("\nMeow, I unscratched the check box for you:\n%s\n\n", task.toString()); } + + public static void deleteTask(int index) throws BadInputException { + if (index > tasks.size()) { + throw new BadInputException("Task index is out of range"); + } + Task task = tasks.remove(index - 1); + System.out.printf("\nMeow, I deleted the task '%s' for you :3\n\n", task.getDescription()); + } public static void exit() { System.out.println(EXIT_MESSAGE); @@ -109,6 +117,13 @@ public static void main(String[] args) { } catch (NumberFormatException e) { throw new BadInputException("Argument for command 'mark' must be a number"); } + } else if (input.startsWith("delete")) { + try { + int index = Integer.parseInt(input.split(" ")[1]); + deleteTask(index); + } catch (NumberFormatException e) { + throw new BadInputException("Argument for command 'delete' must be a number"); + } } else if (input.startsWith("todo")) { String description = input.substring(5); From 7b930d71b17fb297086ef05101674b1f819b1435 Mon Sep 17 00:00:00 2001 From: izruff Date: Tue, 27 Aug 2024 23:45:18 +0800 Subject: [PATCH 023/105] Update UI test to include delete --- text-ui-test/EXPECTED.TXT | 8 ++++++++ text-ui-test/input.txt | 2 ++ 2 files changed, 10 insertions(+) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index bd96aa78dd..23ea061cf2 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -46,6 +46,14 @@ You have 3 tasks in your list, here they are :3 2. [D][ ] submit assignment (due today 3pm) 3. [E][ ] watch movie (1 Sep, 1pm -- 1 Sep, 4pm) +> +Meow, I deleted the task 'read book' for you :3 + +> +You have 2 tasks in your list, here they are :3 +1. [D][ ] submit assignment (due today 3pm) +2. [E][ ] watch movie (1 Sep, 1pm -- 1 Sep, 4pm) + > /\_/\ _____________ >^,^< ( Bye-bye! :3 ) diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index 3820f94e0b..0723e25290 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -8,4 +8,6 @@ mark 1 list unmark 2 list +delete 1 +list bye From 2cfe70bd6fc13ea79fbce776d6a9d023b49fd5ab Mon Sep 17 00:00:00 2001 From: izruff Date: Tue, 27 Aug 2024 23:54:16 +0800 Subject: [PATCH 024/105] Update UI test to include examples of error handling --- text-ui-test/EXPECTED.TXT | 45 +++++++++++++++++++++++++++++++++++++++ text-ui-test/input.txt | 5 +++++ 2 files changed, 50 insertions(+) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 23ea061cf2..fe1ab8a504 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -16,6 +16,24 @@ I've added "submit assignment" to your list :3 > I've added "watch movie" to your list :3 +> + /\_/\ _____________________________ + >x.x< ( Meow?! What does that mean? ) + / \ ----------------------------- + (___)_/ + +Error: Command 'deadline' must have a 'by' flag +Type 'help' to see a list of commands, or 'help ' to see more about a specific command. + +> + /\_/\ _____________________________ + >x.x< ( Meow?! What does that mean? ) + / \ ----------------------------- + (___)_/ + +Error: 'by' is not a known flag +Type 'help' to see a list of commands, or 'help ' to see more about a specific command. + > You have 3 tasks in your list, here they are :3 1. [T][ ] read book @@ -36,6 +54,15 @@ You have 3 tasks in your list, here they are :3 2. [D][X] submit assignment (due today 3pm) 3. [E][ ] watch movie (1 Sep, 1pm -- 1 Sep, 4pm) +> + /\_/\ _____________________________ + >x.x< ( Meow?! What does that mean? ) + / \ ----------------------------- + (___)_/ + +Error: Task index is out of range +Type 'help' to see a list of commands, or 'help ' to see more about a specific command. + > Meow, I unscratched the check box for you: [D][ ] submit assignment (due today 3pm) @@ -46,6 +73,15 @@ You have 3 tasks in your list, here they are :3 2. [D][ ] submit assignment (due today 3pm) 3. [E][ ] watch movie (1 Sep, 1pm -- 1 Sep, 4pm) +> + /\_/\ _____________________________ + >x.x< ( Meow?! What does that mean? ) + / \ ----------------------------- + (___)_/ + +Error: Task index is out of range +Type 'help' to see a list of commands, or 'help ' to see more about a specific command. + > Meow, I deleted the task 'read book' for you :3 @@ -54,6 +90,15 @@ You have 2 tasks in your list, here they are :3 1. [D][ ] submit assignment (due today 3pm) 2. [E][ ] watch movie (1 Sep, 1pm -- 1 Sep, 4pm) +> + /\_/\ _____________________________ + >x.x< ( Meow?! What does that mean? ) + / \ ----------------------------- + (___)_/ + +Error: Task index is out of range +Type 'help' to see a list of commands, or 'help ' to see more about a specific command. + > /\_/\ _____________ >^,^< ( Bye-bye! :3 ) diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index 0723e25290..d342ad34cd 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -2,12 +2,17 @@ list todo read book deadline submit assignment /by today 3pm event watch movie /from 1 Sep, 1pm /to 1 Sep, 4pm +deadline wrong format +event wrong format /by wrong format list mark 2 mark 1 list +mark 5 unmark 2 list +unmark 4 delete 1 list +delete 3 bye From 40ac380e949e5dbf948cc6338737dc347741b82b Mon Sep 17 00:00:00 2001 From: izruff Date: Sat, 31 Aug 2024 10:30:05 +0800 Subject: [PATCH 025/105] Add TaskList class --- src/main/java/TaskList.java | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/main/java/TaskList.java diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java new file mode 100644 index 0000000000..0cfd7a35a3 --- /dev/null +++ b/src/main/java/TaskList.java @@ -0,0 +1,9 @@ +import java.util.ArrayList; + +public class TaskList { + protected ArrayList tasks; + + public TaskList() { + this.tasks = new ArrayList<>(); + } +} From 833c3a684a6fcd414a273b5e88badef07e594760 Mon Sep 17 00:00:00 2001 From: izruff Date: Sat, 31 Aug 2024 10:51:23 +0800 Subject: [PATCH 026/105] Implement TaskList partially --- src/main/java/Mittens.java | 26 +++++++++++++------------- src/main/java/TaskList.java | 18 +++++++++++++++++- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/main/java/Mittens.java b/src/main/java/Mittens.java index d1fede9337..544d802548 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/Mittens.java @@ -20,8 +20,8 @@ public class Mittens { / \\ ------------- (___)_/ """; - - private static ArrayList tasks = new ArrayList<>(); + + private final static TaskList taskList = new TaskList(); public static void greet() { System.out.println(GREETING_MESSAGE); @@ -42,46 +42,46 @@ public static void echo(String command) { } public static void addTask(Task task) { - tasks.add(task); + taskList.addTask(task); System.out.printf("\nI've added \"%s\" to your list :3\n\n", task.getDescription()); } public static void listTasks() { - if (tasks.size() == 0) { + if (taskList.getCount() == 0) { System.out.println("\nMeow?! Your list is empty!\n"); return; } - System.out.printf("\nYou have %d tasks in your list, here they are :3\n", tasks.size()); - for (int i = 0; i < tasks.size(); i++) { - Task task = tasks.get(i); + System.out.printf("\nYou have %d tasks in your list, here they are :3\n", taskList.getCount()); + for (int i = 0; i < taskList.getCount(); i++) { + Task task = taskList.getTask(i); System.out.printf("%d. %s\n", i + 1, task.toString()); } System.out.print("\n"); } public static void markTaskAsDone(int index) throws BadInputException { - if (index > tasks.size()) { + if (index > taskList.getCount()) { throw new BadInputException("Task index is out of range"); } - Task task = tasks.get(index - 1); + Task task = taskList.getTask(index - 1); task.markAsDone(); System.out.printf("\nMeow, I scratched the check box for you:\n%s\n\n", task.toString()); } public static void markTaskAsNotDone(int index) throws BadInputException { - if (index > tasks.size()) { + if (index > taskList.getCount()) { throw new BadInputException("Task index is out of range"); } - Task task = tasks.get(index - 1); + Task task = taskList.getTask(index - 1); task.markAsNotDone(); System.out.printf("\nMeow, I unscratched the check box for you:\n%s\n\n", task.toString()); } public static void deleteTask(int index) throws BadInputException { - if (index > tasks.size()) { + if (index > taskList.getCount()) { throw new BadInputException("Task index is out of range"); } - Task task = tasks.remove(index - 1); + Task task = taskList.removeTask(index - 1); System.out.printf("\nMeow, I deleted the task '%s' for you :3\n\n", task.getDescription()); } diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index 0cfd7a35a3..ea1974f121 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -1,9 +1,25 @@ import java.util.ArrayList; public class TaskList { - protected ArrayList tasks; + protected final ArrayList tasks; public TaskList() { this.tasks = new ArrayList<>(); } + + public Task getTask(int index) { + return this.tasks.get(index); + } + + public int getCount() { + return this.tasks.size(); + } + + public void addTask(Task task) { + this.tasks.add(task); + } + + public Task removeTask(int index) { + return this.tasks.remove(index); + } } From 266b31a046a065425914f1d86eabfc17e3634000 Mon Sep 17 00:00:00 2001 From: izruff Date: Sat, 31 Aug 2024 11:02:36 +0800 Subject: [PATCH 027/105] Implement save to file with Storage class --- src/main/java/Storage.java | 46 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/main/java/Storage.java diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java new file mode 100644 index 0000000000..65450cdcde --- /dev/null +++ b/src/main/java/Storage.java @@ -0,0 +1,46 @@ +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; + +public class Storage { + protected final Path filePath; + + public Storage(String filePath) { + this.filePath = Path.of(filePath); + } + + public void save(TaskList taskList) throws IOException { + try { + ArrayList encodedTasks = new ArrayList<>(); + for (Task task : taskList.tasks) { + String taskEncoding = ""; + if (task instanceof Todo) { + taskEncoding = String.format("T|%s|%s", + task.isDone ? "1" : "0", + task.description); + } else if (task instanceof Deadline) { + taskEncoding = String.format("D|%s|%s|%s", + task.isDone ? "1" : "0", + task.description, + ((Deadline) task).by); + } else if (task instanceof Event) { + taskEncoding = String.format("E|%s|%s|%s|%s", + task.isDone ? "1" : "0", + task.description, + ((Event) task).from, + ((Event) task).to); + } + encodedTasks.add(taskEncoding); + } + Files.write(this.filePath, encodedTasks, java.nio.file.StandardOpenOption.CREATE); + } catch (IOException e) { + System.out.println(e); + throw e; + } + } + + public TaskList load() { + return new TaskList(); + } +} From 7cfde522c17439336516771d86e50572260d9770 Mon Sep 17 00:00:00 2001 From: izruff Date: Sat, 31 Aug 2024 11:05:51 +0800 Subject: [PATCH 028/105] Add data folder to .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 2873e189e1..78170c854f 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ bin/ /text-ui-test/ACTUAL.TXT text-ui-test/EXPECTED-UNIX.TXT + +/data/ From 67c4c4f6971512ca5e3908fbf3b6d54cca3ae825 Mon Sep 17 00:00:00 2001 From: izruff Date: Sat, 31 Aug 2024 11:13:04 +0800 Subject: [PATCH 029/105] Implement Storage and save command on Mittens --- src/main/java/Mittens.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/Mittens.java b/src/main/java/Mittens.java index 544d802548..fc43e8da52 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/Mittens.java @@ -1,4 +1,3 @@ -import java.util.ArrayList; import java.util.Scanner; public class Mittens { @@ -22,6 +21,7 @@ public class Mittens { """; private final static TaskList taskList = new TaskList(); + private final static Storage storage = new Storage("data/data.txt"); public static void greet() { System.out.println(GREETING_MESSAGE); @@ -192,6 +192,8 @@ public static void main(String[] args) { Event newEvent = new Event(description, from, to); addTask(newEvent); + } else if (input.equals("save")) { + storage.save(taskList); } else { throw new BadInputException("'%s' is not a known command".formatted(input)); } From 0351a2f5eb98bc63401b5a34925e9439d8d7ade5 Mon Sep 17 00:00:00 2001 From: izruff Date: Sun, 1 Sep 2024 15:23:03 +0800 Subject: [PATCH 030/105] Implement Storage load on program start --- src/main/java/Mittens.java | 13 +++++++++++-- src/main/java/Storage.java | 37 +++++++++++++++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/main/java/Mittens.java b/src/main/java/Mittens.java index fc43e8da52..2afe9888d7 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/Mittens.java @@ -20,9 +20,10 @@ public class Mittens { (___)_/ """; - private final static TaskList taskList = new TaskList(); + private final static Storage storage = new Storage("data/data.txt"); - + private static TaskList taskList; + public static void greet() { System.out.println(GREETING_MESSAGE); } @@ -90,6 +91,14 @@ public static void exit() { } public static void main(String[] args) { + try { + taskList = storage.load(); + } catch (Exception e) { + UnknownException newException = new UnknownException(e.getMessage()); + newException.echo(); + taskList = new TaskList(); + } + Scanner scanner = new Scanner(System.in); greet(); diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java index 65450cdcde..bcb194605b 100644 --- a/src/main/java/Storage.java +++ b/src/main/java/Storage.java @@ -40,7 +40,40 @@ public void save(TaskList taskList) throws IOException { } } - public TaskList load() { - return new TaskList(); + public TaskList load() throws IOException { + if (!Files.exists(this.filePath)) { + Files.createFile(this.filePath); + return new TaskList(); + } + + try { + ArrayList encodedTasks = new ArrayList<>(Files.readAllLines(this.filePath)); + TaskList taskList = new TaskList(); + for (String encodedTask : encodedTasks) { + String[] taskComponents = encodedTask.split("\\|"); + Task task = null; + switch (taskComponents[0]) { + case "T": + task = new Todo(taskComponents[2]); + break; + case "D": + task = new Deadline(taskComponents[2], taskComponents[3]); + break; + case "E": + task = new Event(taskComponents[2], taskComponents[3], taskComponents[4]); + break; + default: + break; + } + if (taskComponents[1].equals("1")) { + task.markAsDone(); + } + taskList.addTask(task); + } + return taskList; + } catch (IOException e) { + System.out.println(e); + throw e; + } } } From 5f638fc0e34e657ea409f82c5049da7ab8d88296 Mon Sep 17 00:00:00 2001 From: izruff Date: Wed, 4 Sep 2024 16:12:30 +0800 Subject: [PATCH 031/105] Replace String date field on Deadline class with LocalDate --- src/main/java/Deadline.java | 10 +++++++--- src/main/java/Mittens.java | 11 +++++++++-- src/main/java/Storage.java | 8 +++++++- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java index d4d9d00e5e..09552b5bc6 100644 --- a/src/main/java/Deadline.java +++ b/src/main/java/Deadline.java @@ -1,13 +1,17 @@ +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + public class Deadline extends Task { - protected String by; + protected LocalDate by; - public Deadline(String description, String by) { + public Deadline(String description, LocalDate by) { super(description); this.by = by; } @Override public String toString() { - return "[D]" + super.toString() + " (due " + this.by + ")"; + return "[D]" + super.toString() + " (due " + + this.by.format(DateTimeFormatter.ofPattern("MMM d, yyyy")) + ")"; } } diff --git a/src/main/java/Mittens.java b/src/main/java/Mittens.java index 2afe9888d7..4895bf1f5a 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/Mittens.java @@ -1,5 +1,8 @@ +import java.time.LocalDate; +import java.time.format.DateTimeParseException; import java.util.Scanner; + public class Mittens { // Unfortunately we were unable to use the initial cat ASCII art due to the @@ -144,12 +147,16 @@ public static void main(String[] args) { String[] inputs = input.split(" /"); String description = inputs[0].substring(9); - String by = null; + LocalDate by = null; for (int i = 1; i < inputs.length; i++) { String[] flagWords = inputs[i].split(" "); if (flagWords[0].equals("by")) { if (by == null) { - by = inputs[i].substring(3); + try { + by = LocalDate.parse(inputs[i].substring(3)); + } catch (DateTimeParseException e) { + throw new BadInputException("Invalid date format for 'by' flag"); + } } else { throw new BadInputException("Found duplicate of 'by' flag"); } diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java index bcb194605b..abced2fadf 100644 --- a/src/main/java/Storage.java +++ b/src/main/java/Storage.java @@ -1,6 +1,8 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.time.LocalDate; +import java.time.format.DateTimeParseException; import java.util.ArrayList; public class Storage { @@ -57,7 +59,7 @@ public TaskList load() throws IOException { task = new Todo(taskComponents[2]); break; case "D": - task = new Deadline(taskComponents[2], taskComponents[3]); + task = new Deadline(taskComponents[2], LocalDate.parse(taskComponents[3])); break; case "E": task = new Event(taskComponents[2], taskComponents[3], taskComponents[4]); @@ -74,6 +76,10 @@ public TaskList load() throws IOException { } catch (IOException e) { System.out.println(e); throw e; + } catch (DateTimeParseException e) { + // TODO: Handle this exception + System.out.println(e); + throw e; } } } From f44fa76cfeb416e32e6304c1a8a826c755dd1df0 Mon Sep 17 00:00:00 2001 From: izruff Date: Wed, 4 Sep 2024 16:19:07 +0800 Subject: [PATCH 032/105] Replace String date fields on Event class with LocalDate --- src/main/java/Event.java | 13 +++++++++---- src/main/java/Mittens.java | 16 ++++++++++++---- src/main/java/Storage.java | 3 ++- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/main/java/Event.java b/src/main/java/Event.java index a02ae02d5d..2bef586ec7 100644 --- a/src/main/java/Event.java +++ b/src/main/java/Event.java @@ -1,8 +1,11 @@ +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + public class Event extends Task { - protected String from; - protected String to; + protected LocalDate from; + protected LocalDate to; - public Event(String description, String from, String to) { + public Event(String description, LocalDate from, LocalDate to) { super(description); this.from = from; this.to = to; @@ -10,6 +13,8 @@ public Event(String description, String from, String to) { @Override public String toString() { - return "[E]" + super.toString() + " (" + this.from + " -- " + this.to + ")"; + return "[E]" + super.toString() + " (" + + this.from.format(DateTimeFormatter.ofPattern("MMM d, yyyy")) + " -- " + + this.to.format(DateTimeFormatter.ofPattern("MMM d, yyyy")) + ")"; } } diff --git a/src/main/java/Mittens.java b/src/main/java/Mittens.java index 4895bf1f5a..ca42d72351 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/Mittens.java @@ -177,19 +177,27 @@ public static void main(String[] args) { String[] inputs = input.split(" /"); String description = inputs[0].substring(6); - String from = null; - String to = null; + LocalDate from = null; + LocalDate to = null; for (int i = 1; i < inputs.length; i++) { String[] flagWords = inputs[i].split(" "); if (flagWords[0].equals("from")) { if (from == null) { - from = inputs[i].substring(5); + try { + from = LocalDate.parse(inputs[i].substring(5)); + } catch (DateTimeParseException e) { + throw new BadInputException("Invalid date format for 'from' flag"); + } } else { throw new BadInputException("Found duplicate of 'from' flag"); } } else if (flagWords[0].equals("to")) { if (to == null) { - to = inputs[i].substring(3); + try { + to = LocalDate.parse(inputs[i].substring(3)); + } catch (DateTimeParseException e) { + throw new BadInputException("Invalid date format for 'to' flag"); + } } else { throw new BadInputException("Found duplicate of 'to' flag"); } diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java index abced2fadf..c2e5ec64e5 100644 --- a/src/main/java/Storage.java +++ b/src/main/java/Storage.java @@ -62,7 +62,8 @@ public TaskList load() throws IOException { task = new Deadline(taskComponents[2], LocalDate.parse(taskComponents[3])); break; case "E": - task = new Event(taskComponents[2], taskComponents[3], taskComponents[4]); + task = new Event(taskComponents[2], LocalDate.parse(taskComponents[3]), + LocalDate.parse(taskComponents[4])); break; default: break; From 790aea287dde0b85a1e0ff80ac858af6a06e1e3b Mon Sep 17 00:00:00 2001 From: izruff Date: Thu, 5 Sep 2024 13:56:01 +0800 Subject: [PATCH 033/105] Add TextUi class --- src/main/java/TextUi.java | 90 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 src/main/java/TextUi.java diff --git a/src/main/java/TextUi.java b/src/main/java/TextUi.java new file mode 100644 index 0000000000..153596dacc --- /dev/null +++ b/src/main/java/TextUi.java @@ -0,0 +1,90 @@ +import java.io.InputStream; +import java.io.PrintStream; +import java.util.Scanner; + +public class TextUi { + private final static String GREETING_MESSAGE = """ + /\\_/\\ ____________________ + >^,^< / Hi, I'm Mittens! \\ + / \\ \\ I'm a cat! Meow :3 / + (___)_/ -------------------- + """; + + private final static String EXIT_MESSAGE = """ + /\\_/\\ _____________ + >^,^< ( Bye-bye! :3 ) + / \\ ------------- + (___)_/ + """; + + private final Scanner in; + private final PrintStream out; + + public TextUi() { + this(System.in, System.out); + } + + public TextUi(InputStream in, PrintStream out) { + this.in = new Scanner(in); + this.out = out; + } + + public void printGreetingMessage() { + this.printBlankLine(); + this.out.println(GREETING_MESSAGE); + this.printBlankLine(); + } + + public void printExitMessage() { + this.printBlankLine(); + this.out.println(EXIT_MESSAGE); + this.printBlankLine(); + } + + public void printMessage(String message) { + this.out.println(message); + } + + public void printBlankLine() { + this.out.println(); + } + + public void printMittens(String message) { + int len = message.length(); + String uiMessage = """ + /\\_/\\ %s + >^,^< ( %s ) + / \\ %s + (___)_/ + """.formatted("_".repeat(len + 2), + message, "-".repeat(len + 2)); + + this.out.println(uiMessage); + } + + public void printErrorMessage(MittensException e) { + String mittensMessage = e.getMittensMessage(); + int len = mittensMessage.length(); + + String helpMessage = e.getHelpMessage(); + String errorMessage = e.getMessage(); + + String uiMessage = """ + /\\_/\\ %s + >x.x< ( %s ) + / \\ %s + (___)_/ + + Error: %s + %s + """.formatted("_".repeat(len + 2), mittensMessage, + "-".repeat(len + 2), errorMessage, helpMessage); + + this.out.println(uiMessage); + } + + public String getUserInput() { + this.out.print("> "); + return this.in.nextLine(); + } +} From d64de43fe6baea06dd9a60e1004ee834e31042fe Mon Sep 17 00:00:00 2001 From: izruff Date: Thu, 5 Sep 2024 14:40:41 +0800 Subject: [PATCH 034/105] Add abstract Ui class to inherit TextUi --- src/main/java/TextUi.java | 2 +- src/main/java/Ui.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 src/main/java/Ui.java diff --git a/src/main/java/TextUi.java b/src/main/java/TextUi.java index 153596dacc..24f2ec4b28 100644 --- a/src/main/java/TextUi.java +++ b/src/main/java/TextUi.java @@ -2,7 +2,7 @@ import java.io.PrintStream; import java.util.Scanner; -public class TextUi { +public class TextUi extends Ui { private final static String GREETING_MESSAGE = """ /\\_/\\ ____________________ >^,^< / Hi, I'm Mittens! \\ diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java new file mode 100644 index 0000000000..3274de790d --- /dev/null +++ b/src/main/java/Ui.java @@ -0,0 +1,2 @@ +public abstract class Ui { +} From 100f96b5d5e795e90d01c229a74bb799a90400f5 Mon Sep 17 00:00:00 2001 From: izruff Date: Thu, 5 Sep 2024 21:50:59 +0800 Subject: [PATCH 035/105] Add abstract Ui class to inherit TextUi --- src/main/java/TextUi.java | 17 ++++++++++++----- src/main/java/Ui.java | 3 +++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/main/java/TextUi.java b/src/main/java/TextUi.java index 24f2ec4b28..54159038ff 100644 --- a/src/main/java/TextUi.java +++ b/src/main/java/TextUi.java @@ -61,14 +61,20 @@ public void printMittens(String message) { this.out.println(uiMessage); } - - public void printErrorMessage(MittensException e) { + + @Override + public void showCommandCompletion(Command c) { + // TODO + } + + @Override + public void showError(MittensException e) { String mittensMessage = e.getMittensMessage(); int len = mittensMessage.length(); - + String helpMessage = e.getHelpMessage(); String errorMessage = e.getMessage(); - + String uiMessage = """ /\\_/\\ %s >x.x< ( %s ) @@ -82,7 +88,8 @@ public void printErrorMessage(MittensException e) { this.out.println(uiMessage); } - + + @Override public String getUserInput() { this.out.print("> "); return this.in.nextLine(); diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java index 3274de790d..cf3ede3ad5 100644 --- a/src/main/java/Ui.java +++ b/src/main/java/Ui.java @@ -1,2 +1,5 @@ public abstract class Ui { + public abstract void showCommandCompletion(Command c); + public abstract void showError(MittensException e); + public abstract String getUserInput(); } From 6cecc3c50e8d0b4a7f12c2391034eb09c7395cee Mon Sep 17 00:00:00 2001 From: izruff Date: Thu, 5 Sep 2024 22:43:39 +0800 Subject: [PATCH 036/105] Add abstract Command class --- src/main/java/Command.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/main/java/Command.java diff --git a/src/main/java/Command.java b/src/main/java/Command.java new file mode 100644 index 0000000000..aa21a1dc6a --- /dev/null +++ b/src/main/java/Command.java @@ -0,0 +1,16 @@ +public abstract class Command { + protected boolean isExit; + protected T result; + protected MittensException error; + + public Command() { + this.isExit = false; + this.result = null; + this.error = null; + } + + public abstract void execute(TaskList tasks, Ui ui, Storage storage); + public boolean isExit() { + return this.isExit; + } +} From 8d684da3b39af80a168892c9dad61418be94cf2f Mon Sep 17 00:00:00 2001 From: izruff Date: Thu, 5 Sep 2024 22:44:56 +0800 Subject: [PATCH 037/105] Add StorageFileException class and handle errors in save and load methods --- src/main/java/Storage.java | 23 ++++++++++++----------- src/main/java/StorageFileException.java | 9 +++++++++ 2 files changed, 21 insertions(+), 11 deletions(-) create mode 100644 src/main/java/StorageFileException.java diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java index c2e5ec64e5..61e6862f02 100644 --- a/src/main/java/Storage.java +++ b/src/main/java/Storage.java @@ -12,7 +12,7 @@ public Storage(String filePath) { this.filePath = Path.of(filePath); } - public void save(TaskList taskList) throws IOException { + public void save(TaskList taskList) throws StorageFileException { try { ArrayList encodedTasks = new ArrayList<>(); for (Task task : taskList.tasks) { @@ -37,14 +37,18 @@ public void save(TaskList taskList) throws IOException { } Files.write(this.filePath, encodedTasks, java.nio.file.StandardOpenOption.CREATE); } catch (IOException e) { - System.out.println(e); - throw e; + throw new StorageFileException("Unable to write to storage file"); } } - public TaskList load() throws IOException { + public TaskList load() throws StorageFileException { if (!Files.exists(this.filePath)) { - Files.createFile(this.filePath); + try { + Files.createDirectories(this.filePath.getParent()); + Files.createFile(this.filePath); + } catch (IOException e) { + throw new StorageFileException("Unable to create storage file"); + } return new TaskList(); } @@ -66,7 +70,7 @@ public TaskList load() throws IOException { LocalDate.parse(taskComponents[4])); break; default: - break; + throw new StorageFileException("Corrupted storage file"); } if (taskComponents[1].equals("1")) { task.markAsDone(); @@ -75,12 +79,9 @@ public TaskList load() throws IOException { } return taskList; } catch (IOException e) { - System.out.println(e); - throw e; + throw new StorageFileException("Unable to read from storage file"); } catch (DateTimeParseException e) { - // TODO: Handle this exception - System.out.println(e); - throw e; + throw new StorageFileException("Corrupted storage file"); } } } diff --git a/src/main/java/StorageFileException.java b/src/main/java/StorageFileException.java new file mode 100644 index 0000000000..a055e8e3b3 --- /dev/null +++ b/src/main/java/StorageFileException.java @@ -0,0 +1,9 @@ +public class StorageFileException extends MittensException { + private static final String MITTENS_MESSAGE = "Meow?! Something's wrong with your storage!"; + private static final String HELP_MESSAGE = "Your storage might be corrupted. " + + "Try clearing the data folder and restarting the program."; + + public StorageFileException(String message) { + super(message, MITTENS_MESSAGE, HELP_MESSAGE); + } +} From 0d99b063ec1ba235efa046b9bab4ad9d75740027 Mon Sep 17 00:00:00 2001 From: izruff Date: Thu, 5 Sep 2024 23:01:41 +0800 Subject: [PATCH 038/105] Add InitializationException and handle possible errors --- src/main/java/InitializationException.java | 8 ++++++++ src/main/java/Mittens.java | 18 ++++++++++++++---- 2 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 src/main/java/InitializationException.java diff --git a/src/main/java/InitializationException.java b/src/main/java/InitializationException.java new file mode 100644 index 0000000000..af2ec078dd --- /dev/null +++ b/src/main/java/InitializationException.java @@ -0,0 +1,8 @@ +public class InitializationException extends MittensException { + private static final String MITTENS_MESSAGE = "Something is preventing me from starting..."; + private static final String HELP_MESSAGE = "This is most likely a bug in the software."; + + public InitializationException(String message) { + super(message, MITTENS_MESSAGE, HELP_MESSAGE); + } +} diff --git a/src/main/java/Mittens.java b/src/main/java/Mittens.java index ca42d72351..8c89c63cdf 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/Mittens.java @@ -94,16 +94,26 @@ public static void exit() { } public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + try { taskList = storage.load(); + } catch (StorageFileException e) { + e.echo(); + + System.out.print("Would you like to continue with a new list instead? (y/n)\n> "); + String input = scanner.nextLine(); + if (input.equals("y")) { + taskList = new TaskList(); + } else { + return; + } } catch (Exception e) { - UnknownException newException = new UnknownException(e.getMessage()); + InitializationException newException = new InitializationException(e.getMessage()); newException.echo(); - taskList = new TaskList(); + return; } - Scanner scanner = new Scanner(System.in); - greet(); while (true) { From 696e9baa990ccbce8ad8c940e2b9e7bbcbc79dc1 Mon Sep 17 00:00:00 2001 From: izruff Date: Thu, 5 Sep 2024 23:06:06 +0800 Subject: [PATCH 039/105] Fix typo in showCommandCompletion --- src/main/java/TextUi.java | 2 +- src/main/java/Ui.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/TextUi.java b/src/main/java/TextUi.java index 54159038ff..4282b3310f 100644 --- a/src/main/java/TextUi.java +++ b/src/main/java/TextUi.java @@ -63,7 +63,7 @@ public void printMittens(String message) { } @Override - public void showCommandCompletion(Command c) { + public void showCommandCompletion(Command c) { // TODO } diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java index cf3ede3ad5..7d0737601a 100644 --- a/src/main/java/Ui.java +++ b/src/main/java/Ui.java @@ -1,5 +1,5 @@ public abstract class Ui { - public abstract void showCommandCompletion(Command c); + public abstract void showCommandCompletion(Command c); public abstract void showError(MittensException e); public abstract String getUserInput(); } From 5b91e9d54361facfbb1c87cda563e2860934393c Mon Sep 17 00:00:00 2001 From: izruff Date: Thu, 5 Sep 2024 23:52:34 +0800 Subject: [PATCH 040/105] Refactor Mittens to use TaskList methods --- src/main/java/Mittens.java | 32 +++++++++++++++++++------------- src/main/java/TaskList.java | 21 +++++++++++++++++++-- 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/src/main/java/Mittens.java b/src/main/java/Mittens.java index 8c89c63cdf..2a8ae26fac 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/Mittens.java @@ -1,5 +1,6 @@ import java.time.LocalDate; import java.time.format.DateTimeParseException; +import java.util.List; import java.util.Scanner; @@ -56,37 +57,42 @@ public static void listTasks() { return; } System.out.printf("\nYou have %d tasks in your list, here they are :3\n", taskList.getCount()); - for (int i = 0; i < taskList.getCount(); i++) { - Task task = taskList.getTask(i); + List tasks = taskList.getTasks(); + for (int i = 0; i < tasks.size(); i++) { + Task task = tasks.get(i); System.out.printf("%d. %s\n", i + 1, task.toString()); } System.out.print("\n"); } public static void markTaskAsDone(int index) throws BadInputException { - if (index > taskList.getCount()) { + try { + Task task = taskList.markTaskAsDone(index - 1); + System.out.printf("\nMeow, I scratched the check box for you:\n%s\n\n", task.toString()); + } catch (IndexOutOfBoundsException e) { + // TODO: Define custom exceptions for TaskList operations throw new BadInputException("Task index is out of range"); } - Task task = taskList.getTask(index - 1); - task.markAsDone(); - System.out.printf("\nMeow, I scratched the check box for you:\n%s\n\n", task.toString()); } public static void markTaskAsNotDone(int index) throws BadInputException { - if (index > taskList.getCount()) { + try { + Task task = taskList.markTaskAsNotDone(index - 1); + System.out.printf("\nMeow, I unscratched the check box for you:\n%s\n\n", task.toString()); + } catch (IndexOutOfBoundsException e) { + // TODO: Define custom exceptions for TaskList operations throw new BadInputException("Task index is out of range"); } - Task task = taskList.getTask(index - 1); - task.markAsNotDone(); - System.out.printf("\nMeow, I unscratched the check box for you:\n%s\n\n", task.toString()); } public static void deleteTask(int index) throws BadInputException { - if (index > taskList.getCount()) { + try { + Task task = taskList.deleteTask(index - 1); + System.out.printf("\nMeow, I deleted the task '%s' for you :3\n\n", task.getDescription()); + } catch (IndexOutOfBoundsException e) { + // TODO: Define custom exceptions for TaskList operations throw new BadInputException("Task index is out of range"); } - Task task = taskList.removeTask(index - 1); - System.out.printf("\nMeow, I deleted the task '%s' for you :3\n\n", task.getDescription()); } public static void exit() { diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index ea1974f121..95b0d7bd1d 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -1,4 +1,5 @@ import java.util.ArrayList; +import java.util.List; public class TaskList { protected final ArrayList tasks; @@ -6,7 +7,11 @@ public class TaskList { public TaskList() { this.tasks = new ArrayList<>(); } - + + public List getTasks() { + return this.tasks; + } + public Task getTask(int index) { return this.tasks.get(index); } @@ -19,7 +24,19 @@ public void addTask(Task task) { this.tasks.add(task); } - public Task removeTask(int index) { + public Task markTaskAsDone(int index) { + Task task = this.tasks.get(index); + task.markAsDone(); + return task; + } + + public Task markTaskAsNotDone(int index) { + Task task = this.tasks.get(index); + task.markAsNotDone(); + return task; + } + + public Task deleteTask(int index) { return this.tasks.remove(index); } } From f843463797e03ea3d88aaab60ae86997cc1da441 Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 01:07:05 +0800 Subject: [PATCH 041/105] Rewrite Ui class and implement methods in TextUi --- src/main/java/TextUi.java | 64 ++++++++++++++++++++++++++------------- src/main/java/Ui.java | 9 ++++-- 2 files changed, 50 insertions(+), 23 deletions(-) diff --git a/src/main/java/TextUi.java b/src/main/java/TextUi.java index 4282b3310f..ad65d57b88 100644 --- a/src/main/java/TextUi.java +++ b/src/main/java/TextUi.java @@ -1,5 +1,6 @@ import java.io.InputStream; import java.io.PrintStream; +import java.util.List; import java.util.Scanner; public class TextUi extends Ui { @@ -10,7 +11,7 @@ public class TextUi extends Ui { (___)_/ -------------------- """; - private final static String EXIT_MESSAGE = """ + private final static String GOODBYE_MESSAGE = """ /\\_/\\ _____________ >^,^< ( Bye-bye! :3 ) / \\ ------------- @@ -29,18 +30,6 @@ public TextUi(InputStream in, PrintStream out) { this.out = out; } - public void printGreetingMessage() { - this.printBlankLine(); - this.out.println(GREETING_MESSAGE); - this.printBlankLine(); - } - - public void printExitMessage() { - this.printBlankLine(); - this.out.println(EXIT_MESSAGE); - this.printBlankLine(); - } - public void printMessage(String message) { this.out.println(message); } @@ -61,14 +50,8 @@ public void printMittens(String message) { this.out.println(uiMessage); } - - @Override - public void showCommandCompletion(Command c) { - // TODO - } - - @Override - public void showError(MittensException e) { + + public void printErrorMessage(MittensException e) { String mittensMessage = e.getMittensMessage(); int len = mittensMessage.length(); @@ -89,6 +72,45 @@ public void showError(MittensException e) { this.out.println(uiMessage); } + @Override + public void showGreetingMessage() { + this.printBlankLine(); + this.out.println(GREETING_MESSAGE); + this.printBlankLine(); + } + + @Override + public void showGoodbyeMessage() { + this.printBlankLine(); + this.out.println(GOODBYE_MESSAGE); + this.printBlankLine(); + } + + @Override + public void showRegularMessage(List messages) { + this.printBlankLine(); + for (String message : messages) { + this.printMessage(message); + } + this.printBlankLine(); + } + + @Override + public void showMittensMessage(List messages) { + this.printBlankLine(); + for (String message : messages) { + this.printMittens(message); + this.printBlankLine(); + } + } + + @Override + public void showErrorMessage(MittensException e) { + this.printBlankLine(); + this.printErrorMessage(e); + this.printBlankLine(); + } + @Override public String getUserInput() { this.out.print("> "); diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java index 7d0737601a..a230a33c09 100644 --- a/src/main/java/Ui.java +++ b/src/main/java/Ui.java @@ -1,5 +1,10 @@ +import java.util.List; + public abstract class Ui { - public abstract void showCommandCompletion(Command c); - public abstract void showError(MittensException e); + public abstract void showGreetingMessage(); + public abstract void showGoodbyeMessage(); + public abstract void showRegularMessage(List messages); + public abstract void showMittensMessage(List messages); + public abstract void showErrorMessage(MittensException e); public abstract String getUserInput(); } From 9d36f6231f92767bdf837951a473e4d655bd1689 Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 01:37:01 +0800 Subject: [PATCH 042/105] Add command subclass for adding a new task --- src/main/java/AddCommand.java | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/main/java/AddCommand.java diff --git a/src/main/java/AddCommand.java b/src/main/java/AddCommand.java new file mode 100644 index 0000000000..d32759c3cb --- /dev/null +++ b/src/main/java/AddCommand.java @@ -0,0 +1,27 @@ +import java.util.ArrayList; +import java.util.List; + +public class AddCommand extends Command { + protected Task toAdd; + + public AddCommand(Task toAdd) { + this.toAdd = toAdd; + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + try { + tasks.addTask(toAdd); + this.result = toAdd; + + storage.save(tasks); + + List messages = new ArrayList(); + messages.add("I've added \"%s\" to your list :3" + .formatted(toAdd.getDescription())); + ui.showRegularMessage(messages); + } catch (MittensException e) { + ui.showErrorMessage(e); + } + } +} From f90170a9f4754282be37b87544e13434b35e345f Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 01:37:10 +0800 Subject: [PATCH 043/105] Partially implement Command and refactor Mittens The Mittens class violates the SLAP principle. The Command class, along with TaskList, Ui, and Storage aims to fix this. This commit serves as confirmation that the prototype AddCommand class works as expected. --- src/main/java/Mittens.java | 61 ++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/src/main/java/Mittens.java b/src/main/java/Mittens.java index 2a8ae26fac..75e02ec38b 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/Mittens.java @@ -25,14 +25,21 @@ public class Mittens { """; - private final static Storage storage = new Storage("data/data.txt"); - private static TaskList taskList; + private Ui ui; + private Storage storage; + private TaskList taskList; - public static void greet() { + public Mittens(String storageFilePath) { + this.ui = new TextUi(); + this.storage = new Storage(storageFilePath); + this.taskList = new TaskList(); + } + + public void greet() { System.out.println(GREETING_MESSAGE); } - public static void echo(String command) { + public void echo(String command) { int len = command.length(); String message = """ @@ -46,18 +53,18 @@ public static void echo(String command) { System.out.println(message); } - public static void addTask(Task task) { - taskList.addTask(task); + public void addTask(Task task) { + this.taskList.addTask(task); System.out.printf("\nI've added \"%s\" to your list :3\n\n", task.getDescription()); } - public static void listTasks() { - if (taskList.getCount() == 0) { + public void listTasks() { + if (this.taskList.getCount() == 0) { System.out.println("\nMeow?! Your list is empty!\n"); return; } - System.out.printf("\nYou have %d tasks in your list, here they are :3\n", taskList.getCount()); - List tasks = taskList.getTasks(); + System.out.printf("\nYou have %d tasks in your list, here they are :3\n", this.taskList.getCount()); + List tasks = this.taskList.getTasks(); for (int i = 0; i < tasks.size(); i++) { Task task = tasks.get(i); System.out.printf("%d. %s\n", i + 1, task.toString()); @@ -65,9 +72,9 @@ public static void listTasks() { System.out.print("\n"); } - public static void markTaskAsDone(int index) throws BadInputException { + public void markTaskAsDone(int index) throws BadInputException { try { - Task task = taskList.markTaskAsDone(index - 1); + Task task = this.taskList.markTaskAsDone(index - 1); System.out.printf("\nMeow, I scratched the check box for you:\n%s\n\n", task.toString()); } catch (IndexOutOfBoundsException e) { // TODO: Define custom exceptions for TaskList operations @@ -75,9 +82,9 @@ public static void markTaskAsDone(int index) throws BadInputException { } } - public static void markTaskAsNotDone(int index) throws BadInputException { + public void markTaskAsNotDone(int index) throws BadInputException { try { - Task task = taskList.markTaskAsNotDone(index - 1); + Task task = this.taskList.markTaskAsNotDone(index - 1); System.out.printf("\nMeow, I unscratched the check box for you:\n%s\n\n", task.toString()); } catch (IndexOutOfBoundsException e) { // TODO: Define custom exceptions for TaskList operations @@ -85,9 +92,9 @@ public static void markTaskAsNotDone(int index) throws BadInputException { } } - public static void deleteTask(int index) throws BadInputException { + public void deleteTask(int index) throws BadInputException { try { - Task task = taskList.deleteTask(index - 1); + Task task = this.taskList.deleteTask(index - 1); System.out.printf("\nMeow, I deleted the task '%s' for you :3\n\n", task.getDescription()); } catch (IndexOutOfBoundsException e) { // TODO: Define custom exceptions for TaskList operations @@ -99,18 +106,18 @@ public static void exit() { System.out.println(EXIT_MESSAGE); } - public static void main(String[] args) { + public void run() { Scanner scanner = new Scanner(System.in); try { - taskList = storage.load(); + this.taskList = this.storage.load(); } catch (StorageFileException e) { e.echo(); System.out.print("Would you like to continue with a new list instead? (y/n)\n> "); String input = scanner.nextLine(); if (input.equals("y")) { - taskList = new TaskList(); + this.taskList = new TaskList(); } else { return; } @@ -156,7 +163,8 @@ public static void main(String[] args) { String description = input.substring(5); Todo newTodo = new Todo(description); - addTask(newTodo); + AddCommand command = new AddCommand(newTodo); + command.execute(this.taskList, this.ui, this.storage); } else if (input.startsWith("deadline")) { // Separate the inputs so that the first element contains the description while // the rest contains flags. @@ -186,7 +194,8 @@ public static void main(String[] args) { } Deadline newDeadline = new Deadline(description, by); - addTask(newDeadline); + AddCommand command = new AddCommand(newDeadline); + command.execute(this.taskList, this.ui, this.storage); } else if (input.startsWith("event")) { // Separate the inputs so that the first element contains the description while // the rest contains flags. @@ -231,9 +240,10 @@ public static void main(String[] args) { } Event newEvent = new Event(description, from, to); - addTask(newEvent); + AddCommand command = new AddCommand(newEvent); + command.execute(this.taskList, this.ui, this.storage); } else if (input.equals("save")) { - storage.save(taskList); + this.storage.save(this.taskList); } else { throw new BadInputException("'%s' is not a known command".formatted(input)); } @@ -247,4 +257,9 @@ public static void main(String[] args) { exit(); } + + public static void main(String[] args) { + Mittens mittens = new Mittens("data/data.txt"); + mittens.run(); + } } From a66297a36215792da3e413021887331d6fecfdcb Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 01:55:17 +0800 Subject: [PATCH 044/105] Make small changes for style consistency --- src/main/java/AddCommand.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/AddCommand.java b/src/main/java/AddCommand.java index d32759c3cb..b56ffc1831 100644 --- a/src/main/java/AddCommand.java +++ b/src/main/java/AddCommand.java @@ -11,14 +11,14 @@ public AddCommand(Task toAdd) { @Override public void execute(TaskList tasks, Ui ui, Storage storage) { try { - tasks.addTask(toAdd); - this.result = toAdd; + tasks.addTask(this.toAdd); + this.result = this.toAdd; storage.save(tasks); List messages = new ArrayList(); messages.add("I've added \"%s\" to your list :3" - .formatted(toAdd.getDescription())); + .formatted(this.result.getDescription())); ui.showRegularMessage(messages); } catch (MittensException e) { ui.showErrorMessage(e); From 545433510a136ed18b374ca93f936fc231d1236e Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 01:57:57 +0800 Subject: [PATCH 045/105] Overload showRegularMessage method for convenience --- src/main/java/AddCommand.java | 4 +--- src/main/java/TextUi.java | 7 +++++++ src/main/java/Ui.java | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/main/java/AddCommand.java b/src/main/java/AddCommand.java index b56ffc1831..3851d04cb8 100644 --- a/src/main/java/AddCommand.java +++ b/src/main/java/AddCommand.java @@ -16,10 +16,8 @@ public void execute(TaskList tasks, Ui ui, Storage storage) { storage.save(tasks); - List messages = new ArrayList(); - messages.add("I've added \"%s\" to your list :3" + ui.showRegularMessage("I've added \"%s\" to your list :3" .formatted(this.result.getDescription())); - ui.showRegularMessage(messages); } catch (MittensException e) { ui.showErrorMessage(e); } diff --git a/src/main/java/TextUi.java b/src/main/java/TextUi.java index ad65d57b88..537c7e39e3 100644 --- a/src/main/java/TextUi.java +++ b/src/main/java/TextUi.java @@ -95,6 +95,13 @@ public void showRegularMessage(List messages) { this.printBlankLine(); } + @Override + public void showRegularMessage(String message) { + this.printBlankLine(); + this.printMessage(message); + this.printBlankLine(); + } + @Override public void showMittensMessage(List messages) { this.printBlankLine(); diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java index a230a33c09..449fa420cb 100644 --- a/src/main/java/Ui.java +++ b/src/main/java/Ui.java @@ -4,6 +4,7 @@ public abstract class Ui { public abstract void showGreetingMessage(); public abstract void showGoodbyeMessage(); public abstract void showRegularMessage(List messages); + public abstract void showRegularMessage(String message); public abstract void showMittensMessage(List messages); public abstract void showErrorMessage(MittensException e); public abstract String getUserInput(); From 42cb70cc676ce2418872ff5f546c6ba0f1ac9a9c Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 01:58:51 +0800 Subject: [PATCH 046/105] Add command subclass for deleting a task --- src/main/java/DeleteCommand.java | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/main/java/DeleteCommand.java diff --git a/src/main/java/DeleteCommand.java b/src/main/java/DeleteCommand.java new file mode 100644 index 0000000000..4db53acb5d --- /dev/null +++ b/src/main/java/DeleteCommand.java @@ -0,0 +1,24 @@ +import java.util.ArrayList; +import java.util.List; + +public class DeleteCommand extends Command { + protected int index; + + public DeleteCommand(int index) { + this.index = index; + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + try { + this.result = tasks.deleteTask(this.index); + + storage.save(tasks); + + ui.showRegularMessage("Meow, I deleted the task '%s' for you :3" + .formatted(this.result.getDescription())); + } catch (MittensException e) { + ui.showErrorMessage(e); + } + } +} From 18f66e674d86b51421b03e4bccb2543cb10642fc Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 02:21:31 +0800 Subject: [PATCH 047/105] Modify Command and its subclasses Several fixes and nits are included here: * remove redundant fields result and error * remove type parameter from Command class * add missing call to super's constructor\ * remove unused imports --- src/main/java/AddCommand.java | 9 +++------ src/main/java/Command.java | 6 +----- src/main/java/DeleteCommand.java | 12 +++++------- 3 files changed, 9 insertions(+), 18 deletions(-) diff --git a/src/main/java/AddCommand.java b/src/main/java/AddCommand.java index 3851d04cb8..4406a7a316 100644 --- a/src/main/java/AddCommand.java +++ b/src/main/java/AddCommand.java @@ -1,10 +1,8 @@ -import java.util.ArrayList; -import java.util.List; - -public class AddCommand extends Command { +public class AddCommand extends Command { protected Task toAdd; public AddCommand(Task toAdd) { + super(); this.toAdd = toAdd; } @@ -12,12 +10,11 @@ public AddCommand(Task toAdd) { public void execute(TaskList tasks, Ui ui, Storage storage) { try { tasks.addTask(this.toAdd); - this.result = this.toAdd; storage.save(tasks); ui.showRegularMessage("I've added \"%s\" to your list :3" - .formatted(this.result.getDescription())); + .formatted(this.toAdd.getDescription())); } catch (MittensException e) { ui.showErrorMessage(e); } diff --git a/src/main/java/Command.java b/src/main/java/Command.java index aa21a1dc6a..6cf663d62d 100644 --- a/src/main/java/Command.java +++ b/src/main/java/Command.java @@ -1,12 +1,8 @@ -public abstract class Command { +public abstract class Command { protected boolean isExit; - protected T result; - protected MittensException error; public Command() { this.isExit = false; - this.result = null; - this.error = null; } public abstract void execute(TaskList tasks, Ui ui, Storage storage); diff --git a/src/main/java/DeleteCommand.java b/src/main/java/DeleteCommand.java index 4db53acb5d..39e1c4e530 100644 --- a/src/main/java/DeleteCommand.java +++ b/src/main/java/DeleteCommand.java @@ -1,22 +1,20 @@ -import java.util.ArrayList; -import java.util.List; - -public class DeleteCommand extends Command { +public class DeleteCommand extends Command { protected int index; public DeleteCommand(int index) { + super(); this.index = index; } @Override public void execute(TaskList tasks, Ui ui, Storage storage) { try { - this.result = tasks.deleteTask(this.index); + Task deletedTask = tasks.deleteTask(this.index); storage.save(tasks); - ui.showRegularMessage("Meow, I deleted the task '%s' for you :3" - .formatted(this.result.getDescription())); + ui.showRegularMessage("Meow, I deleted the task \"%s\" for you :3" + .formatted(deletedTask.getDescription())); } catch (MittensException e) { ui.showErrorMessage(e); } From c66182dcb9ba64b0f9db819a76f47534221b4d37 Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 02:30:50 +0800 Subject: [PATCH 048/105] Add command subclass for listing all tasks --- src/main/java/ListCommand.java | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/main/java/ListCommand.java diff --git a/src/main/java/ListCommand.java b/src/main/java/ListCommand.java new file mode 100644 index 0000000000..ac0bef353b --- /dev/null +++ b/src/main/java/ListCommand.java @@ -0,0 +1,21 @@ +import java.util.ArrayList; +import java.util.List; + +public class ListCommand extends Command { + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + List messages = new ArrayList<>(); + + int count = tasks.getCount(); + if (count == 0) { + messages.add("Meow?! Your list is empty!"); + } + + for (int i = 0; i < count; i++) { + Task task = tasks.getTask(i); + messages.add("%d. %s".formatted(i + 1, task)); + } + + ui.showRegularMessage(messages); + } +} From be8d1944ea3cc6fa47efe0cd48461bca7d8e7d4d Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 03:03:28 +0800 Subject: [PATCH 049/105] Overload showRegularMessage with varargs --- src/main/java/TextUi.java | 6 ++---- src/main/java/Ui.java | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/TextUi.java b/src/main/java/TextUi.java index 537c7e39e3..d4611c11e1 100644 --- a/src/main/java/TextUi.java +++ b/src/main/java/TextUi.java @@ -96,10 +96,8 @@ public void showRegularMessage(List messages) { } @Override - public void showRegularMessage(String message) { - this.printBlankLine(); - this.printMessage(message); - this.printBlankLine(); + public void showRegularMessage(String... messages) { + showRegularMessage(List.of(messages)); } @Override diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java index 449fa420cb..3a5b69ad40 100644 --- a/src/main/java/Ui.java +++ b/src/main/java/Ui.java @@ -4,7 +4,7 @@ public abstract class Ui { public abstract void showGreetingMessage(); public abstract void showGoodbyeMessage(); public abstract void showRegularMessage(List messages); - public abstract void showRegularMessage(String message); + public abstract void showRegularMessage(String... messages); public abstract void showMittensMessage(List messages); public abstract void showErrorMessage(MittensException e); public abstract String getUserInput(); From 39164a7ad69457378fb2c85647f63d294e6c85d0 Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 03:05:06 +0800 Subject: [PATCH 050/105] Add command subclasses for marking and unmarking a task --- src/main/java/MarkCommand.java | 21 +++++++++++++++++++++ src/main/java/UnmarkCommand.java | 21 +++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 src/main/java/MarkCommand.java create mode 100644 src/main/java/UnmarkCommand.java diff --git a/src/main/java/MarkCommand.java b/src/main/java/MarkCommand.java new file mode 100644 index 0000000000..15f904eda4 --- /dev/null +++ b/src/main/java/MarkCommand.java @@ -0,0 +1,21 @@ +public class MarkCommand extends Command { + protected int index; + + public MarkCommand(int index) { + super(); + this.index = index; + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + try { + Task task = tasks.markTaskAsDone(this.index); + + storage.save(tasks); + + ui.showRegularMessage("Meow, I scratched the check box for you:", task.toString()); + } catch (MittensException e) { + ui.showErrorMessage(e); + } + } +} diff --git a/src/main/java/UnmarkCommand.java b/src/main/java/UnmarkCommand.java new file mode 100644 index 0000000000..c009a08634 --- /dev/null +++ b/src/main/java/UnmarkCommand.java @@ -0,0 +1,21 @@ +public class UnmarkCommand extends Command { + protected int index; + + public UnmarkCommand(int index) { + super(); + this.index = index; + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + try { + Task task = tasks.markTaskAsNotDone(this.index); + + storage.save(tasks); + + ui.showRegularMessage("Meow, I scratched the check box for you:", task.toString()); + } catch (MittensException e) { + ui.showErrorMessage(e); + } + } +} From 9e8333d4a8cc6a5e899037eddfd16d507c75b92a Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 03:05:27 +0800 Subject: [PATCH 051/105] Add command subclass for exiting the program --- src/main/java/ExitCommand.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/main/java/ExitCommand.java diff --git a/src/main/java/ExitCommand.java b/src/main/java/ExitCommand.java new file mode 100644 index 0000000000..719010aa88 --- /dev/null +++ b/src/main/java/ExitCommand.java @@ -0,0 +1,17 @@ +public class ExitCommand extends Command { + public ExitCommand() { + super(); + this.isExit = true; + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + try { + storage.save(tasks); + + ui.showGoodbyeMessage(); + } catch (MittensException e) { + ui.showErrorMessage(e); + } + } +} From f097245ca1e2b9f97c2a8268de761ad34cc1981f Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 03:06:47 +0800 Subject: [PATCH 052/105] Replace class methods in Mittens with use of Command instances --- src/main/java/Mittens.java | 131 ++++++------------------------------- 1 file changed, 20 insertions(+), 111 deletions(-) diff --git a/src/main/java/Mittens.java b/src/main/java/Mittens.java index 75e02ec38b..1665c9fbe9 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/Mittens.java @@ -1,30 +1,9 @@ import java.time.LocalDate; import java.time.format.DateTimeParseException; -import java.util.List; import java.util.Scanner; public class Mittens { - - // Unfortunately we were unable to use the initial cat ASCII art due to the - // Unicode characters interfering with the UI tests. - private final static String GREETING_MESSAGE = """ - - /\\_/\\ ____________________ - >^,^< / Hi, I'm Mittens! \\ - / \\ \\ I'm a cat! Meow :3 / - (___)_/ -------------------- - """; - - private final static String EXIT_MESSAGE = """ - - /\\_/\\ _____________ - >^,^< ( Bye-bye! :3 ) - / \\ ------------- - (___)_/ - """; - - private Ui ui; private Storage storage; private TaskList taskList; @@ -34,77 +13,6 @@ public Mittens(String storageFilePath) { this.storage = new Storage(storageFilePath); this.taskList = new TaskList(); } - - public void greet() { - System.out.println(GREETING_MESSAGE); - } - - public void echo(String command) { - int len = command.length(); - String message = """ - - /\\_/\\ %s - >^,^< ( %s ) - / \\ %s - (___)_/ - """.formatted("_".repeat(len + 2), - command, "-".repeat(len + 2)); - - System.out.println(message); - } - - public void addTask(Task task) { - this.taskList.addTask(task); - System.out.printf("\nI've added \"%s\" to your list :3\n\n", task.getDescription()); - } - - public void listTasks() { - if (this.taskList.getCount() == 0) { - System.out.println("\nMeow?! Your list is empty!\n"); - return; - } - System.out.printf("\nYou have %d tasks in your list, here they are :3\n", this.taskList.getCount()); - List tasks = this.taskList.getTasks(); - for (int i = 0; i < tasks.size(); i++) { - Task task = tasks.get(i); - System.out.printf("%d. %s\n", i + 1, task.toString()); - } - System.out.print("\n"); - } - - public void markTaskAsDone(int index) throws BadInputException { - try { - Task task = this.taskList.markTaskAsDone(index - 1); - System.out.printf("\nMeow, I scratched the check box for you:\n%s\n\n", task.toString()); - } catch (IndexOutOfBoundsException e) { - // TODO: Define custom exceptions for TaskList operations - throw new BadInputException("Task index is out of range"); - } - } - - public void markTaskAsNotDone(int index) throws BadInputException { - try { - Task task = this.taskList.markTaskAsNotDone(index - 1); - System.out.printf("\nMeow, I unscratched the check box for you:\n%s\n\n", task.toString()); - } catch (IndexOutOfBoundsException e) { - // TODO: Define custom exceptions for TaskList operations - throw new BadInputException("Task index is out of range"); - } - } - - public void deleteTask(int index) throws BadInputException { - try { - Task task = this.taskList.deleteTask(index - 1); - System.out.printf("\nMeow, I deleted the task '%s' for you :3\n\n", task.getDescription()); - } catch (IndexOutOfBoundsException e) { - // TODO: Define custom exceptions for TaskList operations - throw new BadInputException("Task index is out of range"); - } - } - - public static void exit() { - System.out.println(EXIT_MESSAGE); - } public void run() { Scanner scanner = new Scanner(System.in); @@ -127,35 +35,35 @@ public void run() { return; } - greet(); + ui.showGreetingMessage(); while (true) { - System.out.print("> "); - String input = scanner.nextLine(); - + String input = ui.getUserInput(); + + Command command = null; try { if (input.equals("bye")) { - break; + command = new ExitCommand(); } else if (input.equals("list")) { - listTasks(); + command = new ListCommand(); } else if (input.startsWith("mark")) { try { int index = Integer.parseInt(input.split(" ")[1]); - markTaskAsDone(index); + command = new MarkCommand(index); } catch (NumberFormatException e) { throw new BadInputException("Argument for command 'mark' must be a number"); } } else if (input.startsWith("unmark")) { try { int index = Integer.parseInt(input.split(" ")[1]); - markTaskAsNotDone(index); + command = new UnmarkCommand(index); } catch (NumberFormatException e) { throw new BadInputException("Argument for command 'mark' must be a number"); } } else if (input.startsWith("delete")) { try { int index = Integer.parseInt(input.split(" ")[1]); - deleteTask(index); + command = new DeleteCommand(index); } catch (NumberFormatException e) { throw new BadInputException("Argument for command 'delete' must be a number"); } @@ -163,8 +71,7 @@ public void run() { String description = input.substring(5); Todo newTodo = new Todo(description); - AddCommand command = new AddCommand(newTodo); - command.execute(this.taskList, this.ui, this.storage); + command = new AddCommand(newTodo); } else if (input.startsWith("deadline")) { // Separate the inputs so that the first element contains the description while // the rest contains flags. @@ -194,8 +101,7 @@ public void run() { } Deadline newDeadline = new Deadline(description, by); - AddCommand command = new AddCommand(newDeadline); - command.execute(this.taskList, this.ui, this.storage); + command = new AddCommand(newDeadline); } else if (input.startsWith("event")) { // Separate the inputs so that the first element contains the description while // the rest contains flags. @@ -240,10 +146,7 @@ public void run() { } Event newEvent = new Event(description, from, to); - AddCommand command = new AddCommand(newEvent); - command.execute(this.taskList, this.ui, this.storage); - } else if (input.equals("save")) { - this.storage.save(this.taskList); + command = new AddCommand(newEvent); } else { throw new BadInputException("'%s' is not a known command".formatted(input)); } @@ -253,9 +156,15 @@ public void run() { UnknownException newException = new UnknownException(e.getMessage()); newException.echo(); } - } - exit(); + if (command != null) { + // This should always happen; the if statement is just to remove the NullPointerException warning. + command.execute(this.taskList, this.ui, this.storage); + if (command.isExit()) { + break; + } + } + } } public static void main(String[] args) { From 22079d3649272c15dbc419f5c5df142fafaedbd1 Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 03:27:39 +0800 Subject: [PATCH 053/105] Add CommandParser class --- src/main/java/CommandParser.java | 115 +++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 src/main/java/CommandParser.java diff --git a/src/main/java/CommandParser.java b/src/main/java/CommandParser.java new file mode 100644 index 0000000000..f2ef0c97d4 --- /dev/null +++ b/src/main/java/CommandParser.java @@ -0,0 +1,115 @@ +import java.time.LocalDate; +import java.time.format.DateTimeParseException; + +public class CommandParser { + public Command parse(String input) throws BadInputException { + if (input.equals("bye")) { + return new ExitCommand(); + } else if (input.equals("list")) { + return new ListCommand(); + } else if (input.startsWith("mark")) { + try { + int index = Integer.parseInt(input.split(" ")[1]); + return new MarkCommand(index); + } catch (NumberFormatException e) { + throw new BadInputException("Argument for command 'mark' must be a number"); + } + } else if (input.startsWith("unmark")) { + try { + int index = Integer.parseInt(input.split(" ")[1]); + return new UnmarkCommand(index); + } catch (NumberFormatException e) { + throw new BadInputException("Argument for command 'mark' must be a number"); + } + } else if (input.startsWith("delete")) { + try { + int index = Integer.parseInt(input.split(" ")[1]); + return new DeleteCommand(index); + } catch (NumberFormatException e) { + throw new BadInputException("Argument for command 'delete' must be a number"); + } + } else if (input.startsWith("todo")) { + String description = input.substring(5); + + Todo newTodo = new Todo(description); + return new AddCommand(newTodo); + } else if (input.startsWith("deadline")) { + // Separate the inputs so that the first element contains the description while + // the rest contains flags. + String[] inputs = input.split(" /"); + String description = inputs[0].substring(9); + + LocalDate by = null; + for (int i = 1; i < inputs.length; i++) { + String[] flagWords = inputs[i].split(" "); + if (flagWords[0].equals("by")) { + if (by == null) { + try { + by = LocalDate.parse(inputs[i].substring(3)); + } catch (DateTimeParseException e) { + throw new BadInputException("Invalid date format for 'by' flag"); + } + } else { + throw new BadInputException("Found duplicate of 'by' flag"); + } + } else { + throw new BadInputException("'%s' is not a known flag".formatted(flagWords[0])); + } + } + + if (by == null) { + throw new BadInputException("Command 'deadline' must have a 'by' flag"); + } + + Deadline newDeadline = new Deadline(description, by); + return new AddCommand(newDeadline); + } else if (input.startsWith("event")) { + // Separate the inputs so that the first element contains the description while + // the rest contains flags. + String[] inputs = input.split(" /"); + String description = inputs[0].substring(6); + + LocalDate from = null; + LocalDate to = null; + for (int i = 1; i < inputs.length; i++) { + String[] flagWords = inputs[i].split(" "); + if (flagWords[0].equals("from")) { + if (from == null) { + try { + from = LocalDate.parse(inputs[i].substring(5)); + } catch (DateTimeParseException e) { + throw new BadInputException("Invalid date format for 'from' flag"); + } + } else { + throw new BadInputException("Found duplicate of 'from' flag"); + } + } else if (flagWords[0].equals("to")) { + if (to == null) { + try { + to = LocalDate.parse(inputs[i].substring(3)); + } catch (DateTimeParseException e) { + throw new BadInputException("Invalid date format for 'to' flag"); + } + } else { + throw new BadInputException("Found duplicate of 'to' flag"); + } + } else { + throw new BadInputException("'%s' is not a known flag".formatted(flagWords[0])); + } + } + + if (from == null) { + throw new BadInputException("Command 'event' must have a 'from' flag"); + } + + if (to == null) { + throw new BadInputException("Command 'event' must have a 'to' flag"); + } + + Event newEvent = new Event(description, from, to); + return new AddCommand(newEvent); + } else { + throw new BadInputException("'%s' is not a known command".formatted(input)); + } + } +} From f6fb1bc8785fb3109ecfe24771ef64bbc35952b4 Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 03:28:02 +0800 Subject: [PATCH 054/105] Implement CommandParser in Mittens --- src/main/java/Mittens.java | 124 ++----------------------------------- 1 file changed, 4 insertions(+), 120 deletions(-) diff --git a/src/main/java/Mittens.java b/src/main/java/Mittens.java index 1665c9fbe9..c69c0c479e 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/Mittens.java @@ -1,5 +1,3 @@ -import java.time.LocalDate; -import java.time.format.DateTimeParseException; import java.util.Scanner; @@ -16,6 +14,7 @@ public Mittens(String storageFilePath) { public void run() { Scanner scanner = new Scanner(System.in); + CommandParser commandParser = new CommandParser(); try { this.taskList = this.storage.load(); @@ -40,129 +39,14 @@ public void run() { while (true) { String input = ui.getUserInput(); - Command command = null; try { - if (input.equals("bye")) { - command = new ExitCommand(); - } else if (input.equals("list")) { - command = new ListCommand(); - } else if (input.startsWith("mark")) { - try { - int index = Integer.parseInt(input.split(" ")[1]); - command = new MarkCommand(index); - } catch (NumberFormatException e) { - throw new BadInputException("Argument for command 'mark' must be a number"); - } - } else if (input.startsWith("unmark")) { - try { - int index = Integer.parseInt(input.split(" ")[1]); - command = new UnmarkCommand(index); - } catch (NumberFormatException e) { - throw new BadInputException("Argument for command 'mark' must be a number"); - } - } else if (input.startsWith("delete")) { - try { - int index = Integer.parseInt(input.split(" ")[1]); - command = new DeleteCommand(index); - } catch (NumberFormatException e) { - throw new BadInputException("Argument for command 'delete' must be a number"); - } - } else if (input.startsWith("todo")) { - String description = input.substring(5); - - Todo newTodo = new Todo(description); - command = new AddCommand(newTodo); - } else if (input.startsWith("deadline")) { - // Separate the inputs so that the first element contains the description while - // the rest contains flags. - String[] inputs = input.split(" /"); - String description = inputs[0].substring(9); - - LocalDate by = null; - for (int i = 1; i < inputs.length; i++) { - String[] flagWords = inputs[i].split(" "); - if (flagWords[0].equals("by")) { - if (by == null) { - try { - by = LocalDate.parse(inputs[i].substring(3)); - } catch (DateTimeParseException e) { - throw new BadInputException("Invalid date format for 'by' flag"); - } - } else { - throw new BadInputException("Found duplicate of 'by' flag"); - } - } else { - throw new BadInputException("'%s' is not a known flag".formatted(flagWords[0])); - } - } - - if (by == null) { - throw new BadInputException("Command 'deadline' must have a 'by' flag"); - } - - Deadline newDeadline = new Deadline(description, by); - command = new AddCommand(newDeadline); - } else if (input.startsWith("event")) { - // Separate the inputs so that the first element contains the description while - // the rest contains flags. - String[] inputs = input.split(" /"); - String description = inputs[0].substring(6); - - LocalDate from = null; - LocalDate to = null; - for (int i = 1; i < inputs.length; i++) { - String[] flagWords = inputs[i].split(" "); - if (flagWords[0].equals("from")) { - if (from == null) { - try { - from = LocalDate.parse(inputs[i].substring(5)); - } catch (DateTimeParseException e) { - throw new BadInputException("Invalid date format for 'from' flag"); - } - } else { - throw new BadInputException("Found duplicate of 'from' flag"); - } - } else if (flagWords[0].equals("to")) { - if (to == null) { - try { - to = LocalDate.parse(inputs[i].substring(3)); - } catch (DateTimeParseException e) { - throw new BadInputException("Invalid date format for 'to' flag"); - } - } else { - throw new BadInputException("Found duplicate of 'to' flag"); - } - } else { - throw new BadInputException("'%s' is not a known flag".formatted(flagWords[0])); - } - } - - if (from == null) { - throw new BadInputException("Command 'event' must have a 'from' flag"); - } - - if (to == null) { - throw new BadInputException("Command 'event' must have a 'to' flag"); - } - - Event newEvent = new Event(description, from, to); - command = new AddCommand(newEvent); - } else { - throw new BadInputException("'%s' is not a known command".formatted(input)); - } - } catch (MittensException e) { - e.echo(); - } catch (Exception e) { - UnknownException newException = new UnknownException(e.getMessage()); - newException.echo(); - } - - if (command != null) { - // This should always happen; the if statement is just to remove the NullPointerException warning. + Command command = commandParser.parse(input); command.execute(this.taskList, this.ui, this.storage); if (command.isExit()) { break; } + } catch (BadInputException e) { + ui.showErrorMessage(e); } } } From 8be896b2eded249267ca58c05b2347c2b336167b Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 03:42:35 +0800 Subject: [PATCH 055/105] Refactor Mittens to utilize all other classes --- src/main/java/Mittens.java | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/main/java/Mittens.java b/src/main/java/Mittens.java index c69c0c479e..0f8584f927 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/Mittens.java @@ -2,38 +2,37 @@ public class Mittens { - private Ui ui; - private Storage storage; - private TaskList taskList; + private final Ui ui; + private final Storage storage; + private final TaskList taskList; public Mittens(String storageFilePath) { this.ui = new TextUi(); this.storage = new Storage(storageFilePath); - this.taskList = new TaskList(); - } - - public void run() { - Scanner scanner = new Scanner(System.in); - CommandParser commandParser = new CommandParser(); + TaskList temp; try { - this.taskList = this.storage.load(); + temp = this.storage.load(); } catch (StorageFileException e) { - e.echo(); - - System.out.print("Would you like to continue with a new list instead? (y/n)\n> "); - String input = scanner.nextLine(); - if (input.equals("y")) { - this.taskList = new TaskList(); + ui.showErrorMessage(e); + ui.showRegularMessage("Would you like to continue with a new list instead? (y/n)"); + if (ui.getUserInput().equals("y")) { + temp = new TaskList(); } else { - return; + throw new RuntimeException("User chose to exit the program"); } } catch (Exception e) { InitializationException newException = new InitializationException(e.getMessage()); - newException.echo(); - return; + ui.showErrorMessage(newException); + throw new RuntimeException("Error occurred during initialization"); } + this.taskList = temp; + } + + public void run() { + CommandParser commandParser = new CommandParser(); + ui.showGreetingMessage(); while (true) { From 0fe3fdcc16fe7fdd1e285a70e004c0968c933b82 Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 05:48:10 +0800 Subject: [PATCH 056/105] Move all files to the mittens package --- src/main/java/{ => mittens}/AddCommand.java | 2 ++ src/main/java/{ => mittens}/BadInputException.java | 2 ++ src/main/java/{ => mittens}/Command.java | 2 ++ src/main/java/{ => mittens}/CommandParser.java | 2 ++ src/main/java/{ => mittens}/Deadline.java | 2 ++ src/main/java/{ => mittens}/DeleteCommand.java | 2 ++ src/main/java/{ => mittens}/Event.java | 2 ++ src/main/java/{ => mittens}/ExitCommand.java | 2 ++ src/main/java/{ => mittens}/InitializationException.java | 2 ++ src/main/java/{ => mittens}/ListCommand.java | 2 ++ src/main/java/{ => mittens}/MarkCommand.java | 2 ++ src/main/java/{ => mittens}/Mittens.java | 2 ++ src/main/java/{ => mittens}/MittensException.java | 2 ++ src/main/java/{ => mittens}/Storage.java | 2 ++ src/main/java/{ => mittens}/StorageFileException.java | 2 ++ src/main/java/{ => mittens}/Task.java | 2 ++ src/main/java/{ => mittens}/TaskList.java | 2 ++ src/main/java/{ => mittens}/TextUi.java | 2 ++ src/main/java/{ => mittens}/Todo.java | 2 ++ src/main/java/{ => mittens}/Ui.java | 2 ++ src/main/java/{ => mittens}/UnknownException.java | 2 ++ src/main/java/{ => mittens}/UnmarkCommand.java | 2 ++ 22 files changed, 44 insertions(+) rename src/main/java/{ => mittens}/AddCommand.java (97%) rename src/main/java/{ => mittens}/BadInputException.java (95%) rename src/main/java/{ => mittens}/Command.java (93%) rename src/main/java/{ => mittens}/CommandParser.java (99%) rename src/main/java/{ => mittens}/Deadline.java (96%) rename src/main/java/{ => mittens}/DeleteCommand.java (97%) rename src/main/java/{ => mittens}/Event.java (97%) rename src/main/java/{ => mittens}/ExitCommand.java (95%) rename src/main/java/{ => mittens}/InitializationException.java (95%) rename src/main/java/{ => mittens}/ListCommand.java (97%) rename src/main/java/{ => mittens}/MarkCommand.java (96%) rename src/main/java/{ => mittens}/Mittens.java (98%) rename src/main/java/{ => mittens}/MittensException.java (98%) rename src/main/java/{ => mittens}/Storage.java (99%) rename src/main/java/{ => mittens}/StorageFileException.java (95%) rename src/main/java/{ => mittens}/Task.java (97%) rename src/main/java/{ => mittens}/TaskList.java (98%) rename src/main/java/{ => mittens}/TextUi.java (99%) rename src/main/java/{ => mittens}/Todo.java (91%) rename src/main/java/{ => mittens}/Ui.java (96%) rename src/main/java/{ => mittens}/UnknownException.java (95%) rename src/main/java/{ => mittens}/UnmarkCommand.java (96%) diff --git a/src/main/java/AddCommand.java b/src/main/java/mittens/AddCommand.java similarity index 97% rename from src/main/java/AddCommand.java rename to src/main/java/mittens/AddCommand.java index 4406a7a316..5d2eb92d44 100644 --- a/src/main/java/AddCommand.java +++ b/src/main/java/mittens/AddCommand.java @@ -1,3 +1,5 @@ +package mittens; + public class AddCommand extends Command { protected Task toAdd; diff --git a/src/main/java/BadInputException.java b/src/main/java/mittens/BadInputException.java similarity index 95% rename from src/main/java/BadInputException.java rename to src/main/java/mittens/BadInputException.java index 760248572a..14dcd6ea17 100644 --- a/src/main/java/BadInputException.java +++ b/src/main/java/mittens/BadInputException.java @@ -1,3 +1,5 @@ +package mittens; + public class BadInputException extends MittensException { private static final String MITTENS_MESSAGE = "Meow?! What does that mean?"; private static final String HELP_MESSAGE = "Type 'help' to see a list of commands," + diff --git a/src/main/java/Command.java b/src/main/java/mittens/Command.java similarity index 93% rename from src/main/java/Command.java rename to src/main/java/mittens/Command.java index 6cf663d62d..99cb3deee4 100644 --- a/src/main/java/Command.java +++ b/src/main/java/mittens/Command.java @@ -1,3 +1,5 @@ +package mittens; + public abstract class Command { protected boolean isExit; diff --git a/src/main/java/CommandParser.java b/src/main/java/mittens/CommandParser.java similarity index 99% rename from src/main/java/CommandParser.java rename to src/main/java/mittens/CommandParser.java index f2ef0c97d4..a7a65df284 100644 --- a/src/main/java/CommandParser.java +++ b/src/main/java/mittens/CommandParser.java @@ -1,3 +1,5 @@ +package mittens; + import java.time.LocalDate; import java.time.format.DateTimeParseException; diff --git a/src/main/java/Deadline.java b/src/main/java/mittens/Deadline.java similarity index 96% rename from src/main/java/Deadline.java rename to src/main/java/mittens/Deadline.java index 09552b5bc6..0b974e6284 100644 --- a/src/main/java/Deadline.java +++ b/src/main/java/mittens/Deadline.java @@ -1,3 +1,5 @@ +package mittens; + import java.time.LocalDate; import java.time.format.DateTimeFormatter; diff --git a/src/main/java/DeleteCommand.java b/src/main/java/mittens/DeleteCommand.java similarity index 97% rename from src/main/java/DeleteCommand.java rename to src/main/java/mittens/DeleteCommand.java index 39e1c4e530..0e5cd0e7b7 100644 --- a/src/main/java/DeleteCommand.java +++ b/src/main/java/mittens/DeleteCommand.java @@ -1,3 +1,5 @@ +package mittens; + public class DeleteCommand extends Command { protected int index; diff --git a/src/main/java/Event.java b/src/main/java/mittens/Event.java similarity index 97% rename from src/main/java/Event.java rename to src/main/java/mittens/Event.java index 2bef586ec7..30c45534fc 100644 --- a/src/main/java/Event.java +++ b/src/main/java/mittens/Event.java @@ -1,3 +1,5 @@ +package mittens; + import java.time.LocalDate; import java.time.format.DateTimeFormatter; diff --git a/src/main/java/ExitCommand.java b/src/main/java/mittens/ExitCommand.java similarity index 95% rename from src/main/java/ExitCommand.java rename to src/main/java/mittens/ExitCommand.java index 719010aa88..284c88e94c 100644 --- a/src/main/java/ExitCommand.java +++ b/src/main/java/mittens/ExitCommand.java @@ -1,3 +1,5 @@ +package mittens; + public class ExitCommand extends Command { public ExitCommand() { super(); diff --git a/src/main/java/InitializationException.java b/src/main/java/mittens/InitializationException.java similarity index 95% rename from src/main/java/InitializationException.java rename to src/main/java/mittens/InitializationException.java index af2ec078dd..32c0801380 100644 --- a/src/main/java/InitializationException.java +++ b/src/main/java/mittens/InitializationException.java @@ -1,3 +1,5 @@ +package mittens; + public class InitializationException extends MittensException { private static final String MITTENS_MESSAGE = "Something is preventing me from starting..."; private static final String HELP_MESSAGE = "This is most likely a bug in the software."; diff --git a/src/main/java/ListCommand.java b/src/main/java/mittens/ListCommand.java similarity index 97% rename from src/main/java/ListCommand.java rename to src/main/java/mittens/ListCommand.java index ac0bef353b..f9e255f436 100644 --- a/src/main/java/ListCommand.java +++ b/src/main/java/mittens/ListCommand.java @@ -1,3 +1,5 @@ +package mittens; + import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/MarkCommand.java b/src/main/java/mittens/MarkCommand.java similarity index 96% rename from src/main/java/MarkCommand.java rename to src/main/java/mittens/MarkCommand.java index 15f904eda4..ac9ab67ed4 100644 --- a/src/main/java/MarkCommand.java +++ b/src/main/java/mittens/MarkCommand.java @@ -1,3 +1,5 @@ +package mittens; + public class MarkCommand extends Command { protected int index; diff --git a/src/main/java/Mittens.java b/src/main/java/mittens/Mittens.java similarity index 98% rename from src/main/java/Mittens.java rename to src/main/java/mittens/Mittens.java index 0f8584f927..4c41ca16ec 100644 --- a/src/main/java/Mittens.java +++ b/src/main/java/mittens/Mittens.java @@ -1,3 +1,5 @@ +package mittens; + import java.util.Scanner; diff --git a/src/main/java/MittensException.java b/src/main/java/mittens/MittensException.java similarity index 98% rename from src/main/java/MittensException.java rename to src/main/java/mittens/MittensException.java index ff261afeec..82d8bb84ee 100644 --- a/src/main/java/MittensException.java +++ b/src/main/java/mittens/MittensException.java @@ -1,3 +1,5 @@ +package mittens; + public class MittensException extends Exception { private final String mittensMessage; private final String helpMessage; diff --git a/src/main/java/Storage.java b/src/main/java/mittens/Storage.java similarity index 99% rename from src/main/java/Storage.java rename to src/main/java/mittens/Storage.java index 61e6862f02..451c5e9407 100644 --- a/src/main/java/Storage.java +++ b/src/main/java/mittens/Storage.java @@ -1,3 +1,5 @@ +package mittens; + import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; diff --git a/src/main/java/StorageFileException.java b/src/main/java/mittens/StorageFileException.java similarity index 95% rename from src/main/java/StorageFileException.java rename to src/main/java/mittens/StorageFileException.java index a055e8e3b3..c55522a1ff 100644 --- a/src/main/java/StorageFileException.java +++ b/src/main/java/mittens/StorageFileException.java @@ -1,3 +1,5 @@ +package mittens; + public class StorageFileException extends MittensException { private static final String MITTENS_MESSAGE = "Meow?! Something's wrong with your storage!"; private static final String HELP_MESSAGE = "Your storage might be corrupted. " + diff --git a/src/main/java/Task.java b/src/main/java/mittens/Task.java similarity index 97% rename from src/main/java/Task.java rename to src/main/java/mittens/Task.java index 998a1e43d4..240b3b7af3 100644 --- a/src/main/java/Task.java +++ b/src/main/java/mittens/Task.java @@ -1,3 +1,5 @@ +package mittens; + public abstract class Task { protected String description; protected boolean isDone; diff --git a/src/main/java/TaskList.java b/src/main/java/mittens/TaskList.java similarity index 98% rename from src/main/java/TaskList.java rename to src/main/java/mittens/TaskList.java index 95b0d7bd1d..4e4cd7e6a0 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/mittens/TaskList.java @@ -1,3 +1,5 @@ +package mittens; + import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/TextUi.java b/src/main/java/mittens/TextUi.java similarity index 99% rename from src/main/java/TextUi.java rename to src/main/java/mittens/TextUi.java index d4611c11e1..e1ab24b8a5 100644 --- a/src/main/java/TextUi.java +++ b/src/main/java/mittens/TextUi.java @@ -1,3 +1,5 @@ +package mittens; + import java.io.InputStream; import java.io.PrintStream; import java.util.List; diff --git a/src/main/java/Todo.java b/src/main/java/mittens/Todo.java similarity index 91% rename from src/main/java/Todo.java rename to src/main/java/mittens/Todo.java index eabef3ab8f..a5d05d6a8d 100644 --- a/src/main/java/Todo.java +++ b/src/main/java/mittens/Todo.java @@ -1,3 +1,5 @@ +package mittens; + public class Todo extends Task { public Todo(String description) { super(description); diff --git a/src/main/java/Ui.java b/src/main/java/mittens/Ui.java similarity index 96% rename from src/main/java/Ui.java rename to src/main/java/mittens/Ui.java index 3a5b69ad40..5375bbb169 100644 --- a/src/main/java/Ui.java +++ b/src/main/java/mittens/Ui.java @@ -1,3 +1,5 @@ +package mittens; + import java.util.List; public abstract class Ui { diff --git a/src/main/java/UnknownException.java b/src/main/java/mittens/UnknownException.java similarity index 95% rename from src/main/java/UnknownException.java rename to src/main/java/mittens/UnknownException.java index 4cb8d36171..adfb3d7d03 100644 --- a/src/main/java/UnknownException.java +++ b/src/main/java/mittens/UnknownException.java @@ -1,3 +1,5 @@ +package mittens; + public class UnknownException extends MittensException { private static final String MITTENS_MESSAGE = "Meow?! Something went wrong..."; private static final String HELP_MESSAGE = "I'm not sure what went wrong. You can try again," + diff --git a/src/main/java/UnmarkCommand.java b/src/main/java/mittens/UnmarkCommand.java similarity index 96% rename from src/main/java/UnmarkCommand.java rename to src/main/java/mittens/UnmarkCommand.java index c009a08634..06e827a56e 100644 --- a/src/main/java/UnmarkCommand.java +++ b/src/main/java/mittens/UnmarkCommand.java @@ -1,3 +1,5 @@ +package mittens; + public class UnmarkCommand extends Command { protected int index; From eea6246f812994038d14e97983e168e4f9ec2d50 Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 06:03:17 +0800 Subject: [PATCH 057/105] Move UI-related files to mittens.ui --- src/main/java/mittens/AddCommand.java | 2 ++ src/main/java/mittens/Command.java | 2 ++ src/main/java/mittens/DeleteCommand.java | 2 ++ src/main/java/mittens/ExitCommand.java | 2 ++ src/main/java/mittens/ListCommand.java | 2 ++ src/main/java/mittens/MarkCommand.java | 2 ++ src/main/java/mittens/Mittens.java | 3 ++- src/main/java/mittens/UnmarkCommand.java | 2 ++ src/main/java/mittens/{ => ui}/TextUi.java | 4 +++- src/main/java/mittens/{ => ui}/Ui.java | 4 +++- 10 files changed, 22 insertions(+), 3 deletions(-) rename src/main/java/mittens/{ => ui}/TextUi.java (98%) rename src/main/java/mittens/{ => ui}/Ui.java (89%) diff --git a/src/main/java/mittens/AddCommand.java b/src/main/java/mittens/AddCommand.java index 5d2eb92d44..d1329a6211 100644 --- a/src/main/java/mittens/AddCommand.java +++ b/src/main/java/mittens/AddCommand.java @@ -1,5 +1,7 @@ package mittens; +import mittens.ui.Ui; + public class AddCommand extends Command { protected Task toAdd; diff --git a/src/main/java/mittens/Command.java b/src/main/java/mittens/Command.java index 99cb3deee4..b073b0f85e 100644 --- a/src/main/java/mittens/Command.java +++ b/src/main/java/mittens/Command.java @@ -1,5 +1,7 @@ package mittens; +import mittens.ui.Ui; + public abstract class Command { protected boolean isExit; diff --git a/src/main/java/mittens/DeleteCommand.java b/src/main/java/mittens/DeleteCommand.java index 0e5cd0e7b7..276756d400 100644 --- a/src/main/java/mittens/DeleteCommand.java +++ b/src/main/java/mittens/DeleteCommand.java @@ -1,5 +1,7 @@ package mittens; +import mittens.ui.Ui; + public class DeleteCommand extends Command { protected int index; diff --git a/src/main/java/mittens/ExitCommand.java b/src/main/java/mittens/ExitCommand.java index 284c88e94c..c9a561e5bb 100644 --- a/src/main/java/mittens/ExitCommand.java +++ b/src/main/java/mittens/ExitCommand.java @@ -1,5 +1,7 @@ package mittens; +import mittens.ui.Ui; + public class ExitCommand extends Command { public ExitCommand() { super(); diff --git a/src/main/java/mittens/ListCommand.java b/src/main/java/mittens/ListCommand.java index f9e255f436..0e76392244 100644 --- a/src/main/java/mittens/ListCommand.java +++ b/src/main/java/mittens/ListCommand.java @@ -1,5 +1,7 @@ package mittens; +import mittens.ui.Ui; + import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/mittens/MarkCommand.java b/src/main/java/mittens/MarkCommand.java index ac9ab67ed4..2a81c733e0 100644 --- a/src/main/java/mittens/MarkCommand.java +++ b/src/main/java/mittens/MarkCommand.java @@ -1,5 +1,7 @@ package mittens; +import mittens.ui.Ui; + public class MarkCommand extends Command { protected int index; diff --git a/src/main/java/mittens/Mittens.java b/src/main/java/mittens/Mittens.java index 4c41ca16ec..fe73e1d0a2 100644 --- a/src/main/java/mittens/Mittens.java +++ b/src/main/java/mittens/Mittens.java @@ -1,6 +1,7 @@ package mittens; -import java.util.Scanner; +import mittens.ui.TextUi; +import mittens.ui.Ui; public class Mittens { diff --git a/src/main/java/mittens/UnmarkCommand.java b/src/main/java/mittens/UnmarkCommand.java index 06e827a56e..9c400a5b08 100644 --- a/src/main/java/mittens/UnmarkCommand.java +++ b/src/main/java/mittens/UnmarkCommand.java @@ -1,5 +1,7 @@ package mittens; +import mittens.ui.Ui; + public class UnmarkCommand extends Command { protected int index; diff --git a/src/main/java/mittens/TextUi.java b/src/main/java/mittens/ui/TextUi.java similarity index 98% rename from src/main/java/mittens/TextUi.java rename to src/main/java/mittens/ui/TextUi.java index e1ab24b8a5..e11d7fc262 100644 --- a/src/main/java/mittens/TextUi.java +++ b/src/main/java/mittens/ui/TextUi.java @@ -1,4 +1,6 @@ -package mittens; +package mittens.ui; + +import mittens.MittensException; import java.io.InputStream; import java.io.PrintStream; diff --git a/src/main/java/mittens/Ui.java b/src/main/java/mittens/ui/Ui.java similarity index 89% rename from src/main/java/mittens/Ui.java rename to src/main/java/mittens/ui/Ui.java index 5375bbb169..706c5ad248 100644 --- a/src/main/java/mittens/Ui.java +++ b/src/main/java/mittens/ui/Ui.java @@ -1,4 +1,6 @@ -package mittens; +package mittens.ui; + +import mittens.MittensException; import java.util.List; From 611e063289b7d83eb0380f79c77fede9e5c90384 Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 06:13:55 +0800 Subject: [PATCH 058/105] Add getter methods to Task and its subclasses --- src/main/java/mittens/Deadline.java | 4 ++++ src/main/java/mittens/Event.java | 8 ++++++++ src/main/java/mittens/Task.java | 4 ++++ 3 files changed, 16 insertions(+) diff --git a/src/main/java/mittens/Deadline.java b/src/main/java/mittens/Deadline.java index 0b974e6284..4e1dfe919f 100644 --- a/src/main/java/mittens/Deadline.java +++ b/src/main/java/mittens/Deadline.java @@ -11,6 +11,10 @@ public Deadline(String description, LocalDate by) { this.by = by; } + public LocalDate getBy() { + return this.by; + } + @Override public String toString() { return "[D]" + super.toString() + " (due " diff --git a/src/main/java/mittens/Event.java b/src/main/java/mittens/Event.java index 30c45534fc..f9a630de06 100644 --- a/src/main/java/mittens/Event.java +++ b/src/main/java/mittens/Event.java @@ -13,6 +13,14 @@ public Event(String description, LocalDate from, LocalDate to) { this.to = to; } + public LocalDate getFrom() { + return this.from; + } + + public LocalDate getTo() { + return this.to; + } + @Override public String toString() { return "[E]" + super.toString() + " (" diff --git a/src/main/java/mittens/Task.java b/src/main/java/mittens/Task.java index 240b3b7af3..4725cbffc5 100644 --- a/src/main/java/mittens/Task.java +++ b/src/main/java/mittens/Task.java @@ -13,6 +13,10 @@ public String getDescription() { return this.description; } + public boolean isDone() { + return isDone; + } + public String getStatusIcon() { return (this.isDone ? "X" : " "); } From 5e7b0784441d8c10ad85353fe8752742281d9cc3 Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 06:14:46 +0800 Subject: [PATCH 059/105] Use getter methods instead of direct access to fields --- src/main/java/mittens/Storage.java | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/main/java/mittens/Storage.java b/src/main/java/mittens/Storage.java index 451c5e9407..a3c2dd56dd 100644 --- a/src/main/java/mittens/Storage.java +++ b/src/main/java/mittens/Storage.java @@ -17,23 +17,23 @@ public Storage(String filePath) { public void save(TaskList taskList) throws StorageFileException { try { ArrayList encodedTasks = new ArrayList<>(); - for (Task task : taskList.tasks) { + for (Task task : taskList.getTasks()) { String taskEncoding = ""; if (task instanceof Todo) { taskEncoding = String.format("T|%s|%s", - task.isDone ? "1" : "0", - task.description); + task.getStatusIcon(), + task.getDescription()); } else if (task instanceof Deadline) { taskEncoding = String.format("D|%s|%s|%s", - task.isDone ? "1" : "0", - task.description, - ((Deadline) task).by); + task.getStatusIcon(), + task.getDescription(), + ((Deadline) task).getBy()); } else if (task instanceof Event) { taskEncoding = String.format("E|%s|%s|%s|%s", - task.isDone ? "1" : "0", - task.description, - ((Event) task).from, - ((Event) task).to); + task.getStatusIcon(), + task.getDescription(), + ((Event) task).getFrom(), + ((Event) task).getTo()); } encodedTasks.add(taskEncoding); } @@ -74,7 +74,7 @@ public TaskList load() throws StorageFileException { default: throw new StorageFileException("Corrupted storage file"); } - if (taskComponents[1].equals("1")) { + if (taskComponents[1].equals("X")) { task.markAsDone(); } taskList.addTask(task); From 2fc2af56bd6ae3258996833179d9048ce4f32fee Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 06:17:10 +0800 Subject: [PATCH 060/105] Move task-related classes to mittens.task --- src/main/java/mittens/AddCommand.java | 2 ++ src/main/java/mittens/Command.java | 1 + src/main/java/mittens/CommandParser.java | 4 ++++ src/main/java/mittens/DeleteCommand.java | 2 ++ src/main/java/mittens/ExitCommand.java | 1 + src/main/java/mittens/ListCommand.java | 2 ++ src/main/java/mittens/MarkCommand.java | 2 ++ src/main/java/mittens/Mittens.java | 1 + src/main/java/mittens/Storage.java | 2 ++ src/main/java/mittens/UnmarkCommand.java | 2 ++ src/main/java/mittens/{ => task}/Deadline.java | 2 +- src/main/java/mittens/{ => task}/Event.java | 2 +- src/main/java/mittens/{ => task}/Task.java | 2 +- src/main/java/mittens/{ => task}/TaskList.java | 2 +- src/main/java/mittens/{ => task}/Todo.java | 2 +- 15 files changed, 24 insertions(+), 5 deletions(-) rename src/main/java/mittens/{ => task}/Deadline.java (95%) rename src/main/java/mittens/{ => task}/Event.java (97%) rename src/main/java/mittens/{ => task}/Task.java (96%) rename src/main/java/mittens/{ => task}/TaskList.java (97%) rename src/main/java/mittens/{ => task}/Todo.java (90%) diff --git a/src/main/java/mittens/AddCommand.java b/src/main/java/mittens/AddCommand.java index d1329a6211..f72fd20d47 100644 --- a/src/main/java/mittens/AddCommand.java +++ b/src/main/java/mittens/AddCommand.java @@ -1,5 +1,7 @@ package mittens; +import mittens.task.Task; +import mittens.task.TaskList; import mittens.ui.Ui; public class AddCommand extends Command { diff --git a/src/main/java/mittens/Command.java b/src/main/java/mittens/Command.java index b073b0f85e..4f1c3c7bd1 100644 --- a/src/main/java/mittens/Command.java +++ b/src/main/java/mittens/Command.java @@ -1,5 +1,6 @@ package mittens; +import mittens.task.TaskList; import mittens.ui.Ui; public abstract class Command { diff --git a/src/main/java/mittens/CommandParser.java b/src/main/java/mittens/CommandParser.java index a7a65df284..588391b3ec 100644 --- a/src/main/java/mittens/CommandParser.java +++ b/src/main/java/mittens/CommandParser.java @@ -1,5 +1,9 @@ package mittens; +import mittens.task.Deadline; +import mittens.task.Event; +import mittens.task.Todo; + import java.time.LocalDate; import java.time.format.DateTimeParseException; diff --git a/src/main/java/mittens/DeleteCommand.java b/src/main/java/mittens/DeleteCommand.java index 276756d400..67b91aaf36 100644 --- a/src/main/java/mittens/DeleteCommand.java +++ b/src/main/java/mittens/DeleteCommand.java @@ -1,5 +1,7 @@ package mittens; +import mittens.task.Task; +import mittens.task.TaskList; import mittens.ui.Ui; public class DeleteCommand extends Command { diff --git a/src/main/java/mittens/ExitCommand.java b/src/main/java/mittens/ExitCommand.java index c9a561e5bb..7aa6303879 100644 --- a/src/main/java/mittens/ExitCommand.java +++ b/src/main/java/mittens/ExitCommand.java @@ -1,5 +1,6 @@ package mittens; +import mittens.task.TaskList; import mittens.ui.Ui; public class ExitCommand extends Command { diff --git a/src/main/java/mittens/ListCommand.java b/src/main/java/mittens/ListCommand.java index 0e76392244..2e958a0e74 100644 --- a/src/main/java/mittens/ListCommand.java +++ b/src/main/java/mittens/ListCommand.java @@ -1,5 +1,7 @@ package mittens; +import mittens.task.Task; +import mittens.task.TaskList; import mittens.ui.Ui; import java.util.ArrayList; diff --git a/src/main/java/mittens/MarkCommand.java b/src/main/java/mittens/MarkCommand.java index 2a81c733e0..2d2e8659e5 100644 --- a/src/main/java/mittens/MarkCommand.java +++ b/src/main/java/mittens/MarkCommand.java @@ -1,5 +1,7 @@ package mittens; +import mittens.task.Task; +import mittens.task.TaskList; import mittens.ui.Ui; public class MarkCommand extends Command { diff --git a/src/main/java/mittens/Mittens.java b/src/main/java/mittens/Mittens.java index fe73e1d0a2..3a00608836 100644 --- a/src/main/java/mittens/Mittens.java +++ b/src/main/java/mittens/Mittens.java @@ -1,5 +1,6 @@ package mittens; +import mittens.task.TaskList; import mittens.ui.TextUi; import mittens.ui.Ui; diff --git a/src/main/java/mittens/Storage.java b/src/main/java/mittens/Storage.java index a3c2dd56dd..b1c3d096c3 100644 --- a/src/main/java/mittens/Storage.java +++ b/src/main/java/mittens/Storage.java @@ -1,5 +1,7 @@ package mittens; +import mittens.task.*; + import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; diff --git a/src/main/java/mittens/UnmarkCommand.java b/src/main/java/mittens/UnmarkCommand.java index 9c400a5b08..a1fa54926a 100644 --- a/src/main/java/mittens/UnmarkCommand.java +++ b/src/main/java/mittens/UnmarkCommand.java @@ -1,5 +1,7 @@ package mittens; +import mittens.task.Task; +import mittens.task.TaskList; import mittens.ui.Ui; public class UnmarkCommand extends Command { diff --git a/src/main/java/mittens/Deadline.java b/src/main/java/mittens/task/Deadline.java similarity index 95% rename from src/main/java/mittens/Deadline.java rename to src/main/java/mittens/task/Deadline.java index 4e1dfe919f..5193f2d76c 100644 --- a/src/main/java/mittens/Deadline.java +++ b/src/main/java/mittens/task/Deadline.java @@ -1,4 +1,4 @@ -package mittens; +package mittens.task; import java.time.LocalDate; import java.time.format.DateTimeFormatter; diff --git a/src/main/java/mittens/Event.java b/src/main/java/mittens/task/Event.java similarity index 97% rename from src/main/java/mittens/Event.java rename to src/main/java/mittens/task/Event.java index f9a630de06..eaf9a3d331 100644 --- a/src/main/java/mittens/Event.java +++ b/src/main/java/mittens/task/Event.java @@ -1,4 +1,4 @@ -package mittens; +package mittens.task; import java.time.LocalDate; import java.time.format.DateTimeFormatter; diff --git a/src/main/java/mittens/Task.java b/src/main/java/mittens/task/Task.java similarity index 96% rename from src/main/java/mittens/Task.java rename to src/main/java/mittens/task/Task.java index 4725cbffc5..bf12c9a1a0 100644 --- a/src/main/java/mittens/Task.java +++ b/src/main/java/mittens/task/Task.java @@ -1,4 +1,4 @@ -package mittens; +package mittens.task; public abstract class Task { protected String description; diff --git a/src/main/java/mittens/TaskList.java b/src/main/java/mittens/task/TaskList.java similarity index 97% rename from src/main/java/mittens/TaskList.java rename to src/main/java/mittens/task/TaskList.java index 4e4cd7e6a0..a877129402 100644 --- a/src/main/java/mittens/TaskList.java +++ b/src/main/java/mittens/task/TaskList.java @@ -1,4 +1,4 @@ -package mittens; +package mittens.task; import java.util.ArrayList; import java.util.List; diff --git a/src/main/java/mittens/Todo.java b/src/main/java/mittens/task/Todo.java similarity index 90% rename from src/main/java/mittens/Todo.java rename to src/main/java/mittens/task/Todo.java index a5d05d6a8d..69b3e28ed5 100644 --- a/src/main/java/mittens/Todo.java +++ b/src/main/java/mittens/task/Todo.java @@ -1,4 +1,4 @@ -package mittens; +package mittens.task; public class Todo extends Task { public Todo(String description) { From 331666e0a896961ab9b2e580d1817264fc713a9f Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 06:17:55 +0800 Subject: [PATCH 061/105] Move storage-related classes to mittens.storage --- src/main/java/mittens/AddCommand.java | 1 + src/main/java/mittens/Command.java | 1 + src/main/java/mittens/DeleteCommand.java | 1 + src/main/java/mittens/ExitCommand.java | 1 + src/main/java/mittens/ListCommand.java | 1 + src/main/java/mittens/MarkCommand.java | 1 + src/main/java/mittens/Mittens.java | 2 ++ src/main/java/mittens/UnmarkCommand.java | 1 + src/main/java/mittens/{ => storage}/Storage.java | 2 +- src/main/java/mittens/{ => storage}/StorageFileException.java | 4 +++- 10 files changed, 13 insertions(+), 2 deletions(-) rename src/main/java/mittens/{ => storage}/Storage.java (99%) rename src/main/java/mittens/{ => storage}/StorageFileException.java (87%) diff --git a/src/main/java/mittens/AddCommand.java b/src/main/java/mittens/AddCommand.java index f72fd20d47..1d9454051b 100644 --- a/src/main/java/mittens/AddCommand.java +++ b/src/main/java/mittens/AddCommand.java @@ -1,5 +1,6 @@ package mittens; +import mittens.storage.Storage; import mittens.task.Task; import mittens.task.TaskList; import mittens.ui.Ui; diff --git a/src/main/java/mittens/Command.java b/src/main/java/mittens/Command.java index 4f1c3c7bd1..06a0fd00da 100644 --- a/src/main/java/mittens/Command.java +++ b/src/main/java/mittens/Command.java @@ -1,5 +1,6 @@ package mittens; +import mittens.storage.Storage; import mittens.task.TaskList; import mittens.ui.Ui; diff --git a/src/main/java/mittens/DeleteCommand.java b/src/main/java/mittens/DeleteCommand.java index 67b91aaf36..e2167fc1cf 100644 --- a/src/main/java/mittens/DeleteCommand.java +++ b/src/main/java/mittens/DeleteCommand.java @@ -1,5 +1,6 @@ package mittens; +import mittens.storage.Storage; import mittens.task.Task; import mittens.task.TaskList; import mittens.ui.Ui; diff --git a/src/main/java/mittens/ExitCommand.java b/src/main/java/mittens/ExitCommand.java index 7aa6303879..6d9a3fc0ac 100644 --- a/src/main/java/mittens/ExitCommand.java +++ b/src/main/java/mittens/ExitCommand.java @@ -1,5 +1,6 @@ package mittens; +import mittens.storage.Storage; import mittens.task.TaskList; import mittens.ui.Ui; diff --git a/src/main/java/mittens/ListCommand.java b/src/main/java/mittens/ListCommand.java index 2e958a0e74..3c8ae45bc5 100644 --- a/src/main/java/mittens/ListCommand.java +++ b/src/main/java/mittens/ListCommand.java @@ -1,5 +1,6 @@ package mittens; +import mittens.storage.Storage; import mittens.task.Task; import mittens.task.TaskList; import mittens.ui.Ui; diff --git a/src/main/java/mittens/MarkCommand.java b/src/main/java/mittens/MarkCommand.java index 2d2e8659e5..b3141812c2 100644 --- a/src/main/java/mittens/MarkCommand.java +++ b/src/main/java/mittens/MarkCommand.java @@ -1,5 +1,6 @@ package mittens; +import mittens.storage.Storage; import mittens.task.Task; import mittens.task.TaskList; import mittens.ui.Ui; diff --git a/src/main/java/mittens/Mittens.java b/src/main/java/mittens/Mittens.java index 3a00608836..6e4a6b2758 100644 --- a/src/main/java/mittens/Mittens.java +++ b/src/main/java/mittens/Mittens.java @@ -1,5 +1,7 @@ package mittens; +import mittens.storage.Storage; +import mittens.storage.StorageFileException; import mittens.task.TaskList; import mittens.ui.TextUi; import mittens.ui.Ui; diff --git a/src/main/java/mittens/UnmarkCommand.java b/src/main/java/mittens/UnmarkCommand.java index a1fa54926a..fb4499c09f 100644 --- a/src/main/java/mittens/UnmarkCommand.java +++ b/src/main/java/mittens/UnmarkCommand.java @@ -1,5 +1,6 @@ package mittens; +import mittens.storage.Storage; import mittens.task.Task; import mittens.task.TaskList; import mittens.ui.Ui; diff --git a/src/main/java/mittens/Storage.java b/src/main/java/mittens/storage/Storage.java similarity index 99% rename from src/main/java/mittens/Storage.java rename to src/main/java/mittens/storage/Storage.java index b1c3d096c3..65a9bb59a2 100644 --- a/src/main/java/mittens/Storage.java +++ b/src/main/java/mittens/storage/Storage.java @@ -1,4 +1,4 @@ -package mittens; +package mittens.storage; import mittens.task.*; diff --git a/src/main/java/mittens/StorageFileException.java b/src/main/java/mittens/storage/StorageFileException.java similarity index 87% rename from src/main/java/mittens/StorageFileException.java rename to src/main/java/mittens/storage/StorageFileException.java index c55522a1ff..0f99b3d087 100644 --- a/src/main/java/mittens/StorageFileException.java +++ b/src/main/java/mittens/storage/StorageFileException.java @@ -1,4 +1,6 @@ -package mittens; +package mittens.storage; + +import mittens.MittensException; public class StorageFileException extends MittensException { private static final String MITTENS_MESSAGE = "Meow?! Something's wrong with your storage!"; From 3e55b1a88bc37d44917d612c3ee6ac5f24fffbdd Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 06:19:47 +0800 Subject: [PATCH 062/105] Move commands to mittens.commands --- src/main/java/mittens/CommandParser.java | 1 + src/main/java/mittens/Mittens.java | 1 + src/main/java/mittens/{ => commands}/AddCommand.java | 3 ++- src/main/java/mittens/{ => commands}/Command.java | 2 +- src/main/java/mittens/{ => commands}/DeleteCommand.java | 3 ++- src/main/java/mittens/{ => commands}/ExitCommand.java | 3 ++- src/main/java/mittens/{ => commands}/ListCommand.java | 2 +- src/main/java/mittens/{ => commands}/MarkCommand.java | 3 ++- src/main/java/mittens/{ => commands}/UnmarkCommand.java | 3 ++- 9 files changed, 14 insertions(+), 7 deletions(-) rename src/main/java/mittens/{ => commands}/AddCommand.java (92%) rename src/main/java/mittens/{ => commands}/Command.java (93%) rename src/main/java/mittens/{ => commands}/DeleteCommand.java (92%) rename src/main/java/mittens/{ => commands}/ExitCommand.java (88%) rename src/main/java/mittens/{ => commands}/ListCommand.java (96%) rename src/main/java/mittens/{ => commands}/MarkCommand.java (91%) rename src/main/java/mittens/{ => commands}/UnmarkCommand.java (91%) diff --git a/src/main/java/mittens/CommandParser.java b/src/main/java/mittens/CommandParser.java index 588391b3ec..54ac95418d 100644 --- a/src/main/java/mittens/CommandParser.java +++ b/src/main/java/mittens/CommandParser.java @@ -1,5 +1,6 @@ package mittens; +import mittens.commands.*; import mittens.task.Deadline; import mittens.task.Event; import mittens.task.Todo; diff --git a/src/main/java/mittens/Mittens.java b/src/main/java/mittens/Mittens.java index 6e4a6b2758..27d79f97fd 100644 --- a/src/main/java/mittens/Mittens.java +++ b/src/main/java/mittens/Mittens.java @@ -1,5 +1,6 @@ package mittens; +import mittens.commands.Command; import mittens.storage.Storage; import mittens.storage.StorageFileException; import mittens.task.TaskList; diff --git a/src/main/java/mittens/AddCommand.java b/src/main/java/mittens/commands/AddCommand.java similarity index 92% rename from src/main/java/mittens/AddCommand.java rename to src/main/java/mittens/commands/AddCommand.java index 1d9454051b..e301be163c 100644 --- a/src/main/java/mittens/AddCommand.java +++ b/src/main/java/mittens/commands/AddCommand.java @@ -1,5 +1,6 @@ -package mittens; +package mittens.commands; +import mittens.MittensException; import mittens.storage.Storage; import mittens.task.Task; import mittens.task.TaskList; diff --git a/src/main/java/mittens/Command.java b/src/main/java/mittens/commands/Command.java similarity index 93% rename from src/main/java/mittens/Command.java rename to src/main/java/mittens/commands/Command.java index 06a0fd00da..622a2aeaab 100644 --- a/src/main/java/mittens/Command.java +++ b/src/main/java/mittens/commands/Command.java @@ -1,4 +1,4 @@ -package mittens; +package mittens.commands; import mittens.storage.Storage; import mittens.task.TaskList; diff --git a/src/main/java/mittens/DeleteCommand.java b/src/main/java/mittens/commands/DeleteCommand.java similarity index 92% rename from src/main/java/mittens/DeleteCommand.java rename to src/main/java/mittens/commands/DeleteCommand.java index e2167fc1cf..594be3ba1f 100644 --- a/src/main/java/mittens/DeleteCommand.java +++ b/src/main/java/mittens/commands/DeleteCommand.java @@ -1,5 +1,6 @@ -package mittens; +package mittens.commands; +import mittens.MittensException; import mittens.storage.Storage; import mittens.task.Task; import mittens.task.TaskList; diff --git a/src/main/java/mittens/ExitCommand.java b/src/main/java/mittens/commands/ExitCommand.java similarity index 88% rename from src/main/java/mittens/ExitCommand.java rename to src/main/java/mittens/commands/ExitCommand.java index 6d9a3fc0ac..d00d6176fd 100644 --- a/src/main/java/mittens/ExitCommand.java +++ b/src/main/java/mittens/commands/ExitCommand.java @@ -1,5 +1,6 @@ -package mittens; +package mittens.commands; +import mittens.MittensException; import mittens.storage.Storage; import mittens.task.TaskList; import mittens.ui.Ui; diff --git a/src/main/java/mittens/ListCommand.java b/src/main/java/mittens/commands/ListCommand.java similarity index 96% rename from src/main/java/mittens/ListCommand.java rename to src/main/java/mittens/commands/ListCommand.java index 3c8ae45bc5..89bd73afb9 100644 --- a/src/main/java/mittens/ListCommand.java +++ b/src/main/java/mittens/commands/ListCommand.java @@ -1,4 +1,4 @@ -package mittens; +package mittens.commands; import mittens.storage.Storage; import mittens.task.Task; diff --git a/src/main/java/mittens/MarkCommand.java b/src/main/java/mittens/commands/MarkCommand.java similarity index 91% rename from src/main/java/mittens/MarkCommand.java rename to src/main/java/mittens/commands/MarkCommand.java index b3141812c2..521d0cf6b3 100644 --- a/src/main/java/mittens/MarkCommand.java +++ b/src/main/java/mittens/commands/MarkCommand.java @@ -1,5 +1,6 @@ -package mittens; +package mittens.commands; +import mittens.MittensException; import mittens.storage.Storage; import mittens.task.Task; import mittens.task.TaskList; diff --git a/src/main/java/mittens/UnmarkCommand.java b/src/main/java/mittens/commands/UnmarkCommand.java similarity index 91% rename from src/main/java/mittens/UnmarkCommand.java rename to src/main/java/mittens/commands/UnmarkCommand.java index fb4499c09f..b81608bebb 100644 --- a/src/main/java/mittens/UnmarkCommand.java +++ b/src/main/java/mittens/commands/UnmarkCommand.java @@ -1,5 +1,6 @@ -package mittens; +package mittens.commands; +import mittens.MittensException; import mittens.storage.Storage; import mittens.task.Task; import mittens.task.TaskList; From 3f45c6874e8302f153215aa7f415d53f2cb3a03c Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 06:20:27 +0800 Subject: [PATCH 063/105] Move parser-related classes to mittens.parser --- src/main/java/mittens/Mittens.java | 2 ++ src/main/java/mittens/{ => parser}/BadInputException.java | 4 +++- src/main/java/mittens/{ => parser}/CommandParser.java | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) rename src/main/java/mittens/{ => parser}/BadInputException.java (87%) rename src/main/java/mittens/{ => parser}/CommandParser.java (99%) diff --git a/src/main/java/mittens/Mittens.java b/src/main/java/mittens/Mittens.java index 27d79f97fd..1029129988 100644 --- a/src/main/java/mittens/Mittens.java +++ b/src/main/java/mittens/Mittens.java @@ -1,6 +1,8 @@ package mittens; import mittens.commands.Command; +import mittens.parser.BadInputException; +import mittens.parser.CommandParser; import mittens.storage.Storage; import mittens.storage.StorageFileException; import mittens.task.TaskList; diff --git a/src/main/java/mittens/BadInputException.java b/src/main/java/mittens/parser/BadInputException.java similarity index 87% rename from src/main/java/mittens/BadInputException.java rename to src/main/java/mittens/parser/BadInputException.java index 14dcd6ea17..c9d7cdcda0 100644 --- a/src/main/java/mittens/BadInputException.java +++ b/src/main/java/mittens/parser/BadInputException.java @@ -1,4 +1,6 @@ -package mittens; +package mittens.parser; + +import mittens.MittensException; public class BadInputException extends MittensException { private static final String MITTENS_MESSAGE = "Meow?! What does that mean?"; diff --git a/src/main/java/mittens/CommandParser.java b/src/main/java/mittens/parser/CommandParser.java similarity index 99% rename from src/main/java/mittens/CommandParser.java rename to src/main/java/mittens/parser/CommandParser.java index 54ac95418d..ee5fb5b7a2 100644 --- a/src/main/java/mittens/CommandParser.java +++ b/src/main/java/mittens/parser/CommandParser.java @@ -1,4 +1,4 @@ -package mittens; +package mittens.parser; import mittens.commands.*; import mittens.task.Deadline; From 0339cd4e6f04aa5eb48ae6ab6bf24a1fd594501a Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 08:12:05 +0800 Subject: [PATCH 064/105] Update name to Mittens --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index c361f9811e..8f032683eb 100644 --- a/build.gradle +++ b/build.gradle @@ -28,11 +28,11 @@ test { } application { - mainClass.set("seedu.duke.Duke") + mainClass.set("mittens.Mittens") } shadowJar { - archiveBaseName = "duke" + archiveBaseName = "mittens" archiveClassifier = null } From 507f25ec606f9a924cee03b38ed6b446d338ff8a Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 6 Sep 2024 08:33:16 +0800 Subject: [PATCH 065/105] Add checkstyle plugin to Gradle --- build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build.gradle b/build.gradle index 8f032683eb..930da5839c 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,7 @@ plugins { id 'java' id 'application' + id 'checkstyle' id 'com.github.johnrengelman.shadow' version '7.1.2' } @@ -31,6 +32,10 @@ application { mainClass.set("mittens.Mittens") } +checkstyle { + toolVersion = '10.2' +} + shadowJar { archiveBaseName = "mittens" archiveClassifier = null From 10d0fe9cccf2a07766307370c5eab0c8530c103f Mon Sep 17 00:00:00 2001 From: izruff Date: Sun, 8 Sep 2024 10:50:42 +0800 Subject: [PATCH 066/105] Write tests for CommandParser --- .../mittens/parser/CommandParserTest.java | 153 ++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 src/test/java/mittens/parser/CommandParserTest.java diff --git a/src/test/java/mittens/parser/CommandParserTest.java b/src/test/java/mittens/parser/CommandParserTest.java new file mode 100644 index 0000000000..f90e85a4a9 --- /dev/null +++ b/src/test/java/mittens/parser/CommandParserTest.java @@ -0,0 +1,153 @@ +package mittens.parser; + + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.fail; + +import mittens.commands.AddCommand; +import mittens.commands.Command; +import mittens.commands.DeleteCommand; +import mittens.commands.ExitCommand; +import mittens.commands.ListCommand; +import mittens.commands.MarkCommand; +import mittens.commands.UnmarkCommand; + +public class CommandParserTest { + public CommandParser parser = new CommandParser(); + + @Test + public void parse_listCommand_parsedCorrectly() { + try { + Command c = parser.parse("list"); + assertInstanceOf(ListCommand.class, c); + } catch (BadInputException e) { + fail(); + } + } + + @Test + public void parse_addCommandTodo_parsedCorrectly() { + try { + Command c = parser.parse("todo taskName"); + assertInstanceOf(AddCommand.class, c); + } catch (BadInputException e) { + fail(); + } + } + + @Test + public void parse_addCommandDeadline_parsedCorrectly() { + try { + Command c = parser.parse("deadline taskName /by 2024-01-31"); + assertInstanceOf(AddCommand.class, c); + } catch (BadInputException e) { + fail(); + } + } + + @Test + public void parse_addCommandEvent_parsedCorrectly() { + try { + Command c = parser.parse("event taskName /from 2024-01-31 /to 2024-02-01"); + assertInstanceOf(AddCommand.class, c); + // Different flag ordering + c = parser.parse("event taskName /to 2024-02-01 /from 2024-01-31"); + assertInstanceOf(AddCommand.class, c); + } catch (BadInputException e) { + fail(); + } + } + + @Test + public void parse_markCommand_parsedCorrectly() { + try { + Command c = parser.parse("mark 1"); + assertInstanceOf(MarkCommand.class, c); + } catch (BadInputException e) { + fail(); + } + } + + @Test + public void parse_unmarkCommand_parsedCorrectly() { + try { + Command c = parser.parse("unmark 1"); + assertInstanceOf(UnmarkCommand.class, c); + } catch (BadInputException e) { + fail(); + } + } + + @Test + public void parse_deleteCommand_parsedCorrectly() { + try { + Command c = parser.parse("delete 1"); + assertInstanceOf(DeleteCommand.class, c); + } catch (BadInputException e) { + fail(); + } + } + + @Test + public void parse_exitCommand_parsedCorrectly() { + try { + Command c = parser.parse("bye"); + assertInstanceOf(ExitCommand.class, c); + } catch (BadInputException e) { + fail(); + } + } + + @Test + public void parse_unknownCommand_exceptionThrown() { + try { + Command c = parser.parse("unknown"); + fail(); + } catch (BadInputException e) { + assertEquals("'unknown' is not a known command", e.getMessage()); + } + } + + @Test + public void parse_addCommandDeadlineInvalidDateFormat_exceptionThrown() { + try { + Command c = parser.parse("deadline taskName /by 20240131"); + fail(); + } catch (BadInputException e) { + assertEquals("Invalid date format for 'by' flag", e.getMessage()); + } + } + + @Test + public void parse_addCommandDeadlineUnknownFlag_exceptionThrown() { + try { + Command c = parser.parse("deadline taskName /unknown 2024-01-31"); + fail(); + } catch (BadInputException e) { + assertEquals("'unknown' is not a known flag", e.getMessage()); + } + } + + @Test + public void parse_addCommandDeadlineDuplicateFlag_exceptionThrown() { + try { + Command c = parser.parse("deadline taskName /by 2024-01-31 /by 2024-02-01"); + fail(); + } catch (BadInputException e) { + assertEquals("Found duplicate of 'by' flag", e.getMessage()); + } + } + + @Test + public void parse_addCommandEventNoToFlag_exceptionThrown() { + try { + Command c = parser.parse("event taskName /from 2024-01-31"); + fail(); + } catch (BadInputException e) { + assertEquals("Command 'event' must have a 'to' flag", e.getMessage()); + } + } +} From 2da1cfd326374492c079b5d1224a64bfc80280a5 Mon Sep 17 00:00:00 2001 From: izruff Date: Sun, 8 Sep 2024 11:17:14 +0800 Subject: [PATCH 067/105] Write tests for Storage --- .../java/mittens/storage/StorageTest.java | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 src/test/java/mittens/storage/StorageTest.java diff --git a/src/test/java/mittens/storage/StorageTest.java b/src/test/java/mittens/storage/StorageTest.java new file mode 100644 index 0000000000..55d086e2a3 --- /dev/null +++ b/src/test/java/mittens/storage/StorageTest.java @@ -0,0 +1,90 @@ +package mittens.storage; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.LocalDate; +import java.util.List; + +import mittens.task.TaskList; +import mittens.task.Todo; +import mittens.task.Deadline; +import mittens.task.Event; + +public class StorageTest { + @Test + public void save_validTaskList_success(@TempDir Path tempDir) { + Path filePath = tempDir.resolve("data.txt"); + + TaskList tasks = new TaskList(); + tasks.addTask(new Todo("todoName")); + tasks.addTask(new Deadline("deadlineName", LocalDate.of(2024, 1, 31))); + tasks.addTask(new Event("eventName", LocalDate.of(2024, 1, 31), LocalDate.of(2024, 2, 1))); + tasks.markTaskAsDone(1); + + Storage storage = new Storage(filePath.toString()); + try { + storage.save(tasks); + } catch (StorageFileException e) { + fail(); + } + + try { + List lines = Files.readAllLines(filePath); + assertEquals(3, lines.size()); + assertEquals("T| |todoName", lines.get(0)); + assertEquals("D|X|deadlineName|2024-01-31", lines.get(1)); + assertEquals("E| |eventName|2024-01-31|2024-02-01", lines.get(2)); + } catch (IOException e) { + fail(); + } + } + + @Test + public void load_validTaskList_success(@TempDir Path tempDir) { + Path filePath = tempDir.resolve("data.txt"); + try { + Files.createFile(filePath); + Files.write(filePath, List.of("T| |todoName","D|X|deadlineName|2024-01-31", + "E| |eventName|2024-01-31|2024-02-01")); + } catch (IOException e) { + fail(); + } + + Storage storage = new Storage(filePath.toString()); + try { + TaskList tasks = storage.load(); + assertEquals(3, tasks.getCount()); + assertEquals("[T][ ] todoName", tasks.getTask(0).toString()); + assertEquals("[D][X] deadlineName (due Jan 31, 2024)", tasks.getTask(1).toString()); + assertEquals("[E][ ] eventName (Jan 31, 2024 -- Feb 1, 2024)", tasks.getTask(2).toString()); + } catch (StorageFileException e) { + fail(); + } + } + + @Test + public void load_invalidTaskList_exceptionThrown(@TempDir Path tempDir) { + Path filePath = tempDir.resolve("data.txt"); + try { + Files.createFile(filePath); + Files.write(filePath, "X| |unknownName\n".getBytes()); + } catch (IOException e) { + fail(); + } + + Storage storage = new Storage(filePath.toString()); + try { + storage.load(); + fail(); + } catch (StorageFileException e) { + assertEquals("Corrupted storage file", e.getMessage()); + } + } +} From 48add82667039885e0dfa9b4711be664cdd76625 Mon Sep 17 00:00:00 2001 From: izruff Date: Wed, 11 Sep 2024 15:28:33 +0800 Subject: [PATCH 068/105] fix: Index off by 1 on delete, mark, and unmark commands --- src/main/java/mittens/commands/DeleteCommand.java | 2 +- src/main/java/mittens/commands/MarkCommand.java | 2 +- src/main/java/mittens/commands/UnmarkCommand.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/mittens/commands/DeleteCommand.java b/src/main/java/mittens/commands/DeleteCommand.java index 594be3ba1f..d70b8a6928 100644 --- a/src/main/java/mittens/commands/DeleteCommand.java +++ b/src/main/java/mittens/commands/DeleteCommand.java @@ -17,7 +17,7 @@ public DeleteCommand(int index) { @Override public void execute(TaskList tasks, Ui ui, Storage storage) { try { - Task deletedTask = tasks.deleteTask(this.index); + Task deletedTask = tasks.deleteTask(this.index - 1); storage.save(tasks); diff --git a/src/main/java/mittens/commands/MarkCommand.java b/src/main/java/mittens/commands/MarkCommand.java index 521d0cf6b3..0d20becbc0 100644 --- a/src/main/java/mittens/commands/MarkCommand.java +++ b/src/main/java/mittens/commands/MarkCommand.java @@ -17,7 +17,7 @@ public MarkCommand(int index) { @Override public void execute(TaskList tasks, Ui ui, Storage storage) { try { - Task task = tasks.markTaskAsDone(this.index); + Task task = tasks.markTaskAsDone(this.index - 1); storage.save(tasks); diff --git a/src/main/java/mittens/commands/UnmarkCommand.java b/src/main/java/mittens/commands/UnmarkCommand.java index b81608bebb..b66a9413cf 100644 --- a/src/main/java/mittens/commands/UnmarkCommand.java +++ b/src/main/java/mittens/commands/UnmarkCommand.java @@ -17,7 +17,7 @@ public UnmarkCommand(int index) { @Override public void execute(TaskList tasks, Ui ui, Storage storage) { try { - Task task = tasks.markTaskAsNotDone(this.index); + Task task = tasks.markTaskAsNotDone(this.index - 1); storage.save(tasks); From 23b66b6694812b1a6401cfb2cfa4376c42af7193 Mon Sep 17 00:00:00 2001 From: izruff Date: Wed, 11 Sep 2024 15:32:03 +0800 Subject: [PATCH 069/105] fix: Remove extra newline from certain messages --- src/main/java/mittens/ui/TextUi.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/mittens/ui/TextUi.java b/src/main/java/mittens/ui/TextUi.java index e11d7fc262..2ad4e62569 100644 --- a/src/main/java/mittens/ui/TextUi.java +++ b/src/main/java/mittens/ui/TextUi.java @@ -12,15 +12,13 @@ public class TextUi extends Ui { /\\_/\\ ____________________ >^,^< / Hi, I'm Mittens! \\ / \\ \\ I'm a cat! Meow :3 / - (___)_/ -------------------- - """; + (___)_/ --------------------"""; private final static String GOODBYE_MESSAGE = """ /\\_/\\ _____________ >^,^< ( Bye-bye! :3 ) / \\ ------------- - (___)_/ - """; + (___)_/"""; private final Scanner in; private final PrintStream out; @@ -48,8 +46,7 @@ public void printMittens(String message) { /\\_/\\ %s >^,^< ( %s ) / \\ %s - (___)_/ - """.formatted("_".repeat(len + 2), + (___)_/""".formatted("_".repeat(len + 2), message, "-".repeat(len + 2)); this.out.println(uiMessage); @@ -69,8 +66,7 @@ public void printErrorMessage(MittensException e) { (___)_/ Error: %s - %s - """.formatted("_".repeat(len + 2), mittensMessage, + %s""".formatted("_".repeat(len + 2), mittensMessage, "-".repeat(len + 2), errorMessage, helpMessage); this.out.println(uiMessage); From 331651ce08faeef850ea647be3bdc7ed97183f6d Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 20 Sep 2024 14:50:00 +0800 Subject: [PATCH 070/105] Add JavaDoc comments to Command and its subclasses --- src/main/java/mittens/commands/AddCommand.java | 11 ++++++++++- src/main/java/mittens/commands/Command.java | 15 ++++++++++++++- src/main/java/mittens/commands/DeleteCommand.java | 9 +++++++++ src/main/java/mittens/commands/ExitCommand.java | 7 +++++++ src/main/java/mittens/commands/ListCommand.java | 4 ++++ src/main/java/mittens/commands/MarkCommand.java | 9 +++++++++ src/main/java/mittens/commands/UnmarkCommand.java | 9 +++++++++ 7 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/main/java/mittens/commands/AddCommand.java b/src/main/java/mittens/commands/AddCommand.java index e301be163c..0ad86d5a90 100644 --- a/src/main/java/mittens/commands/AddCommand.java +++ b/src/main/java/mittens/commands/AddCommand.java @@ -6,9 +6,18 @@ import mittens.task.TaskList; import mittens.ui.Ui; +/** + * Represents a command for adding a task into the task list. + */ public class AddCommand extends Command { - protected Task toAdd; + protected Task toAdd; + + /** + * Creates a new AddCommand object with the specified task to add. + * + * @param toAdd The task to add + */ public AddCommand(Task toAdd) { super(); this.toAdd = toAdd; diff --git a/src/main/java/mittens/commands/Command.java b/src/main/java/mittens/commands/Command.java index 622a2aeaab..82100bc462 100644 --- a/src/main/java/mittens/commands/Command.java +++ b/src/main/java/mittens/commands/Command.java @@ -4,14 +4,27 @@ import mittens.task.TaskList; import mittens.ui.Ui; +/** + * Represents a command that is obtained by parsing the user input. + */ public abstract class Command { + + /** Whether the program should exit upon execution */ protected boolean isExit; public Command() { this.isExit = false; } - + + /** + * Executes the command by interacting with the task list, UI, and storage. + * + * @param tasks The running program's task list + * @param ui The running program's UI + * @param storage The running program's storage + */ public abstract void execute(TaskList tasks, Ui ui, Storage storage); + public boolean isExit() { return this.isExit; } diff --git a/src/main/java/mittens/commands/DeleteCommand.java b/src/main/java/mittens/commands/DeleteCommand.java index d70b8a6928..eff6618405 100644 --- a/src/main/java/mittens/commands/DeleteCommand.java +++ b/src/main/java/mittens/commands/DeleteCommand.java @@ -6,9 +6,18 @@ import mittens.task.TaskList; import mittens.ui.Ui; +/** + * Represents a command for deleting a task from the task list. + */ public class DeleteCommand extends Command { + protected int index; + /** + * Creates a new DeleteCommand object with the specified index of the task to delete. + * + * @param index The index of the task to delete (1-indexed) + */ public DeleteCommand(int index) { super(); this.index = index; diff --git a/src/main/java/mittens/commands/ExitCommand.java b/src/main/java/mittens/commands/ExitCommand.java index d00d6176fd..40021ffdde 100644 --- a/src/main/java/mittens/commands/ExitCommand.java +++ b/src/main/java/mittens/commands/ExitCommand.java @@ -5,7 +5,14 @@ import mittens.task.TaskList; import mittens.ui.Ui; +/** + * Represents a command for exiting the program. + */ public class ExitCommand extends Command { + + /** + * Creates a new ExitCommand object. + */ public ExitCommand() { super(); this.isExit = true; diff --git a/src/main/java/mittens/commands/ListCommand.java b/src/main/java/mittens/commands/ListCommand.java index 89bd73afb9..3fa9cf0880 100644 --- a/src/main/java/mittens/commands/ListCommand.java +++ b/src/main/java/mittens/commands/ListCommand.java @@ -8,7 +8,11 @@ import java.util.ArrayList; import java.util.List; +/** + * Represents a command for listing all tasks in the task list. + */ public class ListCommand extends Command { + @Override public void execute(TaskList tasks, Ui ui, Storage storage) { List messages = new ArrayList<>(); diff --git a/src/main/java/mittens/commands/MarkCommand.java b/src/main/java/mittens/commands/MarkCommand.java index 0d20becbc0..a683ab9e92 100644 --- a/src/main/java/mittens/commands/MarkCommand.java +++ b/src/main/java/mittens/commands/MarkCommand.java @@ -6,9 +6,18 @@ import mittens.task.TaskList; import mittens.ui.Ui; +/** + * Represents a command for marking a task as done in the task list. + */ public class MarkCommand extends Command { + protected int index; + /** + * Creates a new MarkCommand object with the specified index of the task to mark as done. + * + * @param index The index of the task to mark as done (1-indexed) + */ public MarkCommand(int index) { super(); this.index = index; diff --git a/src/main/java/mittens/commands/UnmarkCommand.java b/src/main/java/mittens/commands/UnmarkCommand.java index b66a9413cf..7cae044ab6 100644 --- a/src/main/java/mittens/commands/UnmarkCommand.java +++ b/src/main/java/mittens/commands/UnmarkCommand.java @@ -6,9 +6,18 @@ import mittens.task.TaskList; import mittens.ui.Ui; +/** + * Represents a command for marking a task as not done in the task list. + */ public class UnmarkCommand extends Command { + protected int index; + /** + * Creates a new UnmarkCommand object with the specified index of the task to mark as not done. + * + * @param index The index of the task to mark as not done (1-indexed) + */ public UnmarkCommand(int index) { super(); this.index = index; From c47210d5937ea76d8cc3e3d8c5221cc7f916bec8 Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 20 Sep 2024 15:10:50 +0800 Subject: [PATCH 071/105] Add JavaDoc comments to Mittens class --- src/main/java/mittens/Mittens.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/mittens/Mittens.java b/src/main/java/mittens/Mittens.java index 1029129988..4e41fc0d22 100644 --- a/src/main/java/mittens/Mittens.java +++ b/src/main/java/mittens/Mittens.java @@ -9,12 +9,20 @@ import mittens.ui.TextUi; import mittens.ui.Ui; - +/** + * Represents the main class where the program is initialized and the main loop is run. + */ public class Mittens { + private final Ui ui; private final Storage storage; private final TaskList taskList; + /** + * Creates a new Mittens object with the specified storage file path. + * + * @param storageFilePath The file path to the storage file + */ public Mittens(String storageFilePath) { this.ui = new TextUi(); this.storage = new Storage(storageFilePath); @@ -39,6 +47,9 @@ public Mittens(String storageFilePath) { this.taskList = temp; } + /** + * Runs the main loop of the program which accepts user input. + */ public void run() { CommandParser commandParser = new CommandParser(); From d88c6c265a783c101eafff1fb08e69038452c8e0 Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 20 Sep 2024 15:14:53 +0800 Subject: [PATCH 072/105] Add JavaDoc comments to CommandParser and related classes --- src/main/java/mittens/parser/BadInputException.java | 3 +++ src/main/java/mittens/parser/CommandParser.java | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/main/java/mittens/parser/BadInputException.java b/src/main/java/mittens/parser/BadInputException.java index c9d7cdcda0..0d24feeb94 100644 --- a/src/main/java/mittens/parser/BadInputException.java +++ b/src/main/java/mittens/parser/BadInputException.java @@ -2,6 +2,9 @@ import mittens.MittensException; +/** + * Represents an exception when the user input is invalid. + */ public class BadInputException extends MittensException { private static final String MITTENS_MESSAGE = "Meow?! What does that mean?"; private static final String HELP_MESSAGE = "Type 'help' to see a list of commands," + diff --git a/src/main/java/mittens/parser/CommandParser.java b/src/main/java/mittens/parser/CommandParser.java index ee5fb5b7a2..0e0f0aeb58 100644 --- a/src/main/java/mittens/parser/CommandParser.java +++ b/src/main/java/mittens/parser/CommandParser.java @@ -8,7 +8,19 @@ import java.time.LocalDate; import java.time.format.DateTimeParseException; +/** + * Represents a parser for commands. + */ public class CommandParser { + + /** + * Parses the input and returns the corresponding command. + * If no match with any command format is found, a BadInputException is thrown. + * + * @param input The user input to parse + * @return The corresponding Command object + * @throws BadInputException If the input does not match any known command format + */ public Command parse(String input) throws BadInputException { if (input.equals("bye")) { return new ExitCommand(); From fa54976a136b53d66395a0ab94f0bca630cea90f Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 20 Sep 2024 15:16:59 +0800 Subject: [PATCH 073/105] Add JavaDoc comments to exception classes --- .../java/mittens/InitializationException.java | 3 +++ src/main/java/mittens/MittensException.java | 18 ++++++++++++++++-- src/main/java/mittens/UnknownException.java | 3 +++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/main/java/mittens/InitializationException.java b/src/main/java/mittens/InitializationException.java index 32c0801380..995c86fcab 100644 --- a/src/main/java/mittens/InitializationException.java +++ b/src/main/java/mittens/InitializationException.java @@ -1,5 +1,8 @@ package mittens; +/** + * Represents an exception when there is an error during initialization. + */ public class InitializationException extends MittensException { private static final String MITTENS_MESSAGE = "Something is preventing me from starting..."; private static final String HELP_MESSAGE = "This is most likely a bug in the software."; diff --git a/src/main/java/mittens/MittensException.java b/src/main/java/mittens/MittensException.java index 82d8bb84ee..9fbf4b57d8 100644 --- a/src/main/java/mittens/MittensException.java +++ b/src/main/java/mittens/MittensException.java @@ -1,15 +1,29 @@ package mittens; +/** + * Represents an exception specific to the Mittens program. + */ public class MittensException extends Exception { + + /** The message to be displayed by the cute cat Mittens */ private final String mittensMessage; - private final String helpMessage; + /** The message to be displayed to help the user */ + private final String helpMessage; + + /** + * Constructs a MittensException with the specified message. + * + * @param message The message which describes the technical details of the exception. + * @param mittensMessage The message to be displayed by the cute cat Mittens. + * @param helpMessage The message to be displayed to help the user. + */ public MittensException(String message, String mittensMessage, String helpMessage) { super(message); this.mittensMessage = mittensMessage; this.helpMessage = helpMessage; } - + public String getMittensMessage() { return this.mittensMessage; } diff --git a/src/main/java/mittens/UnknownException.java b/src/main/java/mittens/UnknownException.java index adfb3d7d03..841ef5e48f 100644 --- a/src/main/java/mittens/UnknownException.java +++ b/src/main/java/mittens/UnknownException.java @@ -1,5 +1,8 @@ package mittens; +/** + * Represents an exception when the cause of the error is unknown. + */ public class UnknownException extends MittensException { private static final String MITTENS_MESSAGE = "Meow?! Something went wrong..."; private static final String HELP_MESSAGE = "I'm not sure what went wrong. You can try again," + From 1a98c3f3d102352413175dbba4dbb597084cc757 Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 20 Sep 2024 15:27:24 +0800 Subject: [PATCH 074/105] Add JavaDoc comments to Storage and related classes --- src/main/java/mittens/storage/Storage.java | 23 ++++++++++++++++++- .../mittens/storage/StorageFileException.java | 3 +++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/main/java/mittens/storage/Storage.java b/src/main/java/mittens/storage/Storage.java index 65a9bb59a2..07a188c485 100644 --- a/src/main/java/mittens/storage/Storage.java +++ b/src/main/java/mittens/storage/Storage.java @@ -9,13 +9,27 @@ import java.time.format.DateTimeParseException; import java.util.ArrayList; +/** + * Represents a file storage for saving and loading tasks. + */ public class Storage { protected final Path filePath; + /** + * Creates a new Storage object with the specified file path. + * + * @param filePath The file path where the tasks are stored + */ public Storage(String filePath) { this.filePath = Path.of(filePath); } - + + /** + * Saves the task list to the storage file in CSV-like form. + * + * @param taskList The task list to save + * @throws StorageFileException If an error occurs while writing to the storage file + */ public void save(TaskList taskList) throws StorageFileException { try { ArrayList encodedTasks = new ArrayList<>(); @@ -45,6 +59,13 @@ public void save(TaskList taskList) throws StorageFileException { } } + /** + * Loads the task list from the storage file. + * + * @return The task list obtained by decoding the storage file + * @throws StorageFileException If an error occurs while reading from the storage file + * or if the file is corrupted + */ public TaskList load() throws StorageFileException { if (!Files.exists(this.filePath)) { try { diff --git a/src/main/java/mittens/storage/StorageFileException.java b/src/main/java/mittens/storage/StorageFileException.java index 0f99b3d087..1df093d9c9 100644 --- a/src/main/java/mittens/storage/StorageFileException.java +++ b/src/main/java/mittens/storage/StorageFileException.java @@ -2,6 +2,9 @@ import mittens.MittensException; +/** + * Represents an exception related to the storage file. + */ public class StorageFileException extends MittensException { private static final String MITTENS_MESSAGE = "Meow?! Something's wrong with your storage!"; private static final String HELP_MESSAGE = "Your storage might be corrupted. " + From dbe4fba3b355535624c4bacfc93e8d46feb902ba Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 20 Sep 2024 15:36:47 +0800 Subject: [PATCH 075/105] Add JavaDoc comments to Task and TaskList --- src/main/java/mittens/task/Deadline.java | 10 ++++++ src/main/java/mittens/task/Event.java | 8 +++++ src/main/java/mittens/task/Task.java | 20 ++++++++++++ src/main/java/mittens/task/TaskList.java | 41 ++++++++++++++++++++++++ src/main/java/mittens/task/Todo.java | 9 ++++++ 5 files changed, 88 insertions(+) diff --git a/src/main/java/mittens/task/Deadline.java b/src/main/java/mittens/task/Deadline.java index 5193f2d76c..e716113aa7 100644 --- a/src/main/java/mittens/task/Deadline.java +++ b/src/main/java/mittens/task/Deadline.java @@ -3,9 +3,19 @@ import java.time.LocalDate; import java.time.format.DateTimeFormatter; +/** + * Represents a Deadline task, that is a task having a deadline. + */ public class Deadline extends Task { + protected LocalDate by; + /** + * Creates a Deadline task with the given description and deadline. + * + * @param description The description of the task + * @param by The deadline of the task + */ public Deadline(String description, LocalDate by) { super(description); this.by = by; diff --git a/src/main/java/mittens/task/Event.java b/src/main/java/mittens/task/Event.java index eaf9a3d331..cf13cf894a 100644 --- a/src/main/java/mittens/task/Event.java +++ b/src/main/java/mittens/task/Event.java @@ -4,9 +4,17 @@ import java.time.format.DateTimeFormatter; public class Event extends Task { + protected LocalDate from; protected LocalDate to; + /** + * Creates an Event task with the given description and date range. + * + * @param description The description of the task + * @param from The start date of the event + * @param to The end date of the event + */ public Event(String description, LocalDate from, LocalDate to) { super(description); this.from = from; diff --git a/src/main/java/mittens/task/Task.java b/src/main/java/mittens/task/Task.java index bf12c9a1a0..7aa2c0a00f 100644 --- a/src/main/java/mittens/task/Task.java +++ b/src/main/java/mittens/task/Task.java @@ -1,9 +1,18 @@ package mittens.task; +/** + * Represents a task in the task list. + */ public abstract class Task { + protected String description; protected boolean isDone; + /** + * Creates a task with the given description. + * + * @param description The description of the task + */ public Task(String description) { this.description = description; this.isDone = false; @@ -17,14 +26,25 @@ public boolean isDone() { return isDone; } + /** + * Returns a text representation of whether the task is done. + * + * @return "X" if the task is done, " " otherwise + */ public String getStatusIcon() { return (this.isDone ? "X" : " "); } + /** + * Marks the task as done. + */ public void markAsDone() { this.isDone = true; } + /** + * Marks the task as not done. + */ public void markAsNotDone() { this.isDone = false; } diff --git a/src/main/java/mittens/task/TaskList.java b/src/main/java/mittens/task/TaskList.java index a877129402..0946cbfc4e 100644 --- a/src/main/java/mittens/task/TaskList.java +++ b/src/main/java/mittens/task/TaskList.java @@ -3,9 +3,16 @@ import java.util.ArrayList; import java.util.List; +/** + * Represents a list of tasks. + */ public class TaskList { + protected final ArrayList tasks; + /** + * Initializes a task list. + */ public TaskList() { this.tasks = new ArrayList<>(); } @@ -14,30 +21,64 @@ public List getTasks() { return this.tasks; } + /** + * Gets the task at the specified index. + * + * @param index The index of the task to get + * @return The task at the specified index + */ public Task getTask(int index) { return this.tasks.get(index); } + /** + * Gets the number of tasks in the list. + * + * @return The number of tasks in the list + */ public int getCount() { return this.tasks.size(); } + /** + * Adds a task to the list. + * + * @param task The task to add + */ public void addTask(Task task) { this.tasks.add(task); } + /** + * Marks a task as done. + * + * @param index The index of the task to mark as done + * @return The task that was marked as done + */ public Task markTaskAsDone(int index) { Task task = this.tasks.get(index); task.markAsDone(); return task; } + /** + * Marks a task as not done. + * + * @param index The index of the task to mark as not done + * @return The task that was marked as not done + */ public Task markTaskAsNotDone(int index) { Task task = this.tasks.get(index); task.markAsNotDone(); return task; } + /** + * Deletes a task from the list. + * + * @param index The index of the task to delete + * @return The task that was deleted + */ public Task deleteTask(int index) { return this.tasks.remove(index); } diff --git a/src/main/java/mittens/task/Todo.java b/src/main/java/mittens/task/Todo.java index 69b3e28ed5..9010672553 100644 --- a/src/main/java/mittens/task/Todo.java +++ b/src/main/java/mittens/task/Todo.java @@ -1,6 +1,15 @@ package mittens.task; +/** + * Represents a Todo task, that is a task with description only. + */ public class Todo extends Task { + + /** + * Creates a Todo task with the given description. + * + * @param description The description of the task + */ public Todo(String description) { super(description); } From 15c92b5d6e418b1a5e2c40dfbbcc24f0b63d2880 Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 20 Sep 2024 15:46:14 +0800 Subject: [PATCH 076/105] Add JavaDoc comments to Ui and its subclasses --- src/main/java/mittens/ui/TextUi.java | 35 ++++++++++++++++++++++-- src/main/java/mittens/ui/Ui.java | 41 ++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 2 deletions(-) diff --git a/src/main/java/mittens/ui/TextUi.java b/src/main/java/mittens/ui/TextUi.java index 2ad4e62569..78e605e6cd 100644 --- a/src/main/java/mittens/ui/TextUi.java +++ b/src/main/java/mittens/ui/TextUi.java @@ -7,7 +7,11 @@ import java.util.List; import java.util.Scanner; +/** + * Represents the CLI version of the user interface. + */ public class TextUi extends Ui { + private final static String GREETING_MESSAGE = """ /\\_/\\ ____________________ >^,^< / Hi, I'm Mittens! \\ @@ -23,23 +27,45 @@ public class TextUi extends Ui { private final Scanner in; private final PrintStream out; + /** + * Creates a new TextUi object with the default input and output streams. + */ public TextUi() { this(System.in, System.out); } - + + /** + * Creates a new TextUi object with the given input and output streams. + * + * @param in The input stream + * @param out The output stream + */ public TextUi(InputStream in, PrintStream out) { this.in = new Scanner(in); this.out = out; } + /** + * Prints the given message to the output stream. + * + * @param message The message to print + */ public void printMessage(String message) { this.out.println(message); } + /** + * Prints a blank line to the output stream. + */ public void printBlankLine() { this.out.println(); } + /** + * Prints the given message accompanied by the cute cat Mittens. + * + * @param message The message to print + */ public void printMittens(String message) { int len = message.length(); String uiMessage = """ @@ -52,6 +78,11 @@ public void printMittens(String message) { this.out.println(uiMessage); } + /** + * Prints the given error message accompanied by the cute cat Mittens. + * + * @param e The exception to print + */ public void printErrorMessage(MittensException e) { String mittensMessage = e.getMittensMessage(); int len = mittensMessage.length(); @@ -71,7 +102,7 @@ public void printErrorMessage(MittensException e) { this.out.println(uiMessage); } - + @Override public void showGreetingMessage() { this.printBlankLine(); diff --git a/src/main/java/mittens/ui/Ui.java b/src/main/java/mittens/ui/Ui.java index 706c5ad248..58d035d5ec 100644 --- a/src/main/java/mittens/ui/Ui.java +++ b/src/main/java/mittens/ui/Ui.java @@ -4,12 +4,53 @@ import java.util.List; +/** + * Represents the user interface of the application. + */ public abstract class Ui { + + /** + * Shows the greeting message to be displayed at the start of the program. + */ public abstract void showGreetingMessage(); + + /** + * Shows the goodbye message to be displayed when the user exits the program. + */ public abstract void showGoodbyeMessage(); + + /** + * Generates a combined message formed by the given list of strings. + * + * @param messages The list of strings to output + */ public abstract void showRegularMessage(List messages); + + /** + * Generates a combined message formed by the given strings. + * + * @param messages The strings to output + */ public abstract void showRegularMessage(String... messages); + + /** + * Generates a combined message accompanied by the cute cat Mittens. + * + * @param messages The list of strings to output + */ public abstract void showMittensMessage(List messages); + + /** + * Generates an error message based on the given throwable. + * + * @param e The exception to output + */ public abstract void showErrorMessage(MittensException e); + + /** + * Waits for the user to input a string command and returns that string. + * + * @return The user input + */ public abstract String getUserInput(); } From 88ff04d67d16e064c478d99772868859c0a65e23 Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 20 Sep 2024 15:51:18 +0800 Subject: [PATCH 077/105] Enforce explicit import statements --- src/main/java/mittens/parser/CommandParser.java | 8 +++++++- src/main/java/mittens/storage/Storage.java | 6 +++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/java/mittens/parser/CommandParser.java b/src/main/java/mittens/parser/CommandParser.java index ee5fb5b7a2..4a6f3c2226 100644 --- a/src/main/java/mittens/parser/CommandParser.java +++ b/src/main/java/mittens/parser/CommandParser.java @@ -1,6 +1,12 @@ package mittens.parser; -import mittens.commands.*; +import mittens.commands.AddCommand; +import mittens.commands.Command; +import mittens.commands.DeleteCommand; +import mittens.commands.ExitCommand; +import mittens.commands.ListCommand; +import mittens.commands.MarkCommand; +import mittens.commands.UnmarkCommand; import mittens.task.Deadline; import mittens.task.Event; import mittens.task.Todo; diff --git a/src/main/java/mittens/storage/Storage.java b/src/main/java/mittens/storage/Storage.java index 65a9bb59a2..635938d132 100644 --- a/src/main/java/mittens/storage/Storage.java +++ b/src/main/java/mittens/storage/Storage.java @@ -1,6 +1,10 @@ package mittens.storage; -import mittens.task.*; +import mittens.task.Deadline; +import mittens.task.Event; +import mittens.task.Task; +import mittens.task.TaskList; +import mittens.task.Todo; import java.io.IOException; import java.nio.file.Files; From 240fd19aea6bb3d3d9dca73fe766c2e538d314d0 Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 20 Sep 2024 16:04:12 +0800 Subject: [PATCH 078/105] Auto-format code with Intellij code style --- src/main/java/mittens/Mittens.java | 12 +++---- src/main/java/mittens/MittensException.java | 14 ++++---- src/main/java/mittens/UnknownException.java | 2 +- .../java/mittens/commands/AddCommand.java | 8 ++--- src/main/java/mittens/commands/Command.java | 5 +-- .../java/mittens/commands/ListCommand.java | 6 ++-- .../mittens/parser/BadInputException.java | 2 +- src/main/java/mittens/storage/Storage.java | 32 ++++++++--------- src/main/java/mittens/task/TaskList.java | 10 +++--- src/main/java/mittens/ui/TextUi.java | 36 +++++++++---------- src/main/java/mittens/ui/Ui.java | 6 ++++ .../mittens/parser/CommandParserTest.java | 18 +++++----- .../java/mittens/storage/StorageTest.java | 12 +++---- 13 files changed, 85 insertions(+), 78 deletions(-) diff --git a/src/main/java/mittens/Mittens.java b/src/main/java/mittens/Mittens.java index 1029129988..a7ad8b7904 100644 --- a/src/main/java/mittens/Mittens.java +++ b/src/main/java/mittens/Mittens.java @@ -14,11 +14,11 @@ public class Mittens { private final Ui ui; private final Storage storage; private final TaskList taskList; - + public Mittens(String storageFilePath) { this.ui = new TextUi(); this.storage = new Storage(storageFilePath); - + TaskList temp; try { temp = this.storage.load(); @@ -35,18 +35,18 @@ public Mittens(String storageFilePath) { ui.showErrorMessage(newException); throw new RuntimeException("Error occurred during initialization"); } - + this.taskList = temp; } public void run() { CommandParser commandParser = new CommandParser(); - + ui.showGreetingMessage(); while (true) { String input = ui.getUserInput(); - + try { Command command = commandParser.parse(input); command.execute(this.taskList, this.ui, this.storage); @@ -58,7 +58,7 @@ public void run() { } } } - + public static void main(String[] args) { Mittens mittens = new Mittens("data/data.txt"); mittens.run(); diff --git a/src/main/java/mittens/MittensException.java b/src/main/java/mittens/MittensException.java index 82d8bb84ee..eb28387f63 100644 --- a/src/main/java/mittens/MittensException.java +++ b/src/main/java/mittens/MittensException.java @@ -3,7 +3,7 @@ public class MittensException extends Exception { private final String mittensMessage; private final String helpMessage; - + public MittensException(String message, String mittensMessage, String helpMessage) { super(message); this.mittensMessage = mittensMessage; @@ -13,25 +13,25 @@ public MittensException(String message, String mittensMessage, String helpMessag public String getMittensMessage() { return this.mittensMessage; } - + public String getHelpMessage() { return this.helpMessage; } public void echo() { String message = """ - + /\\_/\\ %s >x.x< ( %s ) / \\ %s (___)_/ - + Error: %s %s """.formatted("_".repeat(this.getMittensMessage().length() + 2), - this.getMittensMessage(), "-".repeat(this.getMittensMessage().length() + 2), - this.getMessage(), this.helpMessage); - + this.getMittensMessage(), "-".repeat(this.getMittensMessage().length() + 2), + this.getMessage(), this.helpMessage); + System.out.println(message); } } diff --git a/src/main/java/mittens/UnknownException.java b/src/main/java/mittens/UnknownException.java index adfb3d7d03..88c255330b 100644 --- a/src/main/java/mittens/UnknownException.java +++ b/src/main/java/mittens/UnknownException.java @@ -4,7 +4,7 @@ public class UnknownException extends MittensException { private static final String MITTENS_MESSAGE = "Meow?! Something went wrong..."; private static final String HELP_MESSAGE = "I'm not sure what went wrong. You can try again," + " or type 'help' to see a list of commands."; - + public UnknownException(String message) { super(message, MITTENS_MESSAGE, HELP_MESSAGE); } diff --git a/src/main/java/mittens/commands/AddCommand.java b/src/main/java/mittens/commands/AddCommand.java index e301be163c..410743c7ed 100644 --- a/src/main/java/mittens/commands/AddCommand.java +++ b/src/main/java/mittens/commands/AddCommand.java @@ -8,19 +8,19 @@ public class AddCommand extends Command { protected Task toAdd; - + public AddCommand(Task toAdd) { super(); this.toAdd = toAdd; } - + @Override public void execute(TaskList tasks, Ui ui, Storage storage) { try { tasks.addTask(this.toAdd); - + storage.save(tasks); - + ui.showRegularMessage("I've added \"%s\" to your list :3" .formatted(this.toAdd.getDescription())); } catch (MittensException e) { diff --git a/src/main/java/mittens/commands/Command.java b/src/main/java/mittens/commands/Command.java index 622a2aeaab..86e9aed5e2 100644 --- a/src/main/java/mittens/commands/Command.java +++ b/src/main/java/mittens/commands/Command.java @@ -6,12 +6,13 @@ public abstract class Command { protected boolean isExit; - + public Command() { this.isExit = false; } - + public abstract void execute(TaskList tasks, Ui ui, Storage storage); + public boolean isExit() { return this.isExit; } diff --git a/src/main/java/mittens/commands/ListCommand.java b/src/main/java/mittens/commands/ListCommand.java index 89bd73afb9..7894ee0cab 100644 --- a/src/main/java/mittens/commands/ListCommand.java +++ b/src/main/java/mittens/commands/ListCommand.java @@ -12,17 +12,17 @@ public class ListCommand extends Command { @Override public void execute(TaskList tasks, Ui ui, Storage storage) { List messages = new ArrayList<>(); - + int count = tasks.getCount(); if (count == 0) { messages.add("Meow?! Your list is empty!"); } - + for (int i = 0; i < count; i++) { Task task = tasks.getTask(i); messages.add("%d. %s".formatted(i + 1, task)); } - + ui.showRegularMessage(messages); } } diff --git a/src/main/java/mittens/parser/BadInputException.java b/src/main/java/mittens/parser/BadInputException.java index c9d7cdcda0..fa28712b09 100644 --- a/src/main/java/mittens/parser/BadInputException.java +++ b/src/main/java/mittens/parser/BadInputException.java @@ -6,7 +6,7 @@ public class BadInputException extends MittensException { private static final String MITTENS_MESSAGE = "Meow?! What does that mean?"; private static final String HELP_MESSAGE = "Type 'help' to see a list of commands," + " or 'help ' to see more about a specific command."; - + public BadInputException(String message) { super(message, MITTENS_MESSAGE, HELP_MESSAGE); } diff --git a/src/main/java/mittens/storage/Storage.java b/src/main/java/mittens/storage/Storage.java index 635938d132..f3cc25892f 100644 --- a/src/main/java/mittens/storage/Storage.java +++ b/src/main/java/mittens/storage/Storage.java @@ -15,11 +15,11 @@ public class Storage { protected final Path filePath; - + public Storage(String filePath) { this.filePath = Path.of(filePath); } - + public void save(TaskList taskList) throws StorageFileException { try { ArrayList encodedTasks = new ArrayList<>(); @@ -48,7 +48,7 @@ public void save(TaskList taskList) throws StorageFileException { throw new StorageFileException("Unable to write to storage file"); } } - + public TaskList load() throws StorageFileException { if (!Files.exists(this.filePath)) { try { @@ -59,7 +59,7 @@ public TaskList load() throws StorageFileException { } return new TaskList(); } - + try { ArrayList encodedTasks = new ArrayList<>(Files.readAllLines(this.filePath)); TaskList taskList = new TaskList(); @@ -67,18 +67,18 @@ public TaskList load() throws StorageFileException { String[] taskComponents = encodedTask.split("\\|"); Task task = null; switch (taskComponents[0]) { - case "T": - task = new Todo(taskComponents[2]); - break; - case "D": - task = new Deadline(taskComponents[2], LocalDate.parse(taskComponents[3])); - break; - case "E": - task = new Event(taskComponents[2], LocalDate.parse(taskComponents[3]), - LocalDate.parse(taskComponents[4])); - break; - default: - throw new StorageFileException("Corrupted storage file"); + case "T": + task = new Todo(taskComponents[2]); + break; + case "D": + task = new Deadline(taskComponents[2], LocalDate.parse(taskComponents[3])); + break; + case "E": + task = new Event(taskComponents[2], LocalDate.parse(taskComponents[3]), + LocalDate.parse(taskComponents[4])); + break; + default: + throw new StorageFileException("Corrupted storage file"); } if (taskComponents[1].equals("X")) { task.markAsDone(); diff --git a/src/main/java/mittens/task/TaskList.java b/src/main/java/mittens/task/TaskList.java index a877129402..e207c3e31f 100644 --- a/src/main/java/mittens/task/TaskList.java +++ b/src/main/java/mittens/task/TaskList.java @@ -5,7 +5,7 @@ public class TaskList { protected final ArrayList tasks; - + public TaskList() { this.tasks = new ArrayList<>(); } @@ -17,15 +17,15 @@ public List getTasks() { public Task getTask(int index) { return this.tasks.get(index); } - + public int getCount() { return this.tasks.size(); } - + public void addTask(Task task) { this.tasks.add(task); } - + public Task markTaskAsDone(int index) { Task task = this.tasks.get(index); task.markAsDone(); @@ -37,7 +37,7 @@ public Task markTaskAsNotDone(int index) { task.markAsNotDone(); return task; } - + public Task deleteTask(int index) { return this.tasks.remove(index); } diff --git a/src/main/java/mittens/ui/TextUi.java b/src/main/java/mittens/ui/TextUi.java index 2ad4e62569..cd8a2b03da 100644 --- a/src/main/java/mittens/ui/TextUi.java +++ b/src/main/java/mittens/ui/TextUi.java @@ -9,16 +9,16 @@ public class TextUi extends Ui { private final static String GREETING_MESSAGE = """ - /\\_/\\ ____________________ - >^,^< / Hi, I'm Mittens! \\ - / \\ \\ I'm a cat! Meow :3 / - (___)_/ --------------------"""; + /\\_/\\ ____________________ + >^,^< / Hi, I'm Mittens! \\ + / \\ \\ I'm a cat! Meow :3 / + (___)_/ --------------------"""; private final static String GOODBYE_MESSAGE = """ - /\\_/\\ _____________ - >^,^< ( Bye-bye! :3 ) - / \\ ------------- - (___)_/"""; + /\\_/\\ _____________ + >^,^< ( Bye-bye! :3 ) + / \\ ------------- + (___)_/"""; private final Scanner in; private final PrintStream out; @@ -31,11 +31,11 @@ public TextUi(InputStream in, PrintStream out) { this.in = new Scanner(in); this.out = out; } - + public void printMessage(String message) { this.out.println(message); } - + public void printBlankLine() { this.out.println(); } @@ -43,15 +43,15 @@ public void printBlankLine() { public void printMittens(String message) { int len = message.length(); String uiMessage = """ - /\\_/\\ %s - >^,^< ( %s ) - / \\ %s - (___)_/""".formatted("_".repeat(len + 2), + /\\_/\\ %s + >^,^< ( %s ) + / \\ %s + (___)_/""".formatted("_".repeat(len + 2), message, "-".repeat(len + 2)); this.out.println(uiMessage); } - + public void printErrorMessage(MittensException e) { String mittensMessage = e.getMittensMessage(); int len = mittensMessage.length(); @@ -64,7 +64,7 @@ public void printErrorMessage(MittensException e) { >x.x< ( %s ) / \\ %s (___)_/ - + Error: %s %s""".formatted("_".repeat(len + 2), mittensMessage, "-".repeat(len + 2), errorMessage, helpMessage); @@ -94,12 +94,12 @@ public void showRegularMessage(List messages) { } this.printBlankLine(); } - + @Override public void showRegularMessage(String... messages) { showRegularMessage(List.of(messages)); } - + @Override public void showMittensMessage(List messages) { this.printBlankLine(); diff --git a/src/main/java/mittens/ui/Ui.java b/src/main/java/mittens/ui/Ui.java index 706c5ad248..a302872feb 100644 --- a/src/main/java/mittens/ui/Ui.java +++ b/src/main/java/mittens/ui/Ui.java @@ -6,10 +6,16 @@ public abstract class Ui { public abstract void showGreetingMessage(); + public abstract void showGoodbyeMessage(); + public abstract void showRegularMessage(List messages); + public abstract void showRegularMessage(String... messages); + public abstract void showMittensMessage(List messages); + public abstract void showErrorMessage(MittensException e); + public abstract String getUserInput(); } diff --git a/src/test/java/mittens/parser/CommandParserTest.java b/src/test/java/mittens/parser/CommandParserTest.java index f90e85a4a9..4c03b99866 100644 --- a/src/test/java/mittens/parser/CommandParserTest.java +++ b/src/test/java/mittens/parser/CommandParserTest.java @@ -27,7 +27,7 @@ public void parse_listCommand_parsedCorrectly() { fail(); } } - + @Test public void parse_addCommandTodo_parsedCorrectly() { try { @@ -60,7 +60,7 @@ public void parse_addCommandEvent_parsedCorrectly() { fail(); } } - + @Test public void parse_markCommand_parsedCorrectly() { try { @@ -70,7 +70,7 @@ public void parse_markCommand_parsedCorrectly() { fail(); } } - + @Test public void parse_unmarkCommand_parsedCorrectly() { try { @@ -80,7 +80,7 @@ public void parse_unmarkCommand_parsedCorrectly() { fail(); } } - + @Test public void parse_deleteCommand_parsedCorrectly() { try { @@ -90,7 +90,7 @@ public void parse_deleteCommand_parsedCorrectly() { fail(); } } - + @Test public void parse_exitCommand_parsedCorrectly() { try { @@ -100,7 +100,7 @@ public void parse_exitCommand_parsedCorrectly() { fail(); } } - + @Test public void parse_unknownCommand_exceptionThrown() { try { @@ -120,7 +120,7 @@ public void parse_addCommandDeadlineInvalidDateFormat_exceptionThrown() { assertEquals("Invalid date format for 'by' flag", e.getMessage()); } } - + @Test public void parse_addCommandDeadlineUnknownFlag_exceptionThrown() { try { @@ -130,7 +130,7 @@ public void parse_addCommandDeadlineUnknownFlag_exceptionThrown() { assertEquals("'unknown' is not a known flag", e.getMessage()); } } - + @Test public void parse_addCommandDeadlineDuplicateFlag_exceptionThrown() { try { @@ -140,7 +140,7 @@ public void parse_addCommandDeadlineDuplicateFlag_exceptionThrown() { assertEquals("Found duplicate of 'by' flag", e.getMessage()); } } - + @Test public void parse_addCommandEventNoToFlag_exceptionThrown() { try { diff --git a/src/test/java/mittens/storage/StorageTest.java b/src/test/java/mittens/storage/StorageTest.java index 55d086e2a3..c50fdfb84f 100644 --- a/src/test/java/mittens/storage/StorageTest.java +++ b/src/test/java/mittens/storage/StorageTest.java @@ -21,20 +21,20 @@ public class StorageTest { @Test public void save_validTaskList_success(@TempDir Path tempDir) { Path filePath = tempDir.resolve("data.txt"); - + TaskList tasks = new TaskList(); tasks.addTask(new Todo("todoName")); tasks.addTask(new Deadline("deadlineName", LocalDate.of(2024, 1, 31))); tasks.addTask(new Event("eventName", LocalDate.of(2024, 1, 31), LocalDate.of(2024, 2, 1))); tasks.markTaskAsDone(1); - + Storage storage = new Storage(filePath.toString()); try { storage.save(tasks); } catch (StorageFileException e) { fail(); } - + try { List lines = Files.readAllLines(filePath); assertEquals(3, lines.size()); @@ -45,18 +45,18 @@ public void save_validTaskList_success(@TempDir Path tempDir) { fail(); } } - + @Test public void load_validTaskList_success(@TempDir Path tempDir) { Path filePath = tempDir.resolve("data.txt"); try { Files.createFile(filePath); - Files.write(filePath, List.of("T| |todoName","D|X|deadlineName|2024-01-31", + Files.write(filePath, List.of("T| |todoName", "D|X|deadlineName|2024-01-31", "E| |eventName|2024-01-31|2024-02-01")); } catch (IOException e) { fail(); } - + Storage storage = new Storage(filePath.toString()); try { TaskList tasks = storage.load(); From 2d252ab0ceae608372fc59295ceddb224a6541d0 Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 20 Sep 2024 16:18:15 +0800 Subject: [PATCH 079/105] Add find tasks by keyword functionality to TaskList --- src/main/java/mittens/task/TaskList.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/mittens/task/TaskList.java b/src/main/java/mittens/task/TaskList.java index a877129402..5f63c4a9f0 100644 --- a/src/main/java/mittens/task/TaskList.java +++ b/src/main/java/mittens/task/TaskList.java @@ -41,4 +41,20 @@ public Task markTaskAsNotDone(int index) { public Task deleteTask(int index) { return this.tasks.remove(index); } + + /** + * Finds tasks that contain the given keyword in their description. + * + * @param keyword The keyword to search for. + * @return A list of tasks that contain the keyword. + */ + public List findTasks(String keyword) { + List matchingTasks = new ArrayList<>(); + for (Task task : this.tasks) { + if (task.getDescription().contains(keyword)) { + matchingTasks.add(task); + } + } + return matchingTasks; + } } From 5cd76741b7392449e9e32276f91623528e3c1d36 Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 20 Sep 2024 16:18:44 +0800 Subject: [PATCH 080/105] Add FindCommand for finding tasks by given keyword --- .../java/mittens/commands/FindCommand.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/main/java/mittens/commands/FindCommand.java diff --git a/src/main/java/mittens/commands/FindCommand.java b/src/main/java/mittens/commands/FindCommand.java new file mode 100644 index 0000000000..8efd224df3 --- /dev/null +++ b/src/main/java/mittens/commands/FindCommand.java @@ -0,0 +1,41 @@ +package mittens.commands; + +import java.util.ArrayList; +import java.util.List; + +import mittens.storage.Storage; +import mittens.task.Task; +import mittens.task.TaskList; +import mittens.ui.Ui; + +/** + * Represents a command for finding tasks that match a keyword. + */ +public class FindCommand extends Command { + protected String keyword; + + public FindCommand(String keyword) { + super(); + this.keyword = keyword; + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + List matchingTasks = tasks.findTasks(this.keyword); + List messages = new ArrayList<>(); + + int count = matchingTasks.size(); + if (count == 0) { + messages.add("Meow?! I couldn't find anything with that keyword!"); + } else { + messages.add("I found %d tasks with that keyword, here they are :3".formatted(count)); + } + + for (int i = 0; i < count; i++) { + Task task = tasks.getTask(i); + messages.add("%d. %s".formatted(i + 1, task)); + } + + ui.showRegularMessage(messages); + } +} From 95d14a39225d81c5f6cada390528eb693101e170 Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 20 Sep 2024 16:20:17 +0800 Subject: [PATCH 081/105] Restore deleted part of message --- src/main/java/mittens/commands/ListCommand.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/mittens/commands/ListCommand.java b/src/main/java/mittens/commands/ListCommand.java index 89bd73afb9..16f9bed2b1 100644 --- a/src/main/java/mittens/commands/ListCommand.java +++ b/src/main/java/mittens/commands/ListCommand.java @@ -16,6 +16,8 @@ public void execute(TaskList tasks, Ui ui, Storage storage) { int count = tasks.getCount(); if (count == 0) { messages.add("Meow?! Your list is empty!"); + } else { + messages.add("You have %d tasks in your list, here they are :3".formatted(count)); } for (int i = 0; i < count; i++) { From 7e209a96e50fa23721a4a5158ee4c8a46a39cf2b Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 20 Sep 2024 16:32:25 +0800 Subject: [PATCH 082/105] Fix typo --- src/main/java/mittens/commands/FindCommand.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/mittens/commands/FindCommand.java b/src/main/java/mittens/commands/FindCommand.java index 8efd224df3..98bc345a7e 100644 --- a/src/main/java/mittens/commands/FindCommand.java +++ b/src/main/java/mittens/commands/FindCommand.java @@ -32,7 +32,7 @@ public void execute(TaskList tasks, Ui ui, Storage storage) { } for (int i = 0; i < count; i++) { - Task task = tasks.getTask(i); + Task task = matchingTasks.get(i); messages.add("%d. %s".formatted(i + 1, task)); } From a93b874308a26eb0bd12b613fe260edb298ecd4c Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 20 Sep 2024 16:33:04 +0800 Subject: [PATCH 083/105] Update CommandParser to detect find commands --- src/main/java/mittens/parser/CommandParser.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/mittens/parser/CommandParser.java b/src/main/java/mittens/parser/CommandParser.java index ee5fb5b7a2..a758f58310 100644 --- a/src/main/java/mittens/parser/CommandParser.java +++ b/src/main/java/mittens/parser/CommandParser.java @@ -35,6 +35,10 @@ public Command parse(String input) throws BadInputException { } catch (NumberFormatException e) { throw new BadInputException("Argument for command 'delete' must be a number"); } + } else if (input.startsWith("find")) { + String keyword = input.substring(5); + + return new FindCommand(keyword); } else if (input.startsWith("todo")) { String description = input.substring(5); From 54339a56ad1ebea70581aecde78cbd7eff99a8ae Mon Sep 17 00:00:00 2001 From: izruff Date: Fri, 20 Sep 2024 16:51:54 +0800 Subject: [PATCH 084/105] Fix missing import statement --- src/main/java/mittens/parser/CommandParser.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/mittens/parser/CommandParser.java b/src/main/java/mittens/parser/CommandParser.java index b56cebbdc3..fd678bd3ce 100644 --- a/src/main/java/mittens/parser/CommandParser.java +++ b/src/main/java/mittens/parser/CommandParser.java @@ -4,6 +4,7 @@ import mittens.commands.Command; import mittens.commands.DeleteCommand; import mittens.commands.ExitCommand; +import mittens.commands.FindCommand; import mittens.commands.ListCommand; import mittens.commands.MarkCommand; import mittens.commands.UnmarkCommand; From 2003c7de2fe9c9aad42aea7a7a20463ca34206dd Mon Sep 17 00:00:00 2001 From: izruff Date: Mon, 23 Sep 2024 05:11:02 +0800 Subject: [PATCH 085/105] Mittens.java: Refactor code and add method to load task list after initialization --- src/main/java/mittens/Mittens.java | 71 ++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 18 deletions(-) diff --git a/src/main/java/mittens/Mittens.java b/src/main/java/mittens/Mittens.java index 4e13202afc..7d03f93df4 100644 --- a/src/main/java/mittens/Mittens.java +++ b/src/main/java/mittens/Mittens.java @@ -1,5 +1,6 @@ package mittens; +import javafx.application.Application; import mittens.commands.Command; import mittens.parser.BadInputException; import mittens.parser.CommandParser; @@ -8,28 +9,39 @@ import mittens.task.TaskList; import mittens.ui.TextUi; import mittens.ui.Ui; +import mittens.ui.fx.MainApp; /** * Represents the main class where the program is initialized and the main loop is run. */ public class Mittens { - + public static final boolean IS_USING_GUI = true; + public static final String DEFAULT_STORAGE_FILE_PATH = "data/data.txt"; + private final Ui ui; private final Storage storage; - private final TaskList taskList; + private TaskList taskList; /** - * Creates a new Mittens object with the specified storage file path. - * + * Creates a new Mittens object with the specified UI object and storage file path. + * + * @param ui The UI object * @param storageFilePath The file path to the storage file */ - public Mittens(String storageFilePath) { - this.ui = new TextUi(); + public Mittens(Ui ui, String storageFilePath) { + this.ui = ui; this.storage = new Storage(storageFilePath); + this.loadTaskList(); + } + + /** + * Initializes the task list by loading it from the storage file. + */ + public void loadTaskList() { TaskList temp; try { - temp = this.storage.load(); + temp = storage.load(); } catch (StorageFileException e) { ui.showErrorMessage(e); ui.showRegularMessage("Would you like to continue with a new list instead? (y/n)"); @@ -47,31 +59,54 @@ public Mittens(String storageFilePath) { this.taskList = temp; } + /** + * Parses the given input and executes the command, then returns a + * boolean indicating whether the program should exit. + * + * @param input The input to process + * @return A boolean indicating whether the program should exit + */ + public boolean process(String input) { + CommandParser commandParser = new CommandParser(); + try { + Command command = commandParser.parse(input); + command.execute(this.taskList, this.ui, this.storage); + return command.isExit(); + } catch (BadInputException e) { + ui.showErrorMessage(e); + return false; + } + } + /** * Runs the main loop of the program which accepts user input. */ public void run() { + if (taskList == null) { + throw new RuntimeException("Task list is not initialized"); + } + CommandParser commandParser = new CommandParser(); ui.showGreetingMessage(); while (true) { String input = ui.getUserInput(); - - try { - Command command = commandParser.parse(input); - command.execute(this.taskList, this.ui, this.storage); - if (command.isExit()) { - break; - } - } catch (BadInputException e) { - ui.showErrorMessage(e); + boolean shouldExit = process(input); + if (shouldExit) { + break; } } + } public static void main(String[] args) { - Mittens mittens = new Mittens("data/data.txt"); - mittens.run(); + if (IS_USING_GUI) { + Application.launch(MainApp.class); + } else { + Mittens mittens = new Mittens(new TextUi(), DEFAULT_STORAGE_FILE_PATH); + mittens.run(); + } + } } From 9ce94a48b7f8bf6c5de98f4551a705d61947be84 Mon Sep 17 00:00:00 2001 From: izruff Date: Mon, 23 Sep 2024 05:12:36 +0800 Subject: [PATCH 086/105] Update dependencies --- build.gradle | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/build.gradle b/build.gradle index 930da5839c..886eb68e46 100644 --- a/build.gradle +++ b/build.gradle @@ -12,6 +12,21 @@ repositories { dependencies { testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.10.0' testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.10.0' + + String javaFxVersion = '17.0.7' + + 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 { From 894d8b9a078c77858ca77855ab9a5f35b7f92637 Mon Sep 17 00:00:00 2001 From: izruff Date: Mon, 23 Sep 2024 06:48:02 +0800 Subject: [PATCH 087/105] Implement JavaFxUi and refactor Ui class --- src/main/java/mittens/ui/JavaFxUi.java | 45 ++++++++++++++++++++++++++ src/main/java/mittens/ui/TextUi.java | 6 ---- src/main/java/mittens/ui/Ui.java | 36 ++++++++++++++------- 3 files changed, 69 insertions(+), 18 deletions(-) create mode 100644 src/main/java/mittens/ui/JavaFxUi.java diff --git a/src/main/java/mittens/ui/JavaFxUi.java b/src/main/java/mittens/ui/JavaFxUi.java new file mode 100644 index 0000000000..636efabd06 --- /dev/null +++ b/src/main/java/mittens/ui/JavaFxUi.java @@ -0,0 +1,45 @@ +package mittens.ui; + +import java.io.InputStream; +import java.util.List; + +import mittens.MittensException; +import mittens.ui.fx.MainWindow; + +public class JavaFxUi extends Ui { + private final MainWindow mainWindow; + + public JavaFxUi(MainWindow mainWindow) { + this.mainWindow = mainWindow; + } + + @Override + public void showGreetingMessage() { + mainWindow.printMittensMessage(List.of("Hi, I'm Mittens!", "I'm a cat! Meow :3")); + } + + @Override + public void showGoodbyeMessage() { + mainWindow.printMittensMessage(List.of("Bye-bye! :3")); + } + + @Override + public void showRegularMessage(List messages) { + mainWindow.printRegularMessage(messages); + } + + @Override + public void showMittensMessage(List messages) { + mainWindow.printMittensMessage(messages); + } + + @Override + public void showErrorMessage(MittensException e) { + mainWindow.printErrorMessage(e); + } + + @Override + public String getUserInput() { + return null; + } +} diff --git a/src/main/java/mittens/ui/TextUi.java b/src/main/java/mittens/ui/TextUi.java index daedb6d6ab..8dc97ab0a7 100644 --- a/src/main/java/mittens/ui/TextUi.java +++ b/src/main/java/mittens/ui/TextUi.java @@ -11,7 +11,6 @@ * Represents the CLI version of the user interface. */ public class TextUi extends Ui { - private final static String GREETING_MESSAGE = """ /\\_/\\ ____________________ >^,^< / Hi, I'm Mittens! \\ @@ -126,11 +125,6 @@ public void showRegularMessage(List messages) { this.printBlankLine(); } - @Override - public void showRegularMessage(String... messages) { - showRegularMessage(List.of(messages)); - } - @Override public void showMittensMessage(List messages) { this.printBlankLine(); diff --git a/src/main/java/mittens/ui/Ui.java b/src/main/java/mittens/ui/Ui.java index ace83f2977..255e11579c 100644 --- a/src/main/java/mittens/ui/Ui.java +++ b/src/main/java/mittens/ui/Ui.java @@ -2,13 +2,21 @@ import mittens.MittensException; +import java.io.InputStream; import java.util.List; +import java.util.Scanner; /** * Represents the user interface of the application. */ public abstract class Ui { - + /** + * Waits for the user to input a string command and returns that string. + * + * @return The user input + */ + public abstract String getUserInput(); + /** * Shows the greeting message to be displayed at the start of the program. */ @@ -26,13 +34,6 @@ public abstract class Ui { */ public abstract void showRegularMessage(List messages); - /** - * Generates a combined message formed by the given strings. - * - * @param messages The strings to output - */ - public abstract void showRegularMessage(String... messages); - /** * Generates a combined message accompanied by the cute cat Mittens. * @@ -48,9 +49,20 @@ public abstract class Ui { public abstract void showErrorMessage(MittensException e); /** - * Waits for the user to input a string command and returns that string. - * - * @return The user input + * Generates a combined message formed by the given strings. + * + * @param messages The strings to output */ - public abstract String getUserInput(); + public void showRegularMessage(String... messages) { + showRegularMessage(List.of(messages)); + }; + + /** + * Generates a combined message accompanied by the cute cat Mittens. + * + * @param messages The strings to output + */ + public void showMittensMessage(String... messages) { + showMittensMessage(List.of(messages)); + }; } From e604d36662585a7ce4186017dfeb899eee7abee0 Mon Sep 17 00:00:00 2001 From: izruff Date: Mon, 23 Sep 2024 06:57:17 +0800 Subject: [PATCH 088/105] Implement JavaFX GUI application --- src/main/java/mittens/Mittens.java | 14 ++-- src/main/java/mittens/ui/fx/DialogBox.java | 76 ++++++++++++++++++++ src/main/java/mittens/ui/fx/MainApp.java | 38 ++++++++++ src/main/java/mittens/ui/fx/MainWindow.java | 70 ++++++++++++++++++ src/main/resources/images/errorAvatar.jpg | Bin 0 -> 38569 bytes src/main/resources/images/mittensAvatar.jpg | Bin 0 -> 7818 bytes src/main/resources/images/userAvatar.png | Bin 0 -> 8217 bytes src/main/resources/views/DialogBox.fxml | 20 ++++++ src/main/resources/views/MainWindow.fxml | 46 ++++++++++++ 9 files changed, 260 insertions(+), 4 deletions(-) create mode 100644 src/main/java/mittens/ui/fx/DialogBox.java create mode 100644 src/main/java/mittens/ui/fx/MainApp.java create mode 100644 src/main/java/mittens/ui/fx/MainWindow.java create mode 100644 src/main/resources/images/errorAvatar.jpg create mode 100644 src/main/resources/images/mittensAvatar.jpg create mode 100644 src/main/resources/images/userAvatar.png create mode 100644 src/main/resources/views/DialogBox.fxml create mode 100644 src/main/resources/views/MainWindow.fxml diff --git a/src/main/java/mittens/Mittens.java b/src/main/java/mittens/Mittens.java index 7d03f93df4..d4c42f5443 100644 --- a/src/main/java/mittens/Mittens.java +++ b/src/main/java/mittens/Mittens.java @@ -18,6 +18,7 @@ public class Mittens { public static final boolean IS_USING_GUI = true; public static final String DEFAULT_STORAGE_FILE_PATH = "data/data.txt"; + private final CommandParser commandParser = new CommandParser(); private final Ui ui; private final Storage storage; private TaskList taskList; @@ -79,16 +80,21 @@ public boolean process(String input) { } /** - * Runs the main loop of the program which accepts user input. + * Prepares the program to run and shows the greeting message. */ - public void run() { + public void prepare_run() { if (taskList == null) { throw new RuntimeException("Task list is not initialized"); } - CommandParser commandParser = new CommandParser(); - ui.showGreetingMessage(); + } + + /** + * Runs the main loop of the program which accepts user input. + */ + public void run() { + prepare_run(); while (true) { String input = ui.getUserInput(); diff --git a/src/main/java/mittens/ui/fx/DialogBox.java b/src/main/java/mittens/ui/fx/DialogBox.java new file mode 100644 index 0000000000..f38438fbfa --- /dev/null +++ b/src/main/java/mittens/ui/fx/DialogBox.java @@ -0,0 +1,76 @@ +package mittens.ui.fx; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +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 mittens.MittensException; + +/** + * 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 { + private static final Image USER_AVATAR = new Image(DialogBox.class.getResourceAsStream("/images/userAvatar.png")); + private static final Image MITTENS_AVATAR = new Image(DialogBox.class.getResourceAsStream("/images/mittensAvatar.jpg")); + private static final Image ERROR_AVATAR = new Image(DialogBox.class.getResourceAsStream("/images/errorAvatar.jpg")); + + @FXML + private Label dialog; + @FXML + private ImageView displayPicture; + + private DialogBox(String text, Image img) { + try { + FXMLLoader fxmlLoader = new FXMLLoader(MainWindow.class.getResource("/views/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 ofUserMessage(String text) { + return new DialogBox(text, USER_AVATAR); + } + + public static DialogBox ofRegularMessage(List text) { + var db = new DialogBox(String.join("\n", text), MITTENS_AVATAR); + db.flip(); + return db; + } + + public static DialogBox ofMittensMessage(List text) { + return new DialogBox(String.join("\n", text), MITTENS_AVATAR); + } + + public static DialogBox ofErrorMessage(MittensException e) { + var db = new DialogBox(e.getMessage(), ERROR_AVATAR); + db.flip(); + return db; + } +} diff --git a/src/main/java/mittens/ui/fx/MainApp.java b/src/main/java/mittens/ui/fx/MainApp.java new file mode 100644 index 0000000000..6805ee831d --- /dev/null +++ b/src/main/java/mittens/ui/fx/MainApp.java @@ -0,0 +1,38 @@ +package mittens.ui.fx; + +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; +import mittens.Mittens; +import mittens.ui.JavaFxUi; + +public class MainApp extends Application { + @Override + public void start(Stage stage) { + try { + // Load the FXML file + FXMLLoader fxmlLoader = new FXMLLoader(MainApp.class.getResource("/views/MainWindow.fxml")); + AnchorPane ap = fxmlLoader.load(); + + Scene scene = new Scene(ap); + stage.setScene(scene); + + // Set up Mittens + JavaFxUi ui = new JavaFxUi(fxmlLoader.getController()); + + Mittens mittens = new Mittens(ui, Mittens.DEFAULT_STORAGE_FILE_PATH); + + fxmlLoader.getController().initialize(mittens); + + // Run the application + stage.setTitle("Mittens"); + stage.show(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/mittens/ui/fx/MainWindow.java b/src/main/java/mittens/ui/fx/MainWindow.java new file mode 100644 index 0000000000..95848e6de3 --- /dev/null +++ b/src/main/java/mittens/ui/fx/MainWindow.java @@ -0,0 +1,70 @@ +package mittens.ui.fx; + +import java.util.List; + +import javafx.fxml.FXML; +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 mittens.Mittens; +import mittens.MittensException; + +public class MainWindow extends AnchorPane { + @FXML + private ScrollPane scrollPane; + @FXML + private VBox dialogContainer; + @FXML + private TextField userInput; + @FXML + private Button sendButton; + + private Mittens mittens; + + @FXML + public void initialize(Mittens mittens) { + this.mittens = mittens; + + scrollPane.vvalueProperty().bind(dialogContainer.heightProperty()); + + mittens.prepare_run(); + } + + @FXML + public void handleUserInput() { + String input = userInput.getText(); + if (input.isEmpty()) { + return; + } + + printUserMessage(input); + userInput.clear(); + + boolean shouldExit = mittens.process(input); + if (shouldExit) { + scrollPane.getScene().getWindow().hide(); + } + } + + @FXML + public void printUserMessage(String message) { + dialogContainer.getChildren().add(DialogBox.ofUserMessage(message)); + } + + @FXML + public void printRegularMessage(List messages) { + dialogContainer.getChildren().add(DialogBox.ofRegularMessage(messages)); + } + + @FXML + public void printMittensMessage(List messages) { + dialogContainer.getChildren().add(DialogBox.ofMittensMessage(messages)); + } + + @FXML + public void printErrorMessage(MittensException e) { + dialogContainer.getChildren().add(DialogBox.ofErrorMessage(e)); + } +} diff --git a/src/main/resources/images/errorAvatar.jpg b/src/main/resources/images/errorAvatar.jpg new file mode 100644 index 0000000000000000000000000000000000000000..388c82e83f6e47933fba15adee64282e74197cc4 GIT binary patch literal 38569 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�@V>!3*v9h9~ zRvKkE5{00T;XUo5go{^NpA!s4%G)u`rr|~?TG?hRc!C1OtE^LrW3p73by{APxc)2u z07xaozTskzE^)v;lc0i~*=>Kr!8VxOFb`z~Ja~v5mXrp%Oo6LK^qAjymn*mo|vQQ z-k<*ffxqmoy?}}Xx~1uWfB1i={{Z1{`z>B0jgY;Zen*R`_OhmqwM#x$e6|+stg=>Q z@qCRg(z&v7BOG)Ve6bK##F3uFD({4M@U<2)Dv1g?R+X6}0mUKh9u}g2?@9=ybcBOy zvJxz=EEJjGTH>k@TBfv{T0r2E01Z&_v{Y0%YI0~-BLN8oboEUQF7k_sT~t-X)E>wI z+OXKc?t)eTbQKT+kwJ4#yD1w%#X%ZI(4-4cEDb1dJ(Fs*x~WjE1seqwCEgUV1lQq6 z3PR)pLg0yYYS4Fu0YN?#Z|y}*t^}wTdqh=7TI*0w*H}wrHi#A0p|$)ed1xDOT<>x< zC9XaZ2XShu{D|4I?JAiaUM7!*%FXlh8uYDJIF0%6w|YNRg|NF9DAZ5$+LwTTS$l;y zx=891x%xC|aq@ZP{A-^TeXb1LXz^pk$CSwXwwqgc*|_+i3I71AAr?aU7ozf{m#PNH z;(k9H`&;xiYL)cDIUChQQJmEv;Xa|qH*E%{Mihbj=}{?$Ra%3D>Nj=0qmoI`b}|BRuseOd?+G}ZtX~o_q5hW^4d^C!Z!*EOG8qn zlS?5}xYbgu4*OD>UP(X=_d#KsD$7c*kN8$?10(Jefl7>zDXptoMW!7Dz(uO@lzfp5 zaj=(kxE&=tpfB1j4^p;0Ds3M`bQ?zUgjRzpWPk0R13v6{ECLU1?V> zadJ`4k==<2e23MP?`GSyt`*r~Vw~+D=qZVh0?%aUJNQfv1+;u3;=7N+{*`!$_c;Nz zGRZ~5!7HE?;G;ORkizJ!jjZ;^#m3g7zD**#Do$YLX+toY4n5R@0RzBGc_GDjE%rl7 z&5g3Kw2NsJzH!xk6lKnl@K?6&h4gYwno73$0@ZZqre~%v{sGhf0Pwf{ma5G3yKmFI zIR60l8~)2ovX{4?$n$l6(2--Ztt&x2m5V)s=d?I!ZZOBmj-A<4mAVUGCN4x;qby)L zirl!YdE%qlQG0f_W^UCCn1~lka_FhV_fubm8wQaAR-|MO8$eUHX42k1m4Iz>>hig2 zA}MzerAS(dP#P2vEfDg#Ye3LKK<*Kh#)5zN1QHiKf)t7&aYO(`<#19JR|P6Ujd@b2 ze5nhKUY7uo9YWNoqNP-IE>UZZl`Y1EG=JVDqIitTyK`w zUVKss(!Jy4QcugeI?@H7dtE&u14DZzH@%at$PoZk-CtO>g_|xEt(F(@b5H)4v%>W! zOw0{A(Vum`N0s1>@xJQcO)ZLMIzZPj8zCiT^7_v~nfaLlNE_{8H~h|C?m2Pt;r{@X zm8I+-BYoG#W%VQSBW5-z_GA5_t@2mA^xi4P!1t$dGFKxQJ=b1(d3>CG*PJdG@lts|TR02ZrFnLEe@+WaJO29!N{`}0>x;gJvI?YNc9V5Cg} z4b!P}z4cq1NH*~bb-E-W>?v?^&Aa;C`0FYh3x<@~y`mJRnp3$ptrCX-Pw{9j~lj>QHmON%l#y7YEKMPX1`8kiV;7tp0iHYLm z?$CQHt@l{KUI=OIsY8Q_gA{Q+M)HG2i~GD68es{tB!((TXV$mY7#hYH$TM=9JR zvI6I@i_x_aE^zRJk)_8(atoT^LIa7^RhZr=6<1V*I=gm3pyz@r(qE-m$W#ZD+@P_` z!UE*BxQ@ym<4Pf*+Tv)Bq^3I4*aCskcvgpHRk}J)4$_K0DS&M!lC==zEmUv`qd_dt zQOqD{*+70JN4cafcC7~&Z9#UDi_sIUBEXZoN|d5~r90^xlp)ENZA;^{LBA5SOGKUGdQDs!JKQzG;k^n?)d$eYlnr1G zt~*?B@}0TxG$!hDylKD1D0_0|Xw&w&jrQ6IZo+;?SCq6dt!MyNmoC4Nu9L$VvPSm2 z2bv)+Km}SUX1j4VQU%H8mn+@B+jGYt-A7G5lmlInHaZKqpUP{bk^l=Sm8vBRnCh^F zt#MP}FwyqAfFiAN91h4s?|^(K#zq=NKJ^E|Iov4I*c7+N>t`96;_9oaU2G?3DHaZeZF9(&aiW6WJv7 zCSUJOn;p;Y6$jybyCApet$Kf_{{Z1{`z;byf2Q020LVIj{uciLve6^`7trJVW0!yJ zL!|_5O>J=$w7_U~Q^Y7gYq=qyAOwkHzY4>RxFIdxf^1nCb2ELFIhb#<*Oinkiz_oK zNMo}ktzaLNopTq~-^Ogrv#_Y-MNdu5>wP{E{{T~wA6`}tZ>l2~>|@zJN?$aKJY7}i zwwp2sf1AtT{$(io?JO2P{9e*Lyp9QZ~Hhw%?F11Q-w-E>09haRv zk8)`gP2QI-y#E04)_7Vnb!ns)-B;45E=01BT_cnh5EM52u3dR;beg7|J^;VNLehd@d1&gQQ)Cj+Aonsv*u60+U_PXd6K1BT(Xgf)IXPsUw*MNqQQW zw%xT_M$@f1?j_$NFMoV;QDUrRM-C+fh zMM-b=LecN80UL#hFWkGT6-&S@y2Jh8$^;F5<4nSwmRd`@~y>@1}tCEBiuVA zt1LlHg7Dr(tgPvwaMdkrNis5+_lhn0E3zPP7fmhmO6(YoiNm@F#tTiY86mUC_VAME zPhh2^Bib&1gwc%P+gFAm=h-?q3w|X*k-)XW(Y3o;uEP%SyYyfUAfpR@U6s~~rOkk} zrnQ?yux)Q*o((jhsuZHlET$4)bMUlH)Sx9cFmelza1)}A_JY`TH3(2m0Hk(S4szgy z&Z3AFR1!0lAQnG_;j|6_e<-Drxp51SMJ^zBU3H`++QQ?U0SQ%J5xCN>_pH>!zqe$z z{{RSs^pni;+JK${Pnu0}u!B~kRwbg1_(dV))eay8A;77ritdikaV#paEYJ1aR|OAigC z5}D9o0X?k5Aw~fsn}W0CrwStN#FuO|s6Ni(WYu zrfhw5#^N+6esrqjW@2KnoUFK+U!AYc{ZITv>v_&_IUdt~nz7r|vojt{`7%EK%9gb_ z*XTUoT6AnCx~CGm#Vrz~83!m~thT4Ks`B`0P)~ApT+HrG8 z3Zu^ZA`b1{7gltj{u0BqrH0J}N-Haajdn&GU%5yk(Ft|9F5~gE_i?W2PjDJWhy)h_ z{$tr07op(^Y2*ubdu?lCbjb@#oaP1*vuK*h)zULn^sQuKMH7!10e8?2r zU!~j)sB>w*m9L;ni@c&>J&J~fVm5#+G!GC#KZR=+D8RQk1csVDw2U&&ip}~iM%cVK zCr0Rn*jepo4UuW^{DGyBf0Pbs(y1+2;*GJ86gi(|K$kEb1cx?>;sUY=4h`8V{s%{! zHNeHM8w$f&c#Ui20#X{3Ppbbocb$oCCYO1?U{>RycKZKILf}B^545L@tMwU~!-+M1RZmTZNu2N<$f}k-=#a+o5%@qty9_?m zFAsIF{?$qxfy0cki33Fs!kC1G%?|)XPJ-ML>Y_U!_Q@cHarEqy0c8R-Qrf`R5Iie_ zBZV{B1Hvfp%6BawtYR0WKGL*o_D~6}ps47DB?eJfT|_0&K!Mpqf+uLw2ReevP!?Ib zOp3c955DP*1HvPmEkQIX5eR4ywE~=WjlGoc+LNSMmLecoL)inJ`9%?Kk{ou7672;N zGz1HB;n=PvMd@O-pmFYzD|s~1V~Xq2#b;Hcz9!V_*E_nGRUqe8B{(MdpsTvUS=AF; zW|45?q`2Mk*-!ZL8(9MOd@WXX&ei8v9V*436bUhcLR+D2_E$LfO17b|%w12`{az^_ zg3Px^1Si{X9cV8*nbos$EX$Q7fc?2EtbzXk70NZgaQ^_hr&?cApUB5k?Hi9L0^$$k zpg+5MAHtViE^BFNWE^0R0FSk)g3Q_ z?7ZDqqn<-;V?Z7eH1Y}yZ5&Lc&blRxqkace@=#9F zOV84f@5a%S{3Q{)Q5&3JNSqDPC>Bknxu%mGc%37TDJ1OMS{1@JI0Llz!6P>2QcK%= z<4R~C=7$4ald|V*&S?zd&^x3xpeS)8@)Ck;NfZ$@h@IPML9$8z08ONy!nSa7n-?d< z;6BJu4?cgwn+bGkyHe)9yQ1PtuSy!g=>R86K@LP32L6$CE{UPQ1FypFG&sjA_u|n5 zUIG(f_CrwE!%dx(Z|tJUAsgCj_(nqqu*8I7Yhmy)-uRiFk^_Z!(sug0*aSJZ(@Q+JJOWhI}%$m z!o&TQc64kO${yGn96t+R+Cj&5s~6~ao*|>K`cVC&aiEm*ucfJ3z{mh?lCb)wXowpr zokuWZw)u8mKdg0uJY}>fd0Q}!tJYmJOCvps^uOWGGu-#jGWpaJjI8#<5H?rYeK~^c zE}t7ucL0fF&;i5~T2|;!3t9~jv&nJN;^SYqf)&;pvbn7cCBVE2N#qG6toF)pXG+v= z1*tj)Bq19lv$U6f5Z@DPQj4y3l3enW@7PInpf|qOg_lT2bfY^%yQ)v0M{28P1@uZE zt#c!2q!|Y)RU47qeIPQB>-$8l0PUuq>{?#Nn(%@v=eKI(gF(WAS_T4Aq7d< zQd>b_Dc@;k?OAJVDGUfHhfyG?bvv?a*g2(<#b*|MEHL;fa&u$H(t90F2;_T6q7xSs z-I7L%=FU4SErpKm5~as&d{Yp!Jrq9T7UMX(xIp-x974)JB=wK~05r<~0LWEJR{FpH z0Gj2G{^3;@)#vgZPqoBpM`KDwl^|JGtoVLBe4R^o79!S-ERLSh$eUaEayPei=kixx zBHlX)*;hqrR%IT^jU?zVFIDM=inMkBNojC5NWdq$%DBia1EdGHbyo=@GMZ%oO z!z?sXn6jj2>;NUo2RD0vve5ygQ>Dptj2yeFuNIgEj>t(JkS)XeEiQ?P7F@g@;mgJL zR9GyjU~^^U!a*KFmrQ*R7ouXiJ}h$^Gk%qvd`HI&@aC2n`20%o-3zQqgYNU>;_oUt zr%|2YhREu7b}4w&p&IYe;}K zO8$IONJF1M52anP*KdxgXJMo=6pKp}L1cU=r`kPy+Z zf$=yxoD>wNXnfxQS4E8N`(tYN9t3e}H?X?6XsQy(_%n=-qEp~&LwMby{SkO2`*(^~ zG2mkvzUo^S1&xmnG48mA`AW;i4VV5_PE74-&aU@i2NpInS_NlU0&$xi5^wUYW5&}| z+e?cg27&Ihn)*SNp1|h&4dMsdjIYTZJK?XoUs3ckTJDj?A{_hw0Qp}WZd3Vk2TRy` zBd@myAT`dY+;_CbdXKG}4Bv%bNsS|lU)4fni-~Psl~;!kvKE|iYAFfsS58X>H6j-P zMG6Ysfu)oXPy?gW@}<3yJ~Zq#t5`}C_Y!EtLP4f{Jgfjd`9Y^kgVfEz>{M`aJc2pwQ8N{cO;(7pCM zs=nnNp_*_-1=0eRUK+Js)7bB%nWeC*I#60@tu>1emMw_JJlt<&es=i{!>tRAI zhX6|AK~zM;_XA~cn47d|f8J|#X)!>Z{pMlbk8M-ipw>bgYE;UtZ7egt?@ z-pCtw*>j7J?NP0Cl#_OJR7lsJ>KMlZWf@KIa+kc)Hn2FNF%Ia`zWc5gRgNHdT|f@V z$XGQ*BueKo{A$5gqa2<9JbWwpeI8h`1j0tT`~+5GTw28~dHT|~7fO~;2tN`ms}OXo zhekv#vFA$~s!Tdu*!{;M_4BAAXX3sU?RC6&@~X*xvMgWEt^OUA>U#5KSHeb$qMaT;o0KA6&%69hB*ZsOoHvE~jhJhPq+uK65I0#Qf>lJ4pQYr>#y)uNaqv2QzE%Rv54KVd{Mj%XA- zC*w*Qel>rDh+%Y%KOczvD_GqxCBT-lnf8feXQX<79!=P&#eEA7OqhQ0zOt~EA_yDbHUL<=@QF@;V(YV8q9OK{>^IoCWGV>nh@pYB$lNrCf@5kBb#zY|(y{>tG7hw!suoBE4EvRhLV0Yo0@jc^uk!cljGi6rA~`v|QeBTQi0TjXd4 zmUxti>eO3_8$oB>_>#Na){+C9LXD5*15ALfCcsG`)s;4EATy=Zgp~!$76Ksw>{oKM zUBbXuE+HkvyS1x^FhU9q@Peqm2axQkzma`~rrBfV#p)!9gc9D$EM~^Qm}3BGIkA9E zrN~2F`9(4}HM%2fj}l6(>phgTnxq#Y3$l!we%!-7s@ij^h+9v_vq5k?@s^EuZ4kRcCX@Q~M6x1cexxf+q)VzQdhQY{u zd;KbIVG{A|p23k1ieUteCP4-FPB4HJ_G&2*ZFN{qe0$Q5Y^&@L;a$6rrDeHpWPBuZ ztMXKPXZxyISdz-?YpGdbjW{}nxWfMc>H>u5x!du6Emy*Q9d`INAA#pM=G>_$D zul@@osXknZ217uym6Ib{@MAmtAP^7KIkIocERw^;tY_lZRM>NaS^YrgsyR7#HOC1d zHL!8tE42lrH~@%ngk%Q2((oXD(uCnOy58VIoM8Df0e9^SMrk35q%>cWpv{bfao@yt z3d7tko2_?Cnn*)AwV=5rlUIK#hH{y|wf2SYfBDxsPTNxUy``eLIob#V+zlPlohfnn zqLGpbILOwvloRwT@UDikUIDz+)^M0q>-TIQ+FhMpZjgvJ)V)$P(4v9jLYZ>F=i z(p1^3#~foEtI-?sO3}~3k?rCF#pc9%09?Dc$IaAC308(RLK||gg+Hn5mDWrXDE_|GgD57i) zBynEf&^1JT<+S)qNX}`hK0v*8HtUF00lDv@(F86uHeUR7{NnM`?el z;Y)%5nNuFmnZ7XtXF3x*s*;z8kKqaTL z9K4sg#_E+Ra>GSBg18GODqRyI#l$u6fFPtNKr<3NosDb>2WBeDqp09C$V(#Yx( zd37utzNqG3C+PNGf2n$j#1^!Lg)dTk-N{{jN4mq!2lu?2@V!4t0!OrQ(O)FM&X7z6 z`K9!4P4yD|h6@@Lmz*qn_@HY5Ya3cySPgKGe@i2#xJ~oE%VHS=2sWlBMYb}XYRHp- z?y7t3aH~-18g*xBiBEjimm{ny?sYgOHNc_`yJ}+vA!2QcwHlHHyJ&?M3rTafj64DP zLYirIf=@drgT5$&Bw7p0;XQ(Y`c~E7bv*exEq(1Y7TIYiQ0KQ55C=vp8 zbgQx8_fks^f&i3rbpuqTk~j)cBXj^#7$<=hMn1%OLn0QDHD+X<#{DD659)BoE7ugK1sh@vpT5oIU z&&1PO(N?y)JVD0RG=Cxj^t~D?Wzys2uD(CDua6l6O4uJ7U5?L=f-|Mzwd%|$u|Np! z&=(t}EmX8xa|LNGHdgI06_mr^liPNwM4^s%E+7;QBF2>WKZHy`b!aZyFu}`6y|dgR z!oz;oalZ-C@dlijS`^h+_Pir(R4Au0pqjb}-w9{!vefn!AC3?3iZ({q-;k^bB&(tl zYNY+DeuE8hBaem7Z?-J%(<2V6153G8xVFIVfp2_btZgahlZOuo9*hDNZUcPX?0GrR^Z>X$0gtEQZ*3_52~o!jc%8_c$9>-r&!WQ2fC9 z4ko+;P(k>Op{AbZzX^W%_bRM?1*479GIHM6ijF_G6-7`0VWa+wpn`0P10rjkeg6Op zZaf?~Bn%+T@BJ&S;KtB=a1PqhRAM(0JZz3RZ}HeJ1@Scd5CGDDdGM^y7A`(XFPEPo z-@2(R@U(%*xxY!GyzX>>+_rv)Wl5}PeYjCqWR;I;_SgcZ;NnH?T~(fL00gbL?5JSk zqynM}!&*QoPSEdRGQTJ!h>@fyV|XUMm6p5)Ql}FLIv@H@8_);+6XP)8;d-SKI1Pj$ zj`7_%KzR1DQ~PSudUd(uh&|WXIxHqGmk>TcUohw}yk|nkH@kxR=9>&*qN#1ex?G3k zs^kJjm6>RR_)x;qqnevJj`po%$k0b4NS+!zD$@`@0ckOQY1zZ#;kD=bk5gYh0!`X6jZf@&Ns;4yV?ljgAHTAC!!ay^j2MG!b;XCtApK z()UE`|^_EWpw9|vf^BAa5do(jQBv~z<@{o zmrTP_kV(w4S3-0$qYKTGLZt%CS)2feKHmGzE;)R-}L;j{L= zE$_5E*ciAn^k@QKd=_E27cT@W?MD$?V(=~?Hbm%C~%tG65FZAx=p8|li&Hv^>-xV%%l zsHIRY?2!1~$munQi|F`Q820f9KON;p226wKrL>Dzy32TVJf@El5UKG1X?+{=<2>D3 z!iYXV7q02h026<$Z6>shppv1Wd`7O6HGpj~?)iahjdv$V1XUtvvq2ZT z3kHRu{Y^XK%KWJfD<&c&1*ID$9lWGSUn7UhNl}(H#ErRY30Cjs30m*Xi}X!vSOksT z(!g`wb^>Hp;qo2R6>d(YEf(Itg+eKd+* z%6Hil>Boo^tH%BU+NIK$9VHH}0rZK41KA;uE_DqnvBNXK42Zcv%tjexHJ}vF#I%98 zjV%tDgDfnTN%*i4Lz0m$CO7~$o2?a@htYEKiFrI)6URh?FP2p8)~F(ztK>Pwt#M;K zQq7dQNjW*ra%wi?p93AdV#en1KXa8ivx|+MRrPubhbkIE=MdW=AakdF!yZ8VD(>a8 z&CdQx;NayJsAE{?)rO_Hr;r41@Q6uGQ|=4cK`w1H0;7vSq%W9Q1Svm}q&3C2`&6~R zeiRo_p=6b6EJZN352UgO4eaZYfn$B1$3 z+XhkI!nGuEOJ%UIe*tM?biOS%18q#O$BH>U%>a3|owU{`{5l}QOK7II1|ZHr1fH?h zv7w0jax{><%>Jm5GP#033%5Ml&Fdcfp~W1zk+z4#uW;_w^t>1NY}1?n05tMTSHF8G z>p^cb^~bNYi7bsJ(FW6|ZxE_UCcCX*ubrLjjfLm4`m>+$k4o2Clu1n;)*SG*Kb7o+ z^%N#+obu_PV(ocuv(_8^NSXnoO2??WtDmOVU53@>wnX}lE!@B^G>(-0ekMd#B|p*ig7w# zTNfbXJD)Eq)^)NvZXOG2I2mmn>1F0*00YLyj^SOv z>TWOn+WKB_JGv-j;A|C=^!iUg>SRg9$3=S&dhx*vprAQRc_bN{f$|p`Nn>rtNE{!u*#1c(Bgjxzn9e8; zHc?D($GU+)epKD8*ahvqs1z+32p!n0SQg?olHwFNp9-|CaeXNWv@F#wdo3Z3dq?4O zr9F{ieX(TuLBSAp_fu*s@_$@E{NpqK03($)L|pFLD(78{yRBw@d#C-aB*zqzpfy68hjTsFDt@zv;HdoH`U$0jS01(sV2p8O?J0vx~0c8o9 z?r-g-=f_p8R*F=FeTr2`k;nHgEiN2Ql|zh;8ngy--`H%Fu^$kH&Y}D&2)a`6Tq#U| zpYv%$GeZDqqjpryDI>Kc*w*xyA-y#)!5PC{WW zLz^Kdx+3=n0B)@TC98?o+PJM;jCffC9T&)*mwhTZ(n9yJH0%we%a-=zn87?sqZkF& zJEjZGXeQS`U6R=It4t&9X8Zwn=Ss{mOCyB=UuwS{kEH9Fpa4K;@}RVObc}`0F8r+c z$mg=IvS|Zp&ag^Rg}kj69~+nmAX?kU>S8E(#=**#Buxz(q-`axwG2Ndd8L0TBsKI9 z2`qLrmf~D~kcS$j5a)|%K;QsI0VBHV2lrBeEolD$DmO;s9R_#orH|ljQByW!+~&}r zw2JMG{{ZG~B9W9fn=FOk0MlvMy)!2y(^^1JZ|G4042Osocl<9^iRtFVL7CO~D@Xnn zh}sT}I487Cc&sQTno+_c@9ez;I#22${-b!1y)yM!*%36C#YdLsjP2n(IEKgB|6pa5Svvs$QO%vGQRrAX?4peNU%! z_JbsW(hYzY&N`o}^71XQJh8umy!K9XvpVH-iTstC=jQ(GGk-SfDp+r(#2U5$RFLbGBcLIOA<5`LB{k- zC@6!lr;>0j@{ihQ(u49(UYriKn94w80KXIZJ9hikE04e8B?7)beO zk#wA6{Cdoh~(@V#F|=}pCmw=y=m(@$rO5YF@cCKa{O zy)!;{$h&|WHoZII#>QbRU>1)CcQlg60M#o#%F=YqYz%%fmbvQA4AC)xtY9CNpVfMX zBOl6X0j~=OC)IeE@3`A_*(WxouVXmm>*PPxE>}YwcKJZA;@8bOm#yWILe+^We{*y!6w_Ba4Y7l&&Ct)yLu&UVKso{O`Vze?C_N2^N^(C=j}2iD^z? zt*HzHW3qETPYnXk(y)4VQ@$c6(e0%DX53W-5;&1TeFyv~>G9@usNU)&ix;JOJ2HL_ zb9gZKweS5a(%|&$jd73?>b090-F=VP92y(ilHZKgUjwPdJS_I)X$r)-ENe+8{TCjl zrUTe#kf~)s8Fye5%he%kF4hiTQ{^uvodt_9RqO6WDNa78~#;aCpY88x=5C0v%;k$oRdLH_c#(tTiiXmKR_4N-f>W^YO^w0V>Ws{{Yo#{H}hhE9<=IMi zrR(}|=Mb;864t9FwuF4|!dqFvr;=l8l%z{LqND)r7?S)b)In`-ke39)bd=`W2(aW} zkTg(xWD7zG1p`B`xl5g_Ed92UUR>fYvMzK8E1eZx4|3F+`B7Gy@Lj&ho)}Js)W3~I zLeb;GmK08H6kgvY1cK0Pr?x>sRCF!|!O&17a1?{`hp3B3UeCY(0KV_{TArVUr)xj2 zL+*9_-~7)10CniPCMaY;pQY~pPhYN{39+iifmBlob?FF;uo_$j`>&aPy-?PId!n&v zJgIe_;Hipvb#_UTQ`jOK7idc_%CaG4?((1$WRy;AC{#cSRFa0u(4Nbj?IE-eC^)%G z1*l-MngD1(ZEEKQ4R+D^K$6QEM#$@KMh?(Q_c_20$jIJ6Z@_%M*M6bSU~Gr`F5#iH ze$#Z~cCl7bK*B}wP7yfyOKhGt6__07O4c=pepYwl=}wDQ4`iVCH?YuJll1(6;ld(X ze5zA5(GVWmS(YBfd*4a8jGL%VA&%^o*quIH>41n-cSNsi(YkCn1;6+I0NkaidRD~r zuyfh(zla^y)Lj#%$6nxT=|3|k9vHwfawq9w=k=USG04e(f~@A>#xG5|a&a-D;R{;O zJg+y_JyV5&U=aBSh336O>j+&7qsP>T>39sBw`4fE&azFe{yz&k^&Ml?Ia$&lY2MR6 z3qCJUX2J;lK`RH}rqyXca3JrK!&|@iZ>p z(KvDfg6&$ zOvZyB92dL-<%#M(w%lwvJ*WKpG!F~BNo{QPZ&1P0;|(umfj|Y|I=85&%9OS@xDM;g z9mw-R2QKJ9Dr5teNuh;Roz58Pfe!_ea80W9@c-S!9+6aZj1ZE; zWm<`3P546nG1hz|e`J?v8{LJjM~2P?*)n(TgB{XF@NClbj=_w~T;`3G_u|6lhPE+v z-F4rIicsV_NW~t?7mjwyK^EaI*LxhalJYN(o}+*$!dy7W+3L`YMn_itK`# zrsyEBjXx*#d8^cUzz_brzukJym1Y2c3(jO=iM>yrNbNhn-FmEM2qOdVy?@I6Z^5`@ z`8a7Uui@P>uN&T!7BSt*@MG3rE=NHa{gjQd@otnB{iX;SYLH5gD}vHEt_!PbOHc_1 z!s=2Qe$)_9by=Xez)B%vlX;yZBnYd*AsH#$ue##k6wr@uh(_Z|ea7C>-0p7;XtJwN zZQkt!vhf|lb1<@{khQEL#+Jq>r6tISI$}rRWijVH=NC~a@yH1R$S1a!vBmV}E-3!6 zR?IT$ee-mv>v^!T$h9 z(>gz>x^@gFk>zO}N7i_(<@#`35zfb^&-G?huRIM}!^!HISueR9 zN~uS}fDY+(=f^oo1GhMmi-I9xPkzg;f50K1YC~E(C^pkX(rj?LL2PZNGuKc9{S>;W zZtZGe^el{$3!6jow{ZF_Fju$(%9b&Dd5G~Qcm=VVD$BZT>|ifx0eeP66B;oMwjm|V2 zv((lvdiM@|Z+my~PwKD+;s>zk1?SnH7aAm32)c(_Yp{b_d{XoE#;~)3@gX730+*Z5 z&KTWvNnyYRotf1g7yT#EKT9{>_oWUef0cOV^GP1Mezp3G4c7kGjO*n7pg1_2R@smk z$8sS=(MOUR;BJ?*pRu_yhbQd_9N^a0*6G58k)Zb-Jhi-n*{bl%I$N?ni1Vtft;QANUf__`U?8t zR)Es#r486bNDU{zSD3|B%b(edyXY?yp7-R;=R3mQ>Y2QxEghCXEgX$5j8#ZtBe+(h zW|6j!V2m_>br7oBu@`hM0Cz_a<+M|y)4vMrb>UJS)uG)1$=xbX+oahIgqIQ;imfQV z>zXzf9l1@?*8D~c*I)vyw0j7Y)=P$w2+q78z!G2R^88eV=Yic0Xc zu%xlwW{+jk$ZRdMx?829EV zDChW6;YwP~E`1V~_aP@p-5MWmmJ|&uj>lv{pdG1i8|<{OmjtujIpkTSlI^2U&CH07 zyO`oMWk2qbu6R*0Ng+BtW^cCKU>|7zAkf_O9#{6>CrTPcrI*{0Fl`o?e+nIHLXZ)V0#`QebE?$1jR0u_IWe?cQr(dq=&Mll z$+Jihu-RI8K9ZBZOQ-|(jMgh$*AL1luyZmb_&4L>KdZ+MG~u|du+HTv*^@FR{{U2t zUWz84lhX3>asA0Fiq2^!K}Lx3if+9jh{X8|hvj6;)VQ4ut2s64V(Jn==Df*Zcvk22 zbE9ApYQEQlmp$?tItr`iC;ZE&J~j4wo~i2$*{zIt0Qn2gPnRUbx$+k(Px)-^Mr=-fYF#6blmW-dP(td`zO4HhfA+2>yQP8~{%R_D z7dQYdGa0>)m|R{4{?WsSJkAu(A!=guR)8HdtbHr`dor8J+F&Nt+)26a);qeMNd&;Gcp4D{-Xtjjf*go97gj`Y0~shm~l7fOT~5R-GPmo3t09TK)N92myg)oox$#zunA3r(`HL;yb^7fBkGa(s>_MRXIn>mpgM z?Oy3wc7J1N&Nh&jp|)wajp7VX&dX_B$+yc-EIjETU_4Z5u}tx#a}N)7m(; zsV$EdnS6@2RMQDA00B!kt!Dn49DwbeE144rV=pJN@V#F(`B_Ja_=2x8l`NUlOnDnt zc>GPOcxv8t!^hiUA#>_3z1}+-Zu~2Z zVB^_h^sLW&TnHt4JV^NstSNEZ2gE19T<6lZ$XY^dQ8lF$4g98qLXkP6!VtoHsYv0q zAsb_$r-%zUq!#?GPJ(R%*(uE;*FL{aLi1=yAwe{z^rJ;O&~ITgkOdG8a44}+$B9UL zk0Px|2I*6Cji|D|9Oi+UIsX9n70z(%5l^g%YyRSr4R}|}Klfeyf9o9GJQA#P?MV&V z?o{peSdOxoWJ!_tY92yck1aG8D!LYt%Sr5UB9P-^mj@RbPKFR2qiC9j*wIZCEk;d8 zBR~ZxyNI)(p0w0BlJiQ&Gg$cty5JfWCuB99wyMjS`K77DH>bYF>v&jE0MZ34p110! zO>KwD@N?!KT5&45%6p9xe}&R`qZYQaI+1(1S+U(xmo&Y*DuJ5&gdFT>E&4`Gbex}K z!jeG=K!AH9uu8ta@Y>>R=>cjZK&Y@hEl8V=8X7`C^0>VRxKDz$tlpi=i0p@*ridRW zVWj+in&~A5(i{WO9^4qX*q-uw182ANSjU26-bx^s*+mo!fOg8=SCa zQXjQcOX86iriYhWTa6H)NIusW0-6;e6hg%H9w^Dhur>nOkb*+3ksm0HCqJX-IQb98 zlz=~JrLhN4E{|XZpVo2CK4H~f)h=#uu0?kB7J80brG0o*45S4TGvj3KCujIpa~fU6 z%X{G zGQ6SA$rzZ9kdbwzsdX)6dYh;QMeRm@M?`%uF^<6Fe62QlU6qjO9lI%zMjF~8mZLhg z32OkMY0Z!w67 zX!5iziXE3;?J5}rng_CH#GR3)1#I__%`AU(f_Wb6erVe(NYcxn5H{%ou<|{(S?;~3 zK*^eCGlf#{mB3e(x6rzap_Q$_C_dNe>0USop9|dK9Rv2hPwCwLWuMu7Bc@DCTW7~* zj^-?H#wjper9f}8dj{4NO=l!p29W@uk0`M&8cQghX=A#TQO=!6+$S`CP(6vqZXp(uYFVJ7}>?OLz2?=L=S(#|^$JzqUO0 zQLL|q<;q)=E`@R_B5rmmJ1KzVNPO}uv7mG109KZ~xBmcj=;Qrh;DPUN!IpmkH}o@+ z^Bhm*YV^Fu;0JSzINz01sdX>Z&CTBd+g+C_HNWXlK?Hl5_I{AblM_c6q5{0CvP}!E z#r?Zl&&%pSzP>a&QtQtQUa@!Ik;aaP;W8|iV@Mp+y7Ii_{ZgAitjY7GdGDpypBq2q zdTidN-*L{de@j0rtCurN3>Qj%PAHuo{{VHavxyS+uyf^mwb?_bk=k+6KwtzE=MnU! zk~8e!LABLIKq%Y!R~B{g6jyBv-Cc?gbB~)^k(<%Q0eu<@54|7(jaDJ)(@90(fSAsZ zTyK5RwUWp{14qi&ho?l)3-&^|VvV42XbFjKvDwp0hs>3794Mo1+sRosdR?_Kmobcw zKxq|#HEIfgRQv|lDCM*_r7bp^f^E2`1G-8EiZE=aus0egnr%lFJ&LoSXxrH+@5<(y z3G9|04}?ScNaUri+Pcmjy8IyyQ{_Z)s_vu|E>O~d&`drw5n2gOty%N%d2dwX)MfS9 zcV1Exs$W9tkc^CXwZq1j&+;O4Gr7J2UHH2QU;vHMgAXk>l4K^krN-jdw2LKab#EUE zS5DRu-Fs|qmjf{xKg~-k)5G0(e5})at=S|Tj}p0e-h4(TPfH=rEDE!5-xFL~-;o{H zpy%R&Tt|uvm$0eQam-O!?zH>_mN#Ih7k}+bb*@w3F2AK8NZKu7w>8vuk<_65W-(`N zCzkC*q(>9nR=KP^o;D$ZXEocUc*NQYT;S)DKGB~Grm}`YK9PvpJAjJAT9nt4;!lM% z7-L$94e3E6ijZt7sC9)t;SLs{kMvSoVFTMETsx^fwb@kQ;n=Bcj%JS040F6JE~w-B zfC20lypjOk)V%(CgYpRlYCuuWT59yC-m_M!fNIwRM#{J?Lo?X_0Et?-(za$(jTMAu z04GB$S+G>Rk-2V(DgZT=2yV|F)@!Rtp~dMucMvHA<5QM z=&|mxPL-zj3Z^vzLbV%(u56s^uE>XECE}NI6}1!lNv|j!L$ZewhW4dvL@WZ5MHJHQ zB)PyHg$Z2ZQrzH}WCT)6htkF>1c9YTxXbRBBS}yqHQh@ZbkdLVn^laP?21@i9yXBs z zhcZc7d3|GhC&SRbF6;-=LdwnCB zp}as`*50jO!(74zT6ZR@&(Wk&Z%O)^XCvSy165%rNdq(n{?}v2CQQH=fC{sXOGPBD zAGf*~-z12 zGM-C(4JF70c2@I=@2X72hA~ZGAK44V8Xc9J+4>1m1&a+RjUlZga6&@MQj|p~v`<3O zv{Vwg6SUHSW|b;iqJ$y=8B8doEpFTxhVg zxDcGxQU~@{+7~m_e@KSKr~wdGG>|lnfkRO-It1ZsJFHA1gMd3LRBRvNd9JM?l4?E` z6mQ4T{K(R*KX^gcvwg@wm%UnS{XJ*~GA2?ObU2hgtPk{aQm z*>dT}r`6$b?$v3hvZIV_0yRqWdoFC|7<*cfbcCHL9g&)z<#!rg+#&2#sT|{^rwa*= n+Jz%zflG-*GDgLFtr>wpMI$Iu|%-O?!^ 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 G$^QX_3@wQO literal 0 HcmV?d00001 diff --git a/src/main/resources/images/userAvatar.png b/src/main/resources/images/userAvatar.png new file mode 100644 index 0000000000000000000000000000000000000000..e5bb652895df02883779fd8d76bd54b17f614f7a GIT binary patch literal 8217 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/views/DialogBox.fxml b/src/main/resources/views/DialogBox.fxml new file mode 100644 index 0000000000..b10b9b6f85 --- /dev/null +++ b/src/main/resources/views/DialogBox.fxml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + diff --git a/src/main/resources/views/MainWindow.fxml b/src/main/resources/views/MainWindow.fxml new file mode 100644 index 0000000000..51c1bad06c --- /dev/null +++ b/src/main/resources/views/MainWindow.fxml @@ -0,0 +1,46 @@ + + + + + + + + + + + + +