From 55f9f9ff7635cef71b5ee58aec7c1b4ceaffea49 Mon Sep 17 00:00:00 2001 From: damithc Date: Sun, 7 Jan 2024 18:33:52 +0800 Subject: [PATCH 001/153] docs/README.md: Tweak document template Let's tweak the docs/README.md (which is used as the user guide) to fit Duke better. Specifically, 1. mention product name in the title 2. mention adding a product screenshot and a product intro 3. tweak the flow to describe feature-by-feature --- docs/README.md | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/docs/README.md b/docs/README.md index 8077118ebe..47b9f984f7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,29 +1,30 @@ -# User Guide +# Duke User Guide -## Features +// Update the title above to match the actual product name -### Feature-ABC +// Product screenshot goes here -Description of the feature. +// Product intro goes here -### Feature-XYZ +## Adding deadlines -Description of the feature. +// Describe the action and its outcome. -## Usage +// Give examples of usage -### `Keyword` - Describe action +Example: `keyword (optional arguments)` -Describe the action and its outcome. +// A description of the expected outcome goes here -Example of usage: +``` +expected output +``` -`keyword (optional arguments)` +## Feature ABC -Expected outcome: +// Feature details -Description of the outcome. -``` -expected output -``` +## Feature XYZ + +// Feature details \ No newline at end of file From f837ddb7d2b77f6654758f93d056420a580787ca Mon Sep 17 00:00:00 2001 From: damithc Date: Mon, 25 May 2020 00:58:18 +0800 Subject: [PATCH 002/153] 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 a6f73244a20539e20c2189973ebf597df34ef631 Mon Sep 17 00:00:00 2001 From: lzq Date: Sat, 5 Aug 2023 15:24:02 +0800 Subject: [PATCH 003/153] 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 e7052e07e562e7b718bcf72e2a5357c122eef4c0 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 6 Feb 2024 00:47:01 +0800 Subject: [PATCH 004/153] Renamed duke to dude, added greet and bye --- .gitignore | 2 ++ src/main/java/Dude.java | 34 ++++++++++++++++++++++++++++++++++ src/main/java/Duke.java | 10 ---------- 3 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 src/main/java/Dude.java delete mode 100644 src/main/java/Duke.java diff --git a/.gitignore b/.gitignore index 2873e189e1..98cd22ff56 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ bin/ /text-ui-test/ACTUAL.TXT text-ui-test/EXPECTED-UNIX.TXT + +*.class diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java new file mode 100644 index 0000000000..35a67595cb --- /dev/null +++ b/src/main/java/Dude.java @@ -0,0 +1,34 @@ +public class Dude { + public static void main(String[] args) { +// String logo = " ____ _ \n" +// + "| _ \\ _ _| | _____ \n" +// + "| | | | | | | |/ / _ \\\n" +// + "| |_| | |_| | < __/\n" +// + "|____/ \\__,_|_|\\_\\___|\n"; +// System.out.println("Hello from\n" + logo); + + System.out.println(greet()); + System.out.println(bye()); + + } + + + + + private static String greet(){ + return "-----------------------------------\n" + + "Hello! I'm Dude\n" + + "What can I do for you?\n" + + "-----------------------------------"; + } + + + private static String bye(){ + String bye_msg = "-----------------------------------"; + bye_msg += "\nBye. Hope to see you again soon!"; + bye_msg += "\n-----------------------------------"; + + return bye_msg; + } + +} diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java deleted file mode 100644 index 5d313334cc..0000000000 --- a/src/main/java/Duke.java +++ /dev/null @@ -1,10 +0,0 @@ -public class Duke { - public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); - } -} From 0232b97ce95345e477fb5b2cb2f6b41bacf291d3 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 6 Feb 2024 00:55:48 +0800 Subject: [PATCH 005/153] Added echo feature, added indentation to responses --- src/main/java/Dude.java | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index 35a67595cb..7d761166b7 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -1,3 +1,5 @@ +import java.util.Scanner; + public class Dude { public static void main(String[] args) { // String logo = " ____ _ \n" @@ -8,7 +10,21 @@ public static void main(String[] args) { // System.out.println("Hello from\n" + logo); System.out.println(greet()); - System.out.println(bye()); + + // Initialise Scanner to reach command line input + Scanner sc = new Scanner(System.in); + while(true){ + + String s = sc.nextLine(); + + switch (s){ + case "bye": + System.out.println(bye()); + return; + default: + System.out.println(get_echo_msg(s)); + } + } } @@ -16,19 +32,26 @@ public static void main(String[] args) { private static String greet(){ - return "-----------------------------------\n" + - "Hello! I'm Dude\n" + - "What can I do for you?\n" + - "-----------------------------------"; + return "\t-----------------------------------\n" + + "\tHello! I'm Dude\n" + + "\tWhat can I do for you?\n" + + "\t-----------------------------------"; } private static String bye(){ - String bye_msg = "-----------------------------------"; - bye_msg += "\nBye. Hope to see you again soon!"; - bye_msg += "\n-----------------------------------"; + String bye_msg = "\t-----------------------------------"; + bye_msg += "\n\tBye. Hope to see you again soon!"; + bye_msg += "\n\t-----------------------------------"; return bye_msg; } + + private static String get_echo_msg(String msg){ + return "\t-----------------------------------\n" + + "\t" + msg + "\n" + + "\t-----------------------------------"; + } + } From 6655cdb376e2376ac259b45255690563d86cfbab Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 6 Feb 2024 01:56:52 +0800 Subject: [PATCH 006/153] Added TaskList.java, Implemented Adding Tasks --- src/main/java/Dude.java | 29 +++++++++++++++++++++------- src/main/java/TaskList.java | 38 +++++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 src/main/java/TaskList.java diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index 7d761166b7..5b53377216 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -1,13 +1,17 @@ import java.util.Scanner; public class Dude { + + static TaskList taskList = new TaskList(); + public static void main(String[] args) { -// String logo = " ____ _ \n" -// + "| _ \\ _ _| | _____ \n" -// + "| | | | | | | |/ / _ \\\n" -// + "| |_| | |_| | < __/\n" -// + "|____/ \\__,_|_|\\_\\___|\n"; -// System.out.println("Hello from\n" + logo); + + String logo = " ____ _ \n" + + "| _ \\ _ _| | _____ \n" + + "| | | | | | | |/ / _ \\\n" + + "| |_| | |_| | < __/\n" + + "|____/ \\__,_|_|\\_\\___|\n"; + System.out.println("Hello from\n" + logo); System.out.println(greet()); @@ -21,8 +25,11 @@ public static void main(String[] args) { case "bye": System.out.println(bye()); return; + case "list": + System.out.println(list()); + break; default: - System.out.println(get_echo_msg(s)); + System.out.println(add_task(s)); } } @@ -38,6 +45,14 @@ private static String greet(){ "\t-----------------------------------"; } + private static String add_task(String msg){ + return taskList.add_task(msg); + } + + private static String list(){ + return taskList.toString(); + } + private static String bye(){ String bye_msg = "\t-----------------------------------"; diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java new file mode 100644 index 0000000000..43a1925465 --- /dev/null +++ b/src/main/java/TaskList.java @@ -0,0 +1,38 @@ +public class TaskList { + + private String[] list; + private int count; + + public TaskList(){ + list = new String[100]; + count = 0; + } + + public String add_task(String msg){ + + if (this.count >= 100) { + return "\t-----------------------------------\n" + + "\tSorry, the list is full. Max size is 100.\n" + + "\t-----------------------------------"; + } + + list[count] = msg; + count++; + + return "\t-----------------------------------\n" + + "\tadded: " + msg + "\n" + + "\t-----------------------------------"; + } + + + @Override + public String toString() { + String result = "\t-----------------------------------\n"; + for (int i = 0; i < count; i++) { + result += "\t" + (i + 1) + ". " + list[i] + "\n"; + } + result += "\t-----------------------------------"; + return result; + } + +} From 8f5c5b69e598c5c4e4eac3d21460577d98b2c152 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 6 Feb 2024 02:10:25 +0800 Subject: [PATCH 007/153] Changed Logo --- src/main/java/Dude.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index 5b53377216..cc92abe53a 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -6,12 +6,17 @@ public class Dude { public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); + String logo = "888888ba dP \n" + + "88 `8b 88 \n" + + "88 88 dP dP .d888b88 .d8888b. \n" + + "88 88 88 88 88' `88 88ooood8 \n" + + "88 .8P 88. .88 88. .88 88. ... \n" + + "8888888P `88888P' `88888P8 `88888P'"; + + System.out.println("--------------------------------------\n"); + System.out.println(logo + "\n"); + System.out.println("--------------------------------------"); + System.out.println("Dude v1.0 by Tahsin Hasem.\n"); System.out.println(greet()); From cface250f0b4410314304ae28323c623d7946f4b Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 6 Feb 2024 02:15:54 +0800 Subject: [PATCH 008/153] Added Task.java --- src/main/java/Task.java | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 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..47fc675234 --- /dev/null +++ b/src/main/java/Task.java @@ -0,0 +1,30 @@ +public class Task { + private final String description; + private boolean isDone; + + public Task(String description) { + this.description = description; + this.isDone = false; + } + + public void markAsDone() { + this.isDone = true; + } + + public void markAsUndone() { + this.isDone = false; + } + + public String getDescription() { + return this.description; + } + + private String getStatusIcon() { + return (isDone ? "X" : " "); // mark done task with X + } + + @Override + public String toString() { + return "[" + this.getStatusIcon() + "] " + this.description; + } +} From a8e470ae734eec58f16a8d8aa779f3a27a64be3e Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 6 Feb 2024 02:19:57 +0800 Subject: [PATCH 009/153] Refactored Task List to work with Task objects instead of Strings --- src/main/java/Dude.java | 2 +- src/main/java/TaskList.java | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index cc92abe53a..f497934522 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -47,7 +47,7 @@ private static String greet(){ return "\t-----------------------------------\n" + "\tHello! I'm Dude\n" + "\tWhat can I do for you?\n" + - "\t-----------------------------------"; + "\t-----------------------------------\n"; } private static String add_task(String msg){ diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index 43a1925465..b7acaa010d 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -1,10 +1,12 @@ +import java.awt.*; + public class TaskList { - private String[] list; + private Task[] list; private int count; public TaskList(){ - list = new String[100]; + list = new Task[100]; count = 0; } @@ -16,7 +18,7 @@ public String add_task(String msg){ "\t-----------------------------------"; } - list[count] = msg; + list[count] = new Task(msg); count++; return "\t-----------------------------------\n" + @@ -29,7 +31,7 @@ public String add_task(String msg){ public String toString() { String result = "\t-----------------------------------\n"; for (int i = 0; i < count; i++) { - result += "\t" + (i + 1) + ". " + list[i] + "\n"; + result += "\t" + (i + 1) + ". " + list[i].toString() + "\n"; } result += "\t-----------------------------------"; return result; From 198fa53d2189a3aca90909d1e3714ed79414934e Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 6 Feb 2024 02:32:14 +0800 Subject: [PATCH 010/153] Refactored TaskList to throw errors --- src/main/java/Dude.java | 14 +++++++++-- src/main/java/TaskList.java | 30 ++++++++++++++++++++---- src/main/java/TaskListFullException.java | 6 +++++ 3 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 src/main/java/TaskListFullException.java diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index f497934522..0b767c320d 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -25,14 +25,17 @@ public static void main(String[] args) { while(true){ String s = sc.nextLine(); + String first_arg = s.split(" ")[0]; - switch (s){ + switch (first_arg){ case "bye": System.out.println(bye()); return; case "list": System.out.println(list()); break; + case "mark": + default: System.out.println(add_task(s)); } @@ -51,7 +54,11 @@ private static String greet(){ } private static String add_task(String msg){ - return taskList.add_task(msg); + try { + return taskList.add_task(msg); + } catch (TaskListFullException e) { + return e.getMessage(); + } } private static String list(){ @@ -67,6 +74,9 @@ private static String bye(){ return bye_msg; } + private static String mark_as_done(int index){ + return taskList.mark_as_done(index); + } private static String get_echo_msg(String msg){ return "\t-----------------------------------\n" + diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index b7acaa010d..a801fc92ed 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -2,7 +2,7 @@ public class TaskList { - private Task[] list; + private final Task[] list; private int count; public TaskList(){ @@ -10,12 +10,10 @@ public TaskList(){ count = 0; } - public String add_task(String msg){ + public String add_task(String msg) throws TaskListFullException { if (this.count >= 100) { - return "\t-----------------------------------\n" + - "\tSorry, the list is full. Max size is 100.\n" + - "\t-----------------------------------"; + throw new TaskListFullException("Sorry, the task list is full."); } list[count] = new Task(msg); @@ -26,6 +24,28 @@ public String add_task(String msg){ "\t-----------------------------------"; } + public String mark_as_done(int index) throws IndexOutOfBoundsException{ + if (index > count || index < 1) { + throw new IndexOutOfBoundsException("Sorry, the index is out of range."); + } + list[index - 1].markAsDone(); + return "\t-----------------------------------\n" + + "\tNice! I've marked this task as done:\n" + + "\t " + list[index - 1].toString() + "\n" + + "\t-----------------------------------"; + } + + public String mark_as_undone(int index) throws IndexOutOfBoundsException { + if (index > count || index < 1) { + throw new IndexOutOfBoundsException("Sorry, the index is out of range."); + } + list[index - 1].markAsUndone(); + return "\t-----------------------------------\n" + + "\tNice! I've marked this task as undone:\n" + + "\t " + list[index - 1].toString() + "\n" + + "\t-----------------------------------"; + } + @Override public String toString() { diff --git a/src/main/java/TaskListFullException.java b/src/main/java/TaskListFullException.java new file mode 100644 index 0000000000..a336ec1e77 --- /dev/null +++ b/src/main/java/TaskListFullException.java @@ -0,0 +1,6 @@ +class TaskListFullException extends Exception { + //Used to indicate that the task list is full + public TaskListFullException(String message) { + super(message); + } +} \ No newline at end of file From cce34ff063d1a463cac30faa557397bf1a208434 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 6 Feb 2024 02:34:09 +0800 Subject: [PATCH 011/153] Changed TaskListFullException to be public --- src/main/java/TaskListFullException.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/TaskListFullException.java b/src/main/java/TaskListFullException.java index a336ec1e77..c7675b8dca 100644 --- a/src/main/java/TaskListFullException.java +++ b/src/main/java/TaskListFullException.java @@ -1,4 +1,4 @@ -class TaskListFullException extends Exception { +public class TaskListFullException extends Exception { //Used to indicate that the task list is full public TaskListFullException(String message) { super(message); From 19b40a536ebc5b816e0e7953d9bcd5f7bc41bad1 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 6 Feb 2024 02:36:03 +0800 Subject: [PATCH 012/153] Renamed variable s to msg --- src/main/java/Dude.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index 0b767c320d..ee934931c0 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -24,8 +24,8 @@ public static void main(String[] args) { Scanner sc = new Scanner(System.in); while(true){ - String s = sc.nextLine(); - String first_arg = s.split(" ")[0]; + String msg = sc.nextLine(); + String first_arg = msg.split(" ")[0]; switch (first_arg){ case "bye": @@ -37,15 +37,12 @@ public static void main(String[] args) { case "mark": default: - System.out.println(add_task(s)); + System.out.println(add_task(msg)); } } } - - - private static String greet(){ return "\t-----------------------------------\n" + "\tHello! I'm Dude\n" + From 397c9b187ac4f12a4842cc1209bb06770d4eb634 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 6 Feb 2024 02:45:57 +0800 Subject: [PATCH 013/153] Added mark_ as done feature --- src/main/java/Dude.java | 24 +++++++++++++++++++++--- src/main/java/TaskList.java | 4 ++-- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index ee934931c0..0617896d0e 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -35,7 +35,8 @@ public static void main(String[] args) { System.out.println(list()); break; case "mark": - + System.out.println(mark_as_done(msg)); + break; default: System.out.println(add_task(msg)); } @@ -71,8 +72,25 @@ private static String bye(){ return bye_msg; } - private static String mark_as_done(int index){ - return taskList.mark_as_done(index); + private static String mark_as_done(String msg){ + //Try to retrieve the index + int index = 0; + try{ + index = Integer.parseInt(msg.split(" ")[1]); + } catch (IndexOutOfBoundsException e) { + return "\t-----------------------------------\n" + + "\tPlease provide a valid task ID. Has to be an integer.\n" + + "\t-----------------------------------"; + } + + //This will run only when the index is valid, as catch block will return the error message + try { + return taskList.mark_as_done(index); + } catch (IndexOutOfBoundsException e) { + return "\t-----------------------------------\n" + + "\t" + e.getMessage() +"\n" + + "\t-----------------------------------"; + } } private static String get_echo_msg(String msg){ diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index a801fc92ed..c470c26c28 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -26,7 +26,7 @@ public String add_task(String msg) throws TaskListFullException { public String mark_as_done(int index) throws IndexOutOfBoundsException{ if (index > count || index < 1) { - throw new IndexOutOfBoundsException("Sorry, the index is out of range."); + throw new IndexOutOfBoundsException("Sorry, the provided id is invalid."); } list[index - 1].markAsDone(); return "\t-----------------------------------\n" + @@ -37,7 +37,7 @@ public String mark_as_done(int index) throws IndexOutOfBoundsException{ public String mark_as_undone(int index) throws IndexOutOfBoundsException { if (index > count || index < 1) { - throw new IndexOutOfBoundsException("Sorry, the index is out of range."); + throw new IndexOutOfBoundsException("Sorry, the provided id is invalid."); } list[index - 1].markAsUndone(); return "\t-----------------------------------\n" + From 51ede74c8b0521e37649500f890c3637154f50a5 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 6 Feb 2024 02:48:27 +0800 Subject: [PATCH 014/153] Changed the output message to include task number for marking and unmarking tasks --- src/main/java/TaskList.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index c470c26c28..74ab25b5ac 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -31,7 +31,7 @@ public String mark_as_done(int index) throws IndexOutOfBoundsException{ list[index - 1].markAsDone(); return "\t-----------------------------------\n" + "\tNice! I've marked this task as done:\n" + - "\t " + list[index - 1].toString() + "\n" + + "\t " + index + ". " + list[index - 1].toString() + "\n" + "\t-----------------------------------"; } @@ -42,7 +42,7 @@ public String mark_as_undone(int index) throws IndexOutOfBoundsException { list[index - 1].markAsUndone(); return "\t-----------------------------------\n" + "\tNice! I've marked this task as undone:\n" + - "\t " + list[index - 1].toString() + "\n" + + "\t " + index + ". " + list[index - 1].toString() + "\n" + "\t-----------------------------------"; } From 90ce70dc1766d74d28641987d19b705b080a7125 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 6 Feb 2024 02:50:56 +0800 Subject: [PATCH 015/153] Added Unmark Feature --- src/main/java/Dude.java | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index 0617896d0e..79c6a9ea83 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -37,6 +37,9 @@ public static void main(String[] args) { case "mark": System.out.println(mark_as_done(msg)); break; + case "unmark": + System.out.println(mark_as_undone(msg)); + break; default: System.out.println(add_task(msg)); } @@ -93,6 +96,27 @@ private static String mark_as_done(String msg){ } } + private static String mark_as_undone(String msg){ + //Try to retrieve the index + int index = 0; + try{ + index = Integer.parseInt(msg.split(" ")[1]); + } catch (IndexOutOfBoundsException e) { + return "\t-----------------------------------\n" + + "\tPlease provide a valid task ID. Has to be an integer.\n" + + "\t-----------------------------------"; + } + + //This will run only when the index is valid, as catch block will return the error message + try { + return taskList.mark_as_undone(index); + } catch (IndexOutOfBoundsException e) { + return "\t-----------------------------------\n" + + "\t" + e.getMessage() +"\n" + + "\t-----------------------------------"; + } + } + private static String get_echo_msg(String msg){ return "\t-----------------------------------\n" + "\t" + msg + "\n" + From 6ecac320f69d437d2e50d065bc688124bdaaad2a Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 6 Feb 2024 02:55:29 +0800 Subject: [PATCH 016/153] Added handling case for empty input - "". --- src/main/java/Dude.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index 79c6a9ea83..e8993d2385 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -40,6 +40,11 @@ public static void main(String[] args) { case "unmark": System.out.println(mark_as_undone(msg)); break; + case "": + System.out.println("\t-----------------------------------\n" + + "\tTask description is empty. Not added.\n" + + "\t-----------------------------------"); + break; default: System.out.println(add_task(msg)); } @@ -76,6 +81,7 @@ private static String bye(){ } private static String mark_as_done(String msg){ + //TODO: Write logic for commands with multiple parameters. Eg: mark 1 2 3 //Try to retrieve the index int index = 0; try{ @@ -97,6 +103,7 @@ private static String mark_as_done(String msg){ } private static String mark_as_undone(String msg){ + //TODO: Write logic for commands with multiple parameters. Eg: unmark 1 2 3 //Try to retrieve the index int index = 0; try{ From 8ba0809134276d4ed7da3533845183b299dbfb79 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 6 Feb 2024 03:07:33 +0800 Subject: [PATCH 017/153] Added Todo class --- src/main/java/Todo.java | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/main/java/Todo.java diff --git a/src/main/java/Todo.java b/src/main/java/Todo.java new file mode 100644 index 0000000000..2edec53028 --- /dev/null +++ b/src/main/java/Todo.java @@ -0,0 +1,21 @@ +public class Todo extends Task{ + + public Todo(String description) { + super(description); + } + + @Override + public void markAsDone() { + super.markAsDone(); + } + + @Override + public void markAsUndone() { + super.markAsUndone(); + } + + @Override + public String toString() { + return "[T]" + super.toString(); + } +} From a2106edb7a596d08be71d3db0db239f2bafe4885 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 6 Feb 2024 03:11:24 +0800 Subject: [PATCH 018/153] Added Deadline class --- src/main/java/Deadline.java | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/main/java/Deadline.java diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java new file mode 100644 index 0000000000..bfe0e98a72 --- /dev/null +++ b/src/main/java/Deadline.java @@ -0,0 +1,24 @@ +public class Deadline extends Task{ + + private final String deadline_date; + public Deadline(String description, String by) { + super(description); + this.deadline_date = by; + } + + @Override + public void markAsDone() { + super.markAsDone(); + } + + @Override + public void markAsUndone() { + super.markAsUndone(); + } + + @Override + public String toString() { + return "[D]" + super.toString() + " (by: " + deadline_date + ")"; + } + +} From 354d0f46dae8a1b29f8dd298c7c0d4aa3cd4840f Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 6 Feb 2024 03:16:35 +0800 Subject: [PATCH 019/153] Added Event class --- src/main/java/Event.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/main/java/Event.java diff --git a/src/main/java/Event.java b/src/main/java/Event.java new file mode 100644 index 0000000000..f9fe081d20 --- /dev/null +++ b/src/main/java/Event.java @@ -0,0 +1,17 @@ +public class Event extends Task{ + + private final String from_time; + private final String to_time; + + public Event(String description, String from_time, String to_time){ + super(description); + this.from_time = from_time; + this.to_time = to_time; + } + + @Override + public String toString() { + return "[E]" + super.toString() + " (from: " + from_time + " to: " + to_time + ")"; + } + +} From f94039598e2c462eef30b017fd5cc0858b08994f Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Wed, 7 Feb 2024 20:07:33 +0800 Subject: [PATCH 020/153] Added a utils class containing utility function(s) --- src/main/java/utils.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/main/java/utils.java diff --git a/src/main/java/utils.java b/src/main/java/utils.java new file mode 100644 index 0000000000..42ae6489c8 --- /dev/null +++ b/src/main/java/utils.java @@ -0,0 +1,19 @@ +public class utils { + + + // From chat GPT https://chat.openai.com/share/1848f5d2-1197-418e-86a9-bccdf69fc790 + public static String discardFirstWord(String input) { + // Split the string by whitespace + String[] words = input.split("\\s+", 2); + // Check if there are at least two words + if (words.length > 1) { + // Return the substring starting from the index of the second word + return input.substring(input.indexOf(words[1])); + } else { + // If there is only one word, return an empty string + return ""; + } + } + + +} From c469c033778caccebe92b7b0879aaa7e504a6a81 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Wed, 7 Feb 2024 20:16:27 +0800 Subject: [PATCH 021/153] Implemented a factory function for Todo --- src/main/java/Todo.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/java/Todo.java b/src/main/java/Todo.java index 2edec53028..33542cf3fe 100644 --- a/src/main/java/Todo.java +++ b/src/main/java/Todo.java @@ -1,5 +1,18 @@ public class Todo extends Task{ + static Todo from(String s){ + //Expects a string in the format "todo " + + //get rid of the command + String description = utils.discardFirstWord(s); + + if (!description.isEmpty()){ + return new Todo(description); + }else { + throw new IllegalArgumentException("The description of a todo cannot be empty."); + } + } + public Todo(String description) { super(description); } From 27166f7a9085ab2a5d6706b198a802d61c6a9dc9 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Wed, 7 Feb 2024 21:02:22 +0800 Subject: [PATCH 022/153] Implemented todo --- src/main/java/Dude.java | 30 ++++++++++++++++-------------- src/main/java/TaskList.java | 6 +++--- src/main/java/Todo.java | 4 +++- src/main/java/utils.java | 2 +- 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index e8993d2385..d553430b29 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -40,13 +40,13 @@ public static void main(String[] args) { case "unmark": System.out.println(mark_as_undone(msg)); break; - case "": - System.out.println("\t-----------------------------------\n" + - "\tTask description is empty. Not added.\n" + - "\t-----------------------------------"); + case "todo": + System.out.println(handle_todo_command(msg)); break; default: - System.out.println(add_task(msg)); + System.out.println("\t-----------------------------------\n" + + "\tI'm sorry, but I don't know what\n\tthat means :-(\n" + + "\t-----------------------------------"); } } @@ -59,14 +59,6 @@ private static String greet(){ "\t-----------------------------------\n"; } - private static String add_task(String msg){ - try { - return taskList.add_task(msg); - } catch (TaskListFullException e) { - return e.getMessage(); - } - } - private static String list(){ return taskList.toString(); } @@ -124,10 +116,20 @@ private static String mark_as_undone(String msg){ } } - private static String get_echo_msg(String msg){ + private static String echo(String msg){ return "\t-----------------------------------\n" + "\t" + msg + "\n" + "\t-----------------------------------"; } + + private static String handle_todo_command(String msg){ + try{ + Todo task = Todo.from(msg); + return taskList.add_task(task); + }catch (IllegalArgumentException | TaskListFullException e) { + return echo(e.getMessage()); + } + } + } diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index 74ab25b5ac..fd3b44ea71 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -10,17 +10,17 @@ public TaskList(){ count = 0; } - public String add_task(String msg) throws TaskListFullException { + public String add_task(Task task) throws TaskListFullException { if (this.count >= 100) { throw new TaskListFullException("Sorry, the task list is full."); } - list[count] = new Task(msg); + list[count] = task; count++; return "\t-----------------------------------\n" + - "\tadded: " + msg + "\n" + + "\tadded: " + task.getDescription() + "\n" + "\t-----------------------------------"; } diff --git a/src/main/java/Todo.java b/src/main/java/Todo.java index 33542cf3fe..38c469058c 100644 --- a/src/main/java/Todo.java +++ b/src/main/java/Todo.java @@ -4,7 +4,9 @@ static Todo from(String s){ //Expects a string in the format "todo " //get rid of the command - String description = utils.discardFirstWord(s); + String description = utils.discardFirstWord(s.trim()).trim(); + + System.out.println("Description is: " + description); if (!description.isEmpty()){ return new Todo(description); diff --git a/src/main/java/utils.java b/src/main/java/utils.java index 42ae6489c8..4ac813b27c 100644 --- a/src/main/java/utils.java +++ b/src/main/java/utils.java @@ -4,7 +4,7 @@ public class utils { // From chat GPT https://chat.openai.com/share/1848f5d2-1197-418e-86a9-bccdf69fc790 public static String discardFirstWord(String input) { // Split the string by whitespace - String[] words = input.split("\\s+", 2); + String[] words = input.split(" ", 2); // Check if there are at least two words if (words.length > 1) { // Return the substring starting from the index of the second word From 81016c0e8fb328dd02889a1bf99e8ed8e46d38d1 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Wed, 7 Feb 2024 22:24:05 +0800 Subject: [PATCH 023/153] Implemented deadline command --- src/main/java/Dude.java | 12 +++++ src/main/java/Event.java | 98 ++++++++++++++++++++++++++++++++++++++++ src/main/java/utils.java | 18 ++++++++ 3 files changed, 128 insertions(+) diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index d553430b29..7b95ff3db6 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -43,6 +43,9 @@ public static void main(String[] args) { case "todo": System.out.println(handle_todo_command(msg)); break; + case "event": + System.out.println(handle_event_command(msg)); + break; default: System.out.println("\t-----------------------------------\n" + "\tI'm sorry, but I don't know what\n\tthat means :-(\n" + @@ -132,4 +135,13 @@ private static String handle_todo_command(String msg){ } } + private static String handle_event_command(String msg){ + try{ + Event task = Event.from(msg); + return taskList.add_task(task); + }catch (IllegalArgumentException | TaskListFullException e) { + return echo(e.getMessage()); + } + } + } diff --git a/src/main/java/Event.java b/src/main/java/Event.java index f9fe081d20..5c8fe910af 100644 --- a/src/main/java/Event.java +++ b/src/main/java/Event.java @@ -3,6 +3,98 @@ public class Event extends Task{ private final String from_time; private final String to_time; + + public static Event from(String s){ + //Expects a string in the format "event /at to " + + //get rid of the command + // time time + String rest = utils.discardFirstWord(s.trim()).trim(); + + String[] arr = rest.split(" "); + + int from_occurences = utils.countOccurrences(arr, "/from"); + + System.out.println("From occurences: " + from_occurences); + + if (from_occurences == 0 || from_occurences > 1){ + throw new IllegalArgumentException("Invalid format. Follow this format: event /from /to . Provide one and only one '/from'."); + } + + int to_occurences = utils.countOccurrences(arr, "/to"); + + if (to_occurences == 0 || to_occurences > 1){ + throw new IllegalArgumentException("Invalid format. Follow this format: event /from /to . Provide one and only one '/to'."); + } + + //they will not be -1 as I have already checked for their occurences + int from_index = utils.findIndex(arr, "/from"); + int to_index = utils.findIndex(arr, "/to"); + + if (from_index > to_index){ + throw new IllegalArgumentException("The 'from time' of an event cannot be after the 'to time'."); + } + + //description is from 0 to from_index + String description = ""; + for (int i = 0; i < from_index; i++){ + description += arr[i] + " "; + } + description = description.trim(); + if (description.isEmpty()){ + throw new IllegalArgumentException("The description of an event cannot be empty."); + } + + String from_time = ""; + for (int i = from_index+1; i < to_index; i++){ + from_time += arr[i] + " "; + } + from_time = from_time.trim(); + if (from_time.isEmpty()){ + throw new IllegalArgumentException("The 'from_time' of an event cannot be empty."); + } + + String to_time = ""; + for (int i = to_index+1; i < arr.length; i++){ + to_time += arr[i] + " "; + } + to_time = to_time.trim(); + if (to_time.isEmpty()){ + throw new IllegalArgumentException("The 'to_time' of an event cannot be empty."); + } + + return new Event(description, from_time, to_time); + + +// String[] arr = rest.split(" /from "); +// if (arr.length != 2) { +// throw new IllegalArgumentException("Invalid format. Follow this format: event /from /to . Provide one and only one '/from'."); +// } +// +// String description = arr[0].trim(); +// if (description.isEmpty()){ +// throw new IllegalArgumentException("The description of an event cannot be empty."); +// } +// +// System.out.println("Description is: " + description); +// +// // /to +// rest = arr[1].trim(); +// arr = rest.split(" /to "); +// if (arr.length != 2) { +// throw new IllegalArgumentException("Invalid format. Follow this format: event /from /to . Provide one and only one '/to'."); +// } +// +// String from_time = arr[0].trim(); +// String to_time = arr[1].trim(); +// +// if (!description.isEmpty() && !from_time.isEmpty() && !to_time.isEmpty()){ +// return new Event(description, from_time, to_time); +// }else { +// throw new IllegalArgumentException("The description, from_time and to_time of an event cannot be empty."); +// } + } + public Event(String description, String from_time, String to_time){ super(description); this.from_time = from_time; @@ -14,4 +106,10 @@ public String toString() { return "[E]" + super.toString() + " (from: " + from_time + " to: " + to_time + ")"; } + private static void print_string_array(String[] arr){ + for (String s: arr){ + System.out.println(s); + } + } + } diff --git a/src/main/java/utils.java b/src/main/java/utils.java index 4ac813b27c..38b05f9b34 100644 --- a/src/main/java/utils.java +++ b/src/main/java/utils.java @@ -15,5 +15,23 @@ public static String discardFirstWord(String input) { } } + public static int countOccurrences(String[] array, String target) { + int count = 0; + for (String str : array) { + if (str.equals(target)) { + count++; + } + } + return count; + } + + public static int findIndex(String[] array, String target) { + for (int i = 0; i < array.length; i++) { + if (array[i].equals(target)) { + return i; // Return the index if the target string is found + } + } + return -1; // Return -1 if the target string is not found in the array + } } From d92b44c6b987765b593702d2c73db5d870801167 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Wed, 7 Feb 2024 22:26:19 +0800 Subject: [PATCH 024/153] Changed task add message --- src/main/java/TaskList.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index fd3b44ea71..bb135abf7d 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -20,7 +20,9 @@ public String add_task(Task task) throws TaskListFullException { count++; return "\t-----------------------------------\n" + - "\tadded: " + task.getDescription() + "\n" + + "\tGot it. I've added this task:\n" + + "\t\t" + task.toString() + "\n" + + "\tNow you have " + count + " tasks in the list.\n" + "\t-----------------------------------"; } From ea0f81005a8b8e311f9c2d0f45755389aaa0de17 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Wed, 7 Feb 2024 22:31:48 +0800 Subject: [PATCH 025/153] Added deadline command --- src/main/java/Deadline.java | 39 +++++++++++++++++++++++++++++++++++++ src/main/java/Dude.java | 12 ++++++++++++ 2 files changed, 51 insertions(+) diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java index bfe0e98a72..1563a19f92 100644 --- a/src/main/java/Deadline.java +++ b/src/main/java/Deadline.java @@ -1,5 +1,44 @@ public class Deadline extends Task{ + public static Deadline from(String s){ + //Expects a string in the format "deadline /by " + + //get rid of the command + String rest = utils.discardFirstWord(s.trim()).trim(); + + String[] arr = rest.split(" "); + + int by_occurences = utils.countOccurrences(arr, "/by"); + + if (by_occurences == 0 || by_occurences > 1){ + throw new IllegalArgumentException("Invalid format. Follow this format: deadline /by . Provide one and only one '/by'."); + } + + //they will not be -1 as I have already checked for their occurences + int by_index = utils.findIndex(arr, "/by"); + + //description is from 0 to by_index + String description = ""; + for (int i = 0; i < by_index; i++){ + description += arr[i] + " "; + } + description = description.trim(); + if (description.isEmpty()){ + throw new IllegalArgumentException("The description of a deadline cannot be empty."); + } + + String by = ""; + for (int i = by_index+1; i < arr.length; i++){ + by += arr[i] + " "; + } + by = by.trim(); + if (by.isEmpty()){ + throw new IllegalArgumentException("The 'by' of a deadline cannot be empty. Follow this format: deadline /by "); + } + + return new Deadline(description, by); + } + private final String deadline_date; public Deadline(String description, String by) { super(description); diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index 7b95ff3db6..315290764a 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -46,6 +46,9 @@ public static void main(String[] args) { case "event": System.out.println(handle_event_command(msg)); break; + case "deadline": + System.out.println(handle_deadline_command(msg)); + break; default: System.out.println("\t-----------------------------------\n" + "\tI'm sorry, but I don't know what\n\tthat means :-(\n" + @@ -144,4 +147,13 @@ private static String handle_event_command(String msg){ } } + private static String handle_deadline_command(String msg){ + try{ + Deadline task = Deadline.from(msg); + return taskList.add_task(task); + }catch (IllegalArgumentException | TaskListFullException e) { + return echo(e.getMessage()); + } + } + } From c7eeee88ae397bbe538691502991c853ffc1091a Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Wed, 7 Feb 2024 22:32:46 +0800 Subject: [PATCH 026/153] Added deadline command --- src/main/java/Event.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/main/java/Event.java b/src/main/java/Event.java index 5c8fe910af..11232c3481 100644 --- a/src/main/java/Event.java +++ b/src/main/java/Event.java @@ -105,11 +105,4 @@ public Event(String description, String from_time, String to_time){ public String toString() { return "[E]" + super.toString() + " (from: " + from_time + " to: " + to_time + ")"; } - - private static void print_string_array(String[] arr){ - for (String s: arr){ - System.out.println(s); - } - } - } From 2aa5e2ef668be4ae1bb5c4a423ca9e65e3b1b7c3 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Thu, 8 Feb 2024 00:32:21 +0800 Subject: [PATCH 027/153] Bug fixes --- src/main/java/Dude.java | 31 ++++++++----- src/main/java/Event.java | 31 ------------- src/main/java/Todo.java | 2 - text-ui-test/EXPECTED.TXT | 97 ++++++++++++++++++++++++++++++++++++--- text-ui-test/input.txt | 23 ++++++++++ text-ui-test/runtest.bat | 2 +- 6 files changed, 134 insertions(+), 52 deletions(-) diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index 315290764a..c7f2948f6c 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -1,3 +1,4 @@ +import java.util.NoSuchElementException; import java.util.Scanner; public class Dude { @@ -6,17 +7,17 @@ public class Dude { public static void main(String[] args) { - String logo = "888888ba dP \n" + - "88 `8b 88 \n" + - "88 88 dP dP .d888b88 .d8888b. \n" + - "88 88 88 88 88' `88 88ooood8 \n" + - "88 .8P 88. .88 88. .88 88. ... \n" + - "8888888P `88888P' `88888P8 `88888P'"; - - System.out.println("--------------------------------------\n"); - System.out.println(logo + "\n"); - System.out.println("--------------------------------------"); - System.out.println("Dude v1.0 by Tahsin Hasem.\n"); +// String logo = "888888ba dP \n" + +// "88 `8b 88 \n" + +// "88 88 dP dP .d888b88 .d8888b. \n" + +// "88 88 88 88 88' `88 88ooood8 \n" + +// "88 .8P 88. .88 88. .88 88. ... \n" + +// "8888888P `88888P' `88888P8 `88888P'"; +// +// System.out.println("--------------------------------------\n"); +// System.out.println(logo + "\n"); +// System.out.println("--------------------------------------"); +// System.out.println("Dude v1.0 by Tahsin Hasem.\n"); System.out.println(greet()); @@ -24,7 +25,13 @@ public static void main(String[] args) { Scanner sc = new Scanner(System.in); while(true){ - String msg = sc.nextLine(); + String msg = ""; + try { + msg = sc.nextLine(); + }catch(NoSuchElementException e){ + //this will not be handled. + break; + } String first_arg = msg.split(" ")[0]; switch (first_arg){ diff --git a/src/main/java/Event.java b/src/main/java/Event.java index 11232c3481..876691a00e 100644 --- a/src/main/java/Event.java +++ b/src/main/java/Event.java @@ -15,8 +15,6 @@ public static Event from(String s){ int from_occurences = utils.countOccurrences(arr, "/from"); - System.out.println("From occurences: " + from_occurences); - if (from_occurences == 0 || from_occurences > 1){ throw new IllegalArgumentException("Invalid format. Follow this format: event /from /to . Provide one and only one '/from'."); } @@ -64,35 +62,6 @@ public static Event from(String s){ } return new Event(description, from_time, to_time); - - -// String[] arr = rest.split(" /from "); -// if (arr.length != 2) { -// throw new IllegalArgumentException("Invalid format. Follow this format: event /from /to . Provide one and only one '/from'."); -// } -// -// String description = arr[0].trim(); -// if (description.isEmpty()){ -// throw new IllegalArgumentException("The description of an event cannot be empty."); -// } -// -// System.out.println("Description is: " + description); -// -// // /to -// rest = arr[1].trim(); -// arr = rest.split(" /to "); -// if (arr.length != 2) { -// throw new IllegalArgumentException("Invalid format. Follow this format: event /from /to . Provide one and only one '/to'."); -// } -// -// String from_time = arr[0].trim(); -// String to_time = arr[1].trim(); -// -// if (!description.isEmpty() && !from_time.isEmpty() && !to_time.isEmpty()){ -// return new Event(description, from_time, to_time); -// }else { -// throw new IllegalArgumentException("The description, from_time and to_time of an event cannot be empty."); -// } } public Event(String description, String from_time, String to_time){ diff --git a/src/main/java/Todo.java b/src/main/java/Todo.java index 38c469058c..b8ec6f81e4 100644 --- a/src/main/java/Todo.java +++ b/src/main/java/Todo.java @@ -6,8 +6,6 @@ static Todo from(String s){ //get rid of the command String description = utils.discardFirstWord(s.trim()).trim(); - System.out.println("Description is: " + description); - if (!description.isEmpty()){ return new Todo(description); }else { diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 657e74f6e7..070d1c18ae 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,7 +1,92 @@ -Hello from - ____ _ -| _ \ _ _| | _____ -| | | | | | | |/ / _ \ -| |_| | |_| | < __/ -|____/ \__,_|_|\_\___| + ----------------------------------- + Hello! I'm Dude + What can I do for you? + ----------------------------------- + ----------------------------------- + Got it. I've added this task: + [T][ ] Do CS2103T ip work + Now you have 1 tasks in the list. + ----------------------------------- + ----------------------------------- + 1. [T][ ] Do CS2103T ip work + ----------------------------------- + ----------------------------------- + The description of a todo cannot be empty. + ----------------------------------- + ----------------------------------- + Got it. I've added this task: + [D][ ] CS2101 CA1 (by: Monday) + Now you have 2 tasks in the list. + ----------------------------------- + ----------------------------------- + 1. [T][ ] Do CS2103T ip work + 2. [D][ ] CS2101 CA1 (by: Monday) + ----------------------------------- + ----------------------------------- + Invalid format. Follow this format: deadline /by . Provide one and only one '/by'. + ----------------------------------- + ----------------------------------- + 1. [T][ ] Do CS2103T ip work + 2. [D][ ] CS2101 CA1 (by: Monday) + ----------------------------------- + ----------------------------------- + The description of a deadline cannot be empty. + ----------------------------------- + ----------------------------------- + 1. [T][ ] Do CS2103T ip work + 2. [D][ ] CS2101 CA1 (by: Monday) + ----------------------------------- + ----------------------------------- + Got it. I've added this task: + [E][ ] CS2103T tutorial (from: 9am to: 11am) + Now you have 3 tasks in the list. + ----------------------------------- + ----------------------------------- + 1. [T][ ] Do CS2103T ip work + 2. [D][ ] CS2101 CA1 (by: Monday) + 3. [E][ ] CS2103T tutorial (from: 9am to: 11am) + ----------------------------------- + ----------------------------------- + The description of an event cannot be empty. + ----------------------------------- + ----------------------------------- + 1. [T][ ] Do CS2103T ip work + 2. [D][ ] CS2101 CA1 (by: Monday) + 3. [E][ ] CS2103T tutorial (from: 9am to: 11am) + ----------------------------------- + ----------------------------------- + Invalid format. Follow this format: event /from /to . Provide one and only one '/from'. + ----------------------------------- + ----------------------------------- + 1. [T][ ] Do CS2103T ip work + 2. [D][ ] CS2101 CA1 (by: Monday) + 3. [E][ ] CS2103T tutorial (from: 9am to: 11am) + ----------------------------------- + ----------------------------------- + Invalid format. Follow this format: event /from /to . Provide one and only one '/to'. + ----------------------------------- + ----------------------------------- + 1. [T][ ] Do CS2103T ip work + 2. [D][ ] CS2101 CA1 (by: Monday) + 3. [E][ ] CS2103T tutorial (from: 9am to: 11am) + ----------------------------------- + ----------------------------------- + Invalid format. Follow this format: event /from /to . Provide one and only one '/from'. + ----------------------------------- + ----------------------------------- + 1. [T][ ] Do CS2103T ip work + 2. [D][ ] CS2101 CA1 (by: Monday) + 3. [E][ ] CS2103T tutorial (from: 9am to: 11am) + ----------------------------------- + ----------------------------------- + Invalid format. Follow this format: event /from /to . Provide one and only one '/from'. + ----------------------------------- + ----------------------------------- + 1. [T][ ] Do CS2103T ip work + 2. [D][ ] CS2101 CA1 (by: Monday) + 3. [E][ ] CS2103T tutorial (from: 9am to: 11am) + ----------------------------------- + ----------------------------------- + Bye. Hope to see you again soon! + ----------------------------------- diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index e69de29bb2..47ff7f6b51 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -0,0 +1,23 @@ +todo Do CS2103T ip work +list +todo +deadline CS2101 CA1 /by Monday +list +deadline some other task +list +deadline /by Monday +list +event CS2103T tutorial /from 9am /to 11am +list +event /from 9am /to 11am +list +event CS2103T tutorial /to 11am +list +event CS2103T tutorial /from 9am +list +event CS2103T tutorial +list +event +list +bye +``` \ No newline at end of file diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat index 0873744649..bd6d4bcdca 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 Dude < input.txt > ACTUAL.TXT REM compare the output to the expected output FC ACTUAL.TXT EXPECTED.TXT From 2f7abe2cf188384b3037033a3206433f100b35b7 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Thu, 8 Feb 2024 00:39:28 +0800 Subject: [PATCH 028/153] Added DukeException.java and subclasses for error handling --- src/main/java/DukeException.java | 5 +++++ src/main/java/InvalidArgumentException.java | 6 ++++++ src/main/java/InvalidCommandException.java | 6 ++++++ src/main/java/InvalidDescriptionException.java | 6 ++++++ src/main/java/TaskListFullException.java | 2 +- 5 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/main/java/DukeException.java create mode 100644 src/main/java/InvalidArgumentException.java create mode 100644 src/main/java/InvalidCommandException.java create mode 100644 src/main/java/InvalidDescriptionException.java diff --git a/src/main/java/DukeException.java b/src/main/java/DukeException.java new file mode 100644 index 0000000000..c858d79e91 --- /dev/null +++ b/src/main/java/DukeException.java @@ -0,0 +1,5 @@ +public class DukeException extends Exception{ + public DukeException(String message) { + super(message); + } +} diff --git a/src/main/java/InvalidArgumentException.java b/src/main/java/InvalidArgumentException.java new file mode 100644 index 0000000000..81a55ba202 --- /dev/null +++ b/src/main/java/InvalidArgumentException.java @@ -0,0 +1,6 @@ +public class InvalidArgumentException extends DukeException{ + //Used to indicate that an argument for the command is invalid + public InvalidArgumentException(String message) { + super(message); + } +} diff --git a/src/main/java/InvalidCommandException.java b/src/main/java/InvalidCommandException.java new file mode 100644 index 0000000000..86ceeb7d38 --- /dev/null +++ b/src/main/java/InvalidCommandException.java @@ -0,0 +1,6 @@ +public class InvalidCommandException extends DukeException{ + //Used to indicate that the command is invalid + public InvalidCommandException(String message) { + super(message); + } +} diff --git a/src/main/java/InvalidDescriptionException.java b/src/main/java/InvalidDescriptionException.java new file mode 100644 index 0000000000..6870f1dc1e --- /dev/null +++ b/src/main/java/InvalidDescriptionException.java @@ -0,0 +1,6 @@ +public class InvalidDescriptionException extends DukeException{ + //Used to indicate that the description is invalid + public InvalidDescriptionException(String message) { + super(message); + } +} diff --git a/src/main/java/TaskListFullException.java b/src/main/java/TaskListFullException.java index c7675b8dca..76f37308a5 100644 --- a/src/main/java/TaskListFullException.java +++ b/src/main/java/TaskListFullException.java @@ -1,4 +1,4 @@ -public class TaskListFullException extends Exception { +public class TaskListFullException extends DukeException { //Used to indicate that the task list is full public TaskListFullException(String message) { super(message); From c2b69d0ce6e1ecd5a0dd2bdfa8d995b067fb2f6c Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Thu, 8 Feb 2024 00:40:23 +0800 Subject: [PATCH 029/153] Renamed DukeException to DudeException --- src/main/java/DudeException.java | 5 +++++ src/main/java/DukeException.java | 5 ----- src/main/java/InvalidArgumentException.java | 2 +- src/main/java/InvalidCommandException.java | 2 +- src/main/java/InvalidDescriptionException.java | 2 +- src/main/java/TaskListFullException.java | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) create mode 100644 src/main/java/DudeException.java delete mode 100644 src/main/java/DukeException.java diff --git a/src/main/java/DudeException.java b/src/main/java/DudeException.java new file mode 100644 index 0000000000..aa946bfcf6 --- /dev/null +++ b/src/main/java/DudeException.java @@ -0,0 +1,5 @@ +public class DudeException extends Exception{ + public DudeException(String message) { + super(message); + } +} diff --git a/src/main/java/DukeException.java b/src/main/java/DukeException.java deleted file mode 100644 index c858d79e91..0000000000 --- a/src/main/java/DukeException.java +++ /dev/null @@ -1,5 +0,0 @@ -public class DukeException extends Exception{ - public DukeException(String message) { - super(message); - } -} diff --git a/src/main/java/InvalidArgumentException.java b/src/main/java/InvalidArgumentException.java index 81a55ba202..d3a3b34b29 100644 --- a/src/main/java/InvalidArgumentException.java +++ b/src/main/java/InvalidArgumentException.java @@ -1,4 +1,4 @@ -public class InvalidArgumentException extends DukeException{ +public class InvalidArgumentException extends DudeException { //Used to indicate that an argument for the command is invalid public InvalidArgumentException(String message) { super(message); diff --git a/src/main/java/InvalidCommandException.java b/src/main/java/InvalidCommandException.java index 86ceeb7d38..4ba4d2074c 100644 --- a/src/main/java/InvalidCommandException.java +++ b/src/main/java/InvalidCommandException.java @@ -1,4 +1,4 @@ -public class InvalidCommandException extends DukeException{ +public class InvalidCommandException extends DudeException { //Used to indicate that the command is invalid public InvalidCommandException(String message) { super(message); diff --git a/src/main/java/InvalidDescriptionException.java b/src/main/java/InvalidDescriptionException.java index 6870f1dc1e..6da76bb00d 100644 --- a/src/main/java/InvalidDescriptionException.java +++ b/src/main/java/InvalidDescriptionException.java @@ -1,4 +1,4 @@ -public class InvalidDescriptionException extends DukeException{ +public class InvalidDescriptionException extends DudeException { //Used to indicate that the description is invalid public InvalidDescriptionException(String message) { super(message); diff --git a/src/main/java/TaskListFullException.java b/src/main/java/TaskListFullException.java index 76f37308a5..520373a9fe 100644 --- a/src/main/java/TaskListFullException.java +++ b/src/main/java/TaskListFullException.java @@ -1,4 +1,4 @@ -public class TaskListFullException extends DukeException { +public class TaskListFullException extends DudeException { //Used to indicate that the task list is full public TaskListFullException(String message) { super(message); From adbedecedd57db93ba78ca5e035238580442b737 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Thu, 8 Feb 2024 00:43:10 +0800 Subject: [PATCH 030/153] Added InvalidFormatException.java --- src/main/java/InvalidFormatException.java | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/main/java/InvalidFormatException.java diff --git a/src/main/java/InvalidFormatException.java b/src/main/java/InvalidFormatException.java new file mode 100644 index 0000000000..309850ffe8 --- /dev/null +++ b/src/main/java/InvalidFormatException.java @@ -0,0 +1,6 @@ +public class InvalidFormatException extends DudeException{ + //Used to indicate that the format is invalid + public InvalidFormatException(String message) { + super(message); + } +} From 8960bc53c412a6331876f4c7ffc451fd96605ae8 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Thu, 8 Feb 2024 00:44:43 +0800 Subject: [PATCH 031/153] Added appropriate exceptions to Event Class --- src/main/java/Event.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/Event.java b/src/main/java/Event.java index 876691a00e..146344980c 100644 --- a/src/main/java/Event.java +++ b/src/main/java/Event.java @@ -4,7 +4,7 @@ public class Event extends Task{ private final String to_time; - public static Event from(String s){ + public static Event from(String s) throws InvalidArgumentException, InvalidFormatException, InvalidDescriptionException { //Expects a string in the format "event /at to " //get rid of the command @@ -16,13 +16,13 @@ public static Event from(String s){ int from_occurences = utils.countOccurrences(arr, "/from"); if (from_occurences == 0 || from_occurences > 1){ - throw new IllegalArgumentException("Invalid format. Follow this format: event /from /to . Provide one and only one '/from'."); + throw new InvalidFormatException("Invalid format. Follow this format: event /from /to . Provide one and only one '/from'."); } int to_occurences = utils.countOccurrences(arr, "/to"); if (to_occurences == 0 || to_occurences > 1){ - throw new IllegalArgumentException("Invalid format. Follow this format: event /from /to . Provide one and only one '/to'."); + throw new InvalidFormatException("Invalid format. Follow this format: event /from /to . Provide one and only one '/to'."); } //they will not be -1 as I have already checked for their occurences @@ -30,7 +30,7 @@ public static Event from(String s){ int to_index = utils.findIndex(arr, "/to"); if (from_index > to_index){ - throw new IllegalArgumentException("The 'from time' of an event cannot be after the 'to time'."); + throw new InvalidFormatException("The 'from time' of an event cannot be after the 'to time'."); } //description is from 0 to from_index @@ -40,7 +40,7 @@ public static Event from(String s){ } description = description.trim(); if (description.isEmpty()){ - throw new IllegalArgumentException("The description of an event cannot be empty."); + throw new InvalidDescriptionException("The description of an event cannot be empty."); } String from_time = ""; @@ -49,7 +49,7 @@ public static Event from(String s){ } from_time = from_time.trim(); if (from_time.isEmpty()){ - throw new IllegalArgumentException("The 'from_time' of an event cannot be empty."); + throw new InvalidArgumentException("The 'from_time' of an event cannot be empty."); } String to_time = ""; @@ -58,7 +58,7 @@ public static Event from(String s){ } to_time = to_time.trim(); if (to_time.isEmpty()){ - throw new IllegalArgumentException("The 'to_time' of an event cannot be empty."); + throw new InvalidArgumentException("The 'to_time' of an event cannot be empty."); } return new Event(description, from_time, to_time); From 6f2636f1a2a02cc4b6dba9c3c99708f19c84e095 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Thu, 8 Feb 2024 00:45:35 +0800 Subject: [PATCH 032/153] Added appropriate exceptions to Todo Class --- src/main/java/Todo.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/Todo.java b/src/main/java/Todo.java index b8ec6f81e4..6b367aa2c4 100644 --- a/src/main/java/Todo.java +++ b/src/main/java/Todo.java @@ -1,6 +1,6 @@ public class Todo extends Task{ - static Todo from(String s){ + static Todo from(String s) throws InvalidDescriptionException { //Expects a string in the format "todo " //get rid of the command @@ -9,7 +9,7 @@ static Todo from(String s){ if (!description.isEmpty()){ return new Todo(description); }else { - throw new IllegalArgumentException("The description of a todo cannot be empty."); + throw new InvalidDescriptionException("The description of a todo cannot be empty."); } } From 0bb1cb878b070c8c5e90b580c224f17f7f4ba392 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Thu, 8 Feb 2024 00:46:21 +0800 Subject: [PATCH 033/153] Added appropriate exceptions to Deadline Class --- src/main/java/Deadline.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java index 1563a19f92..5a6c35eb0a 100644 --- a/src/main/java/Deadline.java +++ b/src/main/java/Deadline.java @@ -11,7 +11,7 @@ public static Deadline from(String s){ int by_occurences = utils.countOccurrences(arr, "/by"); if (by_occurences == 0 || by_occurences > 1){ - throw new IllegalArgumentException("Invalid format. Follow this format: deadline /by . Provide one and only one '/by'."); + throw new InvalidFormatException("Invalid format. Follow this format: deadline /by . Provide one and only one '/by'."); } //they will not be -1 as I have already checked for their occurences @@ -24,7 +24,7 @@ public static Deadline from(String s){ } description = description.trim(); if (description.isEmpty()){ - throw new IllegalArgumentException("The description of a deadline cannot be empty."); + throw new InvalidDescriptionException("The description of a deadline cannot be empty."); } String by = ""; @@ -33,7 +33,7 @@ public static Deadline from(String s){ } by = by.trim(); if (by.isEmpty()){ - throw new IllegalArgumentException("The 'by' of a deadline cannot be empty. Follow this format: deadline /by "); + throw new InvalidArgumentException("The 'by' of a deadline cannot be empty. Follow this format: deadline /by "); } return new Deadline(description, by); From 93ba8d6f3b6cdd905b5ab6d20a1615e60cd01304 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Thu, 8 Feb 2024 01:41:02 +0800 Subject: [PATCH 034/153] Refactored to proper error handling --- src/main/java/Deadline.java | 2 +- src/main/java/Dude.java | 30 +++++++++++++++++++++++++----- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java index 5a6c35eb0a..d3605d0811 100644 --- a/src/main/java/Deadline.java +++ b/src/main/java/Deadline.java @@ -1,6 +1,6 @@ public class Deadline extends Task{ - public static Deadline from(String s){ + public static Deadline from(String s) throws InvalidFormatException, InvalidDescriptionException, InvalidArgumentException { //Expects a string in the format "deadline /by " //get rid of the command diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index c7f2948f6c..d42b0d7cba 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -5,6 +5,8 @@ public class Dude { static TaskList taskList = new TaskList(); + static final String[] supported_commands = {"bye", "list", "mark", "unmark", "todo", "event", "deadline"}; + public static void main(String[] args) { // String logo = "888888ba dP \n" + @@ -32,9 +34,16 @@ public static void main(String[] args) { //this will not be handled. break; } - String first_arg = msg.split(" ")[0]; - switch (first_arg){ + String command = ""; + try { + command = get_command(msg); + }catch (InvalidCommandException e){ + System.out.println(echo(e.getMessage())); + continue; + } + + switch (command){ case "bye": System.out.println(bye()); return; @@ -140,7 +149,7 @@ private static String handle_todo_command(String msg){ try{ Todo task = Todo.from(msg); return taskList.add_task(task); - }catch (IllegalArgumentException | TaskListFullException e) { + }catch (InvalidDescriptionException | TaskListFullException e) { return echo(e.getMessage()); } } @@ -149,7 +158,7 @@ private static String handle_event_command(String msg){ try{ Event task = Event.from(msg); return taskList.add_task(task); - }catch (IllegalArgumentException | TaskListFullException e) { + }catch (InvalidDescriptionException | InvalidFormatException | InvalidArgumentException | TaskListFullException e) { return echo(e.getMessage()); } } @@ -158,9 +167,20 @@ private static String handle_deadline_command(String msg){ try{ Deadline task = Deadline.from(msg); return taskList.add_task(task); - }catch (IllegalArgumentException | TaskListFullException e) { + }catch (InvalidFormatException | InvalidArgumentException | InvalidDescriptionException | TaskListFullException e) { return echo(e.getMessage()); } } + private static String get_command(String msg) throws InvalidCommandException { + String cmd = msg.split(" ")[0]; + + for (String supported_command : supported_commands) { + if (cmd.equals(supported_command)) { + return cmd; + } + } + throw new InvalidCommandException("I'm sorry, but I don't know what\n\tthat means :-("); + } + } From 4c80fead9f948dafa27ba9ac855e942752ebb8cb Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Thu, 8 Feb 2024 01:42:40 +0800 Subject: [PATCH 035/153] Removed default file --- src/main/java/Dude.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index d42b0d7cba..f75fe9c103 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -65,10 +65,6 @@ public static void main(String[] args) { case "deadline": System.out.println(handle_deadline_command(msg)); break; - default: - System.out.println("\t-----------------------------------\n" + - "\tI'm sorry, but I don't know what\n\tthat means :-(\n" + - "\t-----------------------------------"); } } From cc49f02b5bd92e0478f47ae92fe08582aa37710c Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Thu, 8 Feb 2024 01:42:40 +0800 Subject: [PATCH 036/153] Removed default from switch statement --- src/main/java/Dude.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index d42b0d7cba..f75fe9c103 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -65,10 +65,6 @@ public static void main(String[] args) { case "deadline": System.out.println(handle_deadline_command(msg)); break; - default: - System.out.println("\t-----------------------------------\n" + - "\tI'm sorry, but I don't know what\n\tthat means :-(\n" + - "\t-----------------------------------"); } } From 8412be503e76d25a9a8e3544f54bb4e3188437f1 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Thu, 8 Feb 2024 02:20:27 +0800 Subject: [PATCH 037/153] Refactored list from array to ArrayList --- src/main/java/TaskList.java | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index bb135abf7d..e9d1e1f5db 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -1,12 +1,13 @@ import java.awt.*; +import java.util.ArrayList; public class TaskList { - private final Task[] list; + private final ArrayList list; private int count; public TaskList(){ - list = new Task[100]; + list = new ArrayList<>(100); count = 0; } @@ -16,7 +17,7 @@ public String add_task(Task task) throws TaskListFullException { throw new TaskListFullException("Sorry, the task list is full."); } - list[count] = task; + list.add(task); count++; return "\t-----------------------------------\n" + @@ -30,10 +31,10 @@ public String mark_as_done(int index) throws IndexOutOfBoundsException{ if (index > count || index < 1) { throw new IndexOutOfBoundsException("Sorry, the provided id is invalid."); } - list[index - 1].markAsDone(); + list.get(index - 1).markAsDone(); return "\t-----------------------------------\n" + "\tNice! I've marked this task as done:\n" + - "\t " + index + ". " + list[index - 1].toString() + "\n" + + "\t " + index + ". " + list.get(index - 1).toString() + "\n" + "\t-----------------------------------"; } @@ -41,10 +42,10 @@ public String mark_as_undone(int index) throws IndexOutOfBoundsException { if (index > count || index < 1) { throw new IndexOutOfBoundsException("Sorry, the provided id is invalid."); } - list[index - 1].markAsUndone(); + list.get(index - 1).markAsUndone(); return "\t-----------------------------------\n" + "\tNice! I've marked this task as undone:\n" + - "\t " + index + ". " + list[index - 1].toString() + "\n" + + "\t " + index + ". " + list.get(index - 1).toString() + "\n" + "\t-----------------------------------"; } @@ -53,7 +54,7 @@ public String mark_as_undone(int index) throws IndexOutOfBoundsException { public String toString() { String result = "\t-----------------------------------\n"; for (int i = 0; i < count; i++) { - result += "\t" + (i + 1) + ". " + list[i].toString() + "\n"; + result += "\t" + (i + 1) + ". " + list.get(i).toString() + "\n"; } result += "\t-----------------------------------"; return result; From 5336b7f1e0d789c889d1f61dea67ead2ae57a20a Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Thu, 8 Feb 2024 02:22:36 +0800 Subject: [PATCH 038/153] Removed use of count to keep track of tasks. Replaced with arraylist size --- src/main/java/TaskList.java | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index e9d1e1f5db..87c80df94f 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -4,31 +4,28 @@ public class TaskList { private final ArrayList list; - private int count; public TaskList(){ - list = new ArrayList<>(100); - count = 0; + list = new ArrayList<>(); } public String add_task(Task task) throws TaskListFullException { - if (this.count >= 100) { + if ( list.size() >= 100) { throw new TaskListFullException("Sorry, the task list is full."); } list.add(task); - count++; return "\t-----------------------------------\n" + "\tGot it. I've added this task:\n" + "\t\t" + task.toString() + "\n" + - "\tNow you have " + count + " tasks in the list.\n" + + "\tNow you have " + list.size() + " tasks in the list.\n" + "\t-----------------------------------"; } public String mark_as_done(int index) throws IndexOutOfBoundsException{ - if (index > count || index < 1) { + if (index > list.size() || index < 1) { throw new IndexOutOfBoundsException("Sorry, the provided id is invalid."); } list.get(index - 1).markAsDone(); @@ -39,7 +36,7 @@ public String mark_as_done(int index) throws IndexOutOfBoundsException{ } public String mark_as_undone(int index) throws IndexOutOfBoundsException { - if (index > count || index < 1) { + if (index > list.size() || index < 1) { throw new IndexOutOfBoundsException("Sorry, the provided id is invalid."); } list.get(index - 1).markAsUndone(); @@ -53,7 +50,7 @@ public String mark_as_undone(int index) throws IndexOutOfBoundsException { @Override public String toString() { String result = "\t-----------------------------------\n"; - for (int i = 0; i < count; i++) { + for (int i = 0; i < list.size(); i++) { result += "\t" + (i + 1) + ". " + list.get(i).toString() + "\n"; } result += "\t-----------------------------------"; From dd4918a3c007ccc206c8b1cbed560218f4e58d3d Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Thu, 8 Feb 2024 02:43:29 +0800 Subject: [PATCH 039/153] Handle error for non integer ids --- src/main/java/Dude.java | 28 +++++++++++++++++++++++++--- src/main/java/TaskList.java | 12 ++++++++++++ text-ui-test/input.txt | 1 + 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index f75fe9c103..41b24c2c43 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -5,7 +5,7 @@ public class Dude { static TaskList taskList = new TaskList(); - static final String[] supported_commands = {"bye", "list", "mark", "unmark", "todo", "event", "deadline"}; + static final String[] supported_commands = {"bye", "list", "mark", "unmark", "todo", "event", "deadline", "delete"}; public static void main(String[] args) { @@ -65,6 +65,9 @@ public static void main(String[] args) { case "deadline": System.out.println(handle_deadline_command(msg)); break; + case "delete": + System.out.println(handle_delete_command(msg)); + break; } } @@ -96,7 +99,7 @@ private static String mark_as_done(String msg){ int index = 0; try{ index = Integer.parseInt(msg.split(" ")[1]); - } catch (IndexOutOfBoundsException e) { + } catch (IndexOutOfBoundsException | NumberFormatException e) { return "\t-----------------------------------\n" + "\tPlease provide a valid task ID. Has to be an integer.\n" + "\t-----------------------------------"; @@ -118,7 +121,7 @@ private static String mark_as_undone(String msg){ int index = 0; try{ index = Integer.parseInt(msg.split(" ")[1]); - } catch (IndexOutOfBoundsException e) { + } catch (IndexOutOfBoundsException | NumberFormatException e) { return "\t-----------------------------------\n" + "\tPlease provide a valid task ID. Has to be an integer.\n" + "\t-----------------------------------"; @@ -168,6 +171,25 @@ private static String handle_deadline_command(String msg){ } } + private static String handle_delete_command(String msg){ + int index = 0; + try{ + index = Integer.parseInt(msg.split(" ")[1]); + } catch (IndexOutOfBoundsException | NumberFormatException e) { + return "\t-----------------------------------\n" + + "\tPlease provide a valid task ID. Has to be an integer.\n" + + "\t-----------------------------------"; + } + + try { + return taskList.remove_task(index); + } catch (IndexOutOfBoundsException e) { + return "\t-----------------------------------\n" + + "\t" + e.getMessage() +"\n" + + "\t-----------------------------------"; + } + } + private static String get_command(String msg) throws InvalidCommandException { String cmd = msg.split(" ")[0]; diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index 87c80df94f..56d9d0e703 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -24,6 +24,18 @@ public String add_task(Task task) throws TaskListFullException { "\t-----------------------------------"; } + public String remove_task(int index) throws IndexOutOfBoundsException { + if (index > list.size() || index < 1) { + throw new IndexOutOfBoundsException("Sorry, the provided id is invalid."); + } + Task removed = list.remove(index - 1); + return "\t-----------------------------------\n" + + "\tNoted. I've removed this task:\n" + + "\t " + removed.toString() + "\n" + + "\tNow you have " + list.size() + " tasks in the list.\n" + + "\t-----------------------------------"; + } + public String mark_as_done(int index) throws IndexOutOfBoundsException{ if (index > list.size() || index < 1) { throw new IndexOutOfBoundsException("Sorry, the provided id is invalid."); diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index 47ff7f6b51..956b22f84a 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -19,5 +19,6 @@ event CS2103T tutorial list event list +delete 1 bye ``` \ No newline at end of file From 4657d4af8e44bc16b70e1776c2346ea1ad69e932 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Thu, 8 Feb 2024 02:46:41 +0800 Subject: [PATCH 040/153] Added testing for delete command --- text-ui-test/EXPECTED.TXT | 19 +++++++++++++++++++ text-ui-test/input.txt | 4 ++++ 2 files changed, 23 insertions(+) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 070d1c18ae..1c4f3d7f6e 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -88,5 +88,24 @@ 3. [E][ ] CS2103T tutorial (from: 9am to: 11am) ----------------------------------- ----------------------------------- + Noted. I've removed this task: + [T][ ] Do CS2103T ip work + Now you have 2 tasks in the list. + ----------------------------------- + ----------------------------------- + 1. [D][ ] CS2101 CA1 (by: Monday) + 2. [E][ ] CS2103T tutorial (from: 9am to: 11am) + ----------------------------------- + ----------------------------------- + Please provide a valid task ID. Has to be an integer. + ----------------------------------- + ----------------------------------- + Please provide a valid task ID. Has to be an integer. + ----------------------------------- + ----------------------------------- + 1. [D][ ] CS2101 CA1 (by: Monday) + 2. [E][ ] CS2103T tutorial (from: 9am to: 11am) + ----------------------------------- + ----------------------------------- Bye. Hope to see you again soon! ----------------------------------- diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index 956b22f84a..3165555d72 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -20,5 +20,9 @@ list event list delete 1 +list +delete +delete x +list bye ``` \ No newline at end of file From 2d3a5baf5f8cfea159710b8d3e9630a57c5b4c02 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sat, 17 Feb 2024 03:44:54 +0800 Subject: [PATCH 041/153] Added Storage Class --- src/main/java/Utils/Storage.java | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 src/main/java/Utils/Storage.java diff --git a/src/main/java/Utils/Storage.java b/src/main/java/Utils/Storage.java new file mode 100644 index 0000000000..211be24ca2 --- /dev/null +++ b/src/main/java/Utils/Storage.java @@ -0,0 +1,4 @@ +package Utils; + +public class Storage { +} From 502845f8a773660eb7c347d5991e2eaa501d4cc8 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sat, 17 Feb 2024 03:58:34 +0800 Subject: [PATCH 042/153] Added create storage function --- src/main/java/Utils/Storage.java | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/main/java/Utils/Storage.java b/src/main/java/Utils/Storage.java index 211be24ca2..6770123c37 100644 --- a/src/main/java/Utils/Storage.java +++ b/src/main/java/Utils/Storage.java @@ -1,4 +1,26 @@ package Utils; +import java.io.File; +import java.io.IOException; + public class Storage { + + + /** + * Creates a storage file if it does not exist. + * @throws IOException + */ + public static void createStorage() throws IOException, SecurityException{ + String filepath = "data/dude.txt"; + File file = new File(filepath); + + boolean fileExists = file.exists(); + + if (!fileExists) { + boolean created = file.createNewFile(); + } + } + + + } From 473d1fd8394405fa20fdc01867bf35e430dbacc5 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sat, 17 Feb 2024 04:09:24 +0800 Subject: [PATCH 043/153] Added Deleting to Storage Class --- src/main/java/Utils/Storage.java | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/src/main/java/Utils/Storage.java b/src/main/java/Utils/Storage.java index 6770123c37..4792e44779 100644 --- a/src/main/java/Utils/Storage.java +++ b/src/main/java/Utils/Storage.java @@ -5,22 +5,46 @@ public class Storage { + static String filepath = "data/"; + static String filename = "storage.txt"; /** * Creates a storage file if it does not exist. - * @throws IOException + * @throws IOException, SecurityException */ public static void createStorage() throws IOException, SecurityException{ - String filepath = "data/dude.txt"; - File file = new File(filepath); + File path = new File(filepath); + //create the directory if it does not exist + if (!path.exists()) { + boolean created = path.mkdirs(); + } + + File file = new File(filepath + filename); boolean fileExists = file.exists(); + //create the file if it does not exist if (!fileExists) { boolean created = file.createNewFile(); } } + /** + * Deletes the storage file if it exists. + * @throws SecurityException + */ + public static void deleteStorage() throws SecurityException{ + File file = new File(filepath + filename); + boolean fileExists = file.exists(); + if (fileExists) { + boolean deleted = file.delete(); + } + } + + + public static void main(String[] args) throws IOException, SecurityException { + + } } From f384ae7c23156b27979700f48853bb6599b4cb32 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sat, 17 Feb 2024 04:16:53 +0800 Subject: [PATCH 044/153] Refactored into Packages --- src/main/java/Dude.java | 7 +++++++ src/main/java/{ => Exceptions}/DudeException.java | 2 ++ .../java/{ => Exceptions}/InvalidArgumentException.java | 4 ++++ .../java/{ => Exceptions}/InvalidCommandException.java | 4 ++++ .../{ => Exceptions}/InvalidDescriptionException.java | 4 ++++ .../java/{ => Exceptions}/InvalidFormatException.java | 6 +++++- .../java/{ => Exceptions}/TaskListFullException.java | 4 ++++ src/main/java/{ => Tasks}/Deadline.java | 9 ++++++++- src/main/java/{ => Tasks}/Event.java | 8 +++++++- src/main/java/{ => Tasks}/Task.java | 2 ++ src/main/java/{ => Tasks}/TaskList.java | 6 +++++- src/main/java/{ => Tasks}/Todo.java | 8 ++++++-- src/main/java/{ => Utils}/utils.java | 2 ++ 13 files changed, 60 insertions(+), 6 deletions(-) rename src/main/java/{ => Exceptions}/DudeException.java (85%) rename src/main/java/{ => Exceptions}/InvalidArgumentException.java (79%) rename src/main/java/{ => Exceptions}/InvalidCommandException.java (78%) rename src/main/java/{ => Exceptions}/InvalidDescriptionException.java (79%) rename src/main/java/{ => Exceptions}/InvalidFormatException.java (53%) rename src/main/java/{ => Exceptions}/TaskListFullException.java (77%) rename src/main/java/{ => Tasks}/Deadline.java (90%) rename src/main/java/{ => Tasks}/Event.java (93%) rename src/main/java/{ => Tasks}/Task.java (97%) rename src/main/java/{ => Tasks}/TaskList.java (97%) rename src/main/java/{ => Tasks}/Todo.java (78%) rename src/main/java/{ => Utils}/utils.java (98%) diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index 41b24c2c43..0d74bccf79 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -1,3 +1,10 @@ +import Exceptions.*; +import Exceptions.TaskListFullException; +import Tasks.Deadline; +import Tasks.Event; +import Tasks.TaskList; +import Tasks.Todo; + import java.util.NoSuchElementException; import java.util.Scanner; diff --git a/src/main/java/DudeException.java b/src/main/java/Exceptions/DudeException.java similarity index 85% rename from src/main/java/DudeException.java rename to src/main/java/Exceptions/DudeException.java index aa946bfcf6..75cbd46164 100644 --- a/src/main/java/DudeException.java +++ b/src/main/java/Exceptions/DudeException.java @@ -1,3 +1,5 @@ +package Exceptions; + public class DudeException extends Exception{ public DudeException(String message) { super(message); diff --git a/src/main/java/InvalidArgumentException.java b/src/main/java/Exceptions/InvalidArgumentException.java similarity index 79% rename from src/main/java/InvalidArgumentException.java rename to src/main/java/Exceptions/InvalidArgumentException.java index d3a3b34b29..4ae96e6e18 100644 --- a/src/main/java/InvalidArgumentException.java +++ b/src/main/java/Exceptions/InvalidArgumentException.java @@ -1,3 +1,7 @@ +package Exceptions; + +import Exceptions.DudeException; + public class InvalidArgumentException extends DudeException { //Used to indicate that an argument for the command is invalid public InvalidArgumentException(String message) { diff --git a/src/main/java/InvalidCommandException.java b/src/main/java/Exceptions/InvalidCommandException.java similarity index 78% rename from src/main/java/InvalidCommandException.java rename to src/main/java/Exceptions/InvalidCommandException.java index 4ba4d2074c..ab9093b7a8 100644 --- a/src/main/java/InvalidCommandException.java +++ b/src/main/java/Exceptions/InvalidCommandException.java @@ -1,3 +1,7 @@ +package Exceptions; + +import Exceptions.DudeException; + public class InvalidCommandException extends DudeException { //Used to indicate that the command is invalid public InvalidCommandException(String message) { diff --git a/src/main/java/InvalidDescriptionException.java b/src/main/java/Exceptions/InvalidDescriptionException.java similarity index 79% rename from src/main/java/InvalidDescriptionException.java rename to src/main/java/Exceptions/InvalidDescriptionException.java index 6da76bb00d..16c720f560 100644 --- a/src/main/java/InvalidDescriptionException.java +++ b/src/main/java/Exceptions/InvalidDescriptionException.java @@ -1,3 +1,7 @@ +package Exceptions; + +import Exceptions.DudeException; + public class InvalidDescriptionException extends DudeException { //Used to indicate that the description is invalid public InvalidDescriptionException(String message) { diff --git a/src/main/java/InvalidFormatException.java b/src/main/java/Exceptions/InvalidFormatException.java similarity index 53% rename from src/main/java/InvalidFormatException.java rename to src/main/java/Exceptions/InvalidFormatException.java index 309850ffe8..039ee37dfa 100644 --- a/src/main/java/InvalidFormatException.java +++ b/src/main/java/Exceptions/InvalidFormatException.java @@ -1,4 +1,8 @@ -public class InvalidFormatException extends DudeException{ +package Exceptions; + +import Exceptions.DudeException; + +public class InvalidFormatException extends DudeException { //Used to indicate that the format is invalid public InvalidFormatException(String message) { super(message); diff --git a/src/main/java/TaskListFullException.java b/src/main/java/Exceptions/TaskListFullException.java similarity index 77% rename from src/main/java/TaskListFullException.java rename to src/main/java/Exceptions/TaskListFullException.java index 520373a9fe..d0dcb5e18e 100644 --- a/src/main/java/TaskListFullException.java +++ b/src/main/java/Exceptions/TaskListFullException.java @@ -1,3 +1,7 @@ +package Exceptions; + +import Exceptions.DudeException; + public class TaskListFullException extends DudeException { //Used to indicate that the task list is full public TaskListFullException(String message) { diff --git a/src/main/java/Deadline.java b/src/main/java/Tasks/Deadline.java similarity index 90% rename from src/main/java/Deadline.java rename to src/main/java/Tasks/Deadline.java index d3605d0811..e9d1aff047 100644 --- a/src/main/java/Deadline.java +++ b/src/main/java/Tasks/Deadline.java @@ -1,4 +1,11 @@ -public class Deadline extends Task{ +package Tasks; + +import Exceptions.InvalidArgumentException; +import Exceptions.InvalidDescriptionException; +import Exceptions.InvalidFormatException; +import Utils.utils; + +public class Deadline extends Task { public static Deadline from(String s) throws InvalidFormatException, InvalidDescriptionException, InvalidArgumentException { //Expects a string in the format "deadline /by " diff --git a/src/main/java/Event.java b/src/main/java/Tasks/Event.java similarity index 93% rename from src/main/java/Event.java rename to src/main/java/Tasks/Event.java index 146344980c..e302128234 100644 --- a/src/main/java/Event.java +++ b/src/main/java/Tasks/Event.java @@ -1,4 +1,10 @@ -public class Event extends Task{ +package Tasks; +import Exceptions.InvalidArgumentException; +import Exceptions.InvalidDescriptionException; +import Exceptions.InvalidFormatException; +import Utils.utils; + +public class Event extends Task { private final String from_time; private final String to_time; diff --git a/src/main/java/Task.java b/src/main/java/Tasks/Task.java similarity index 97% rename from src/main/java/Task.java rename to src/main/java/Tasks/Task.java index 47fc675234..ce3a5c1aea 100644 --- a/src/main/java/Task.java +++ b/src/main/java/Tasks/Task.java @@ -1,3 +1,5 @@ +package Tasks; + public class Task { private final String description; private boolean isDone; diff --git a/src/main/java/TaskList.java b/src/main/java/Tasks/TaskList.java similarity index 97% rename from src/main/java/TaskList.java rename to src/main/java/Tasks/TaskList.java index 56d9d0e703..97181bbed0 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/Tasks/TaskList.java @@ -1,5 +1,9 @@ -import java.awt.*; +package Tasks; + +import Tasks.Task; + import java.util.ArrayList; +import Exceptions.TaskListFullException; public class TaskList { diff --git a/src/main/java/Todo.java b/src/main/java/Tasks/Todo.java similarity index 78% rename from src/main/java/Todo.java rename to src/main/java/Tasks/Todo.java index 6b367aa2c4..36000c680a 100644 --- a/src/main/java/Todo.java +++ b/src/main/java/Tasks/Todo.java @@ -1,6 +1,10 @@ -public class Todo extends Task{ +package Tasks; +import Exceptions.InvalidDescriptionException; +import Utils.utils; - static Todo from(String s) throws InvalidDescriptionException { +public class Todo extends Task { + + public static Todo from(String s) throws InvalidDescriptionException { //Expects a string in the format "todo " //get rid of the command diff --git a/src/main/java/utils.java b/src/main/java/Utils/utils.java similarity index 98% rename from src/main/java/utils.java rename to src/main/java/Utils/utils.java index 38b05f9b34..756320dd0c 100644 --- a/src/main/java/utils.java +++ b/src/main/java/Utils/utils.java @@ -1,3 +1,5 @@ +package Utils; + public class utils { From a22e7d83cb36aa9edfe86caa536fe080f5db8294 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sat, 17 Feb 2024 04:40:32 +0800 Subject: [PATCH 045/153] Added saving taskList functiuonality --- data/tasklist.ser | Bin 0 -> 396 bytes src/main/java/Tasks/Deadline.java | 3 ++ src/main/java/Tasks/Event.java | 8 ++++++ src/main/java/Tasks/Task.java | 4 ++- src/main/java/Tasks/TaskList.java | 20 +++++++++++++ src/main/java/Utils/Storage.java | 46 +++++++++++++++++++++++++++--- 6 files changed, 76 insertions(+), 5 deletions(-) create mode 100644 data/tasklist.ser diff --git a/data/tasklist.ser b/data/tasklist.ser new file mode 100644 index 0000000000000000000000000000000000000000..280a0d048d974cdce5d27936073d54c62bf69416 GIT binary patch literal 396 zcmX|*y-EW?6h?3MPhv=l*a=oCg$>z8h?Ni#Wxzr!5yHeBm(k76I&+P?8U=f6!D7h^ zXlLgGSPFRn-#~l?XWVR>dzm?W=YFq0;3^4g7j#1XYvi%NBPGoVSC~D{H(owzVMA>n z9K~;0mI8oxsx&-IsuQXfk+sEM#$8eUw{kRmG!R=#@0OutcHn%mmE1g6?353)bz#(4bz literal 0 HcmV?d00001 diff --git a/src/main/java/Tasks/Deadline.java b/src/main/java/Tasks/Deadline.java index e9d1aff047..4275308c54 100644 --- a/src/main/java/Tasks/Deadline.java +++ b/src/main/java/Tasks/Deadline.java @@ -67,4 +67,7 @@ public String toString() { return "[D]" + super.toString() + " (by: " + deadline_date + ")"; } + public String getBy() { + return deadline_date; + } } diff --git a/src/main/java/Tasks/Event.java b/src/main/java/Tasks/Event.java index e302128234..06145eb355 100644 --- a/src/main/java/Tasks/Event.java +++ b/src/main/java/Tasks/Event.java @@ -80,4 +80,12 @@ public Event(String description, String from_time, String to_time){ public String toString() { return "[E]" + super.toString() + " (from: " + from_time + " to: " + to_time + ")"; } + + public String getFromTime() { + return from_time; + } + + public String getToTime() { + return to_time; + } } diff --git a/src/main/java/Tasks/Task.java b/src/main/java/Tasks/Task.java index ce3a5c1aea..ccd407b554 100644 --- a/src/main/java/Tasks/Task.java +++ b/src/main/java/Tasks/Task.java @@ -1,6 +1,8 @@ package Tasks; -public class Task { +import java.io.Serializable; + +public class Task implements Serializable { private final String description; private boolean isDone; diff --git a/src/main/java/Tasks/TaskList.java b/src/main/java/Tasks/TaskList.java index 97181bbed0..ee71a0741a 100644 --- a/src/main/java/Tasks/TaskList.java +++ b/src/main/java/Tasks/TaskList.java @@ -73,4 +73,24 @@ public String toString() { return result; } + /** + * Returns a deep copy of the list of tasks + * @return An ArrayList of Task objects + */ + public ArrayList getList() { + ArrayList copy = new ArrayList<>(); + for (Task task : list) { + if (task instanceof Deadline) { + copy.add(new Deadline(task.getDescription(), ((Deadline) task).getBy())); + } else if (task instanceof Event) { + copy.add(new Event(task.getDescription(), ((Event) task).getFromTime(), ((Event) task).getToTime())); + } else if (task instanceof Todo) { + copy.add(new Todo(task.getDescription())); + } else { + copy.add(new Task(task.getDescription())); + } + } + return copy; + } + } diff --git a/src/main/java/Utils/Storage.java b/src/main/java/Utils/Storage.java index 4792e44779..5c2622471d 100644 --- a/src/main/java/Utils/Storage.java +++ b/src/main/java/Utils/Storage.java @@ -1,12 +1,15 @@ package Utils; -import java.io.File; -import java.io.IOException; +import Exceptions.TaskListFullException; +import Tasks.*; + +import java.io.*; +import java.util.ArrayList; public class Storage { static String filepath = "data/"; - static String filename = "storage.txt"; + static String filename = "tasklist.ser"; /** * Creates a storage file if it does not exist. @@ -44,7 +47,42 @@ public static void deleteStorage() throws SecurityException{ } - public static void main(String[] args) throws IOException, SecurityException { + public static void saveTasks(TaskList taskList) throws IOException, SecurityException{ + + try{ + FileOutputStream fos = new FileOutputStream(filepath + filename); + java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(fos); + oos.writeObject(taskList.getList()); + oos.close(); + fos.close(); + } + catch (FileNotFoundException e){ + throw new FileNotFoundException("The file to save the task list was not found."); + } + catch (IOException e){ + throw new IOException("An error occurred while saving the task list."); + } + + } + + + public static void main(String[] args) throws IOException, TaskListFullException, SecurityException { + createStorage(); + + TaskList ls = new TaskList(); + + ls.add_task(new Event("event1", "from1", "to1")); + ls.add_task(new Event("event2", "from2", "to2")); + ls.add_task(new Todo("todo1")); + ls.add_task(new Todo("todo2")); + ls.add_task(new Deadline("deadline1", "by1")); + ls.add_task(new Deadline("deadline2", "by2")); + + System.out.println(ls); + + System.out.println(ls.getList()); + saveTasks(ls); + System.out.println("Saved"); } } From 6e42fffc155f8728cf020426fff950fcb0e0f61f Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sat, 17 Feb 2024 05:02:42 +0800 Subject: [PATCH 046/153] Fixed edge case bug where exception would be thrown if there was an empty tasklist.ser file --- data/tasklist.ser | Bin 396 -> 0 bytes src/main/java/Tasks/TaskList.java | 16 +++++++ src/main/java/Utils/Storage.java | 73 ++++++++++++++++++++++-------- 3 files changed, 70 insertions(+), 19 deletions(-) delete mode 100644 data/tasklist.ser diff --git a/data/tasklist.ser b/data/tasklist.ser deleted file mode 100644 index 280a0d048d974cdce5d27936073d54c62bf69416..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 396 zcmX|*y-EW?6h?3MPhv=l*a=oCg$>z8h?Ni#Wxzr!5yHeBm(k76I&+P?8U=f6!D7h^ zXlLgGSPFRn-#~l?XWVR>dzm?W=YFq0;3^4g7j#1XYvi%NBPGoVSC~D{H(owzVMA>n z9K~;0mI8oxsx&-IsuQXfk+sEM#$8eUw{kRmG!R=#@0OutcHn%mmE1g6?353)bz#(4bz diff --git a/src/main/java/Tasks/TaskList.java b/src/main/java/Tasks/TaskList.java index ee71a0741a..323406b304 100644 --- a/src/main/java/Tasks/TaskList.java +++ b/src/main/java/Tasks/TaskList.java @@ -13,6 +13,12 @@ public TaskList(){ list = new ArrayList<>(); } + public static TaskList from(ArrayList tasks) { + TaskList taskList = new TaskList(); + taskList.list.addAll(tasks); + return taskList; + } + public String add_task(Task task) throws TaskListFullException { if ( list.size() >= 100) { @@ -93,4 +99,14 @@ public ArrayList getList() { return copy; } + public int getSize() { + return list.size(); + } + + public Task getTask(int index) throws IndexOutOfBoundsException{ + if (index < 0 || index >= list.size()) { + throw new IndexOutOfBoundsException("Sorry, the provided id is invalid."); + } + return list.get(index); + } } diff --git a/src/main/java/Utils/Storage.java b/src/main/java/Utils/Storage.java index 5c2622471d..1cd94f38de 100644 --- a/src/main/java/Utils/Storage.java +++ b/src/main/java/Utils/Storage.java @@ -15,7 +15,7 @@ public class Storage { * Creates a storage file if it does not exist. * @throws IOException, SecurityException */ - public static void createStorage() throws IOException, SecurityException{ + private static void createStorageIfNotExists() throws IOException, SecurityException{ File path = new File(filepath); //create the directory if it does not exist @@ -28,10 +28,15 @@ public static void createStorage() throws IOException, SecurityException{ //create the file if it does not exist if (!fileExists) { - boolean created = file.createNewFile(); + FileOutputStream fos = new FileOutputStream(filepath + filename); + java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(fos); + oos.writeObject(new ArrayList()); + oos.close(); + fos.close(); } } + /** * Deletes the storage file if it exists. * @throws SecurityException @@ -64,25 +69,55 @@ public static void saveTasks(TaskList taskList) throws IOException, SecurityExce } } - - - public static void main(String[] args) throws IOException, TaskListFullException, SecurityException { - createStorage(); - TaskList ls = new TaskList(); - - ls.add_task(new Event("event1", "from1", "to1")); - ls.add_task(new Event("event2", "from2", "to2")); - ls.add_task(new Todo("todo1")); - ls.add_task(new Todo("todo2")); - ls.add_task(new Deadline("deadline1", "by1")); - ls.add_task(new Deadline("deadline2", "by2")); - - System.out.println(ls); + /** + * Loads the task list from the storage file. Returns empty task list if no task data is found. + * @return TaskList + * @throws IOException, ClassNotFoundException, SecurityException + */ + @SuppressWarnings("unchecked") //safe as only ArrayList is written to the file + public static TaskList loadTasks() throws IOException, ClassNotFoundException, SecurityException { + createStorageIfNotExists(); + + ArrayList list = new ArrayList<>(); + try { + FileInputStream fis = new FileInputStream(filepath + filename); + ObjectInputStream ois = new ObjectInputStream(fis); + + list = (ArrayList) ois.readObject(); + ois.close(); + fis.close(); + + return TaskList.from(list); + + } catch (FileNotFoundException e) { + throw new FileNotFoundException("The file to load the task list was not found."); + } catch (IOException e) { + throw new IOException("An error occurred while loading the task list."); + } catch (ClassNotFoundException e) { + throw new ClassNotFoundException("The class of the object to be loaded was not found."); + } + } - System.out.println(ls.getList()); - saveTasks(ls); - System.out.println("Saved"); + public static void main(String[] args) throws IOException, TaskListFullException, SecurityException, ClassNotFoundException { + // +// TaskList ls = new TaskList(); +// +// ls.add_task(new Event("event1", "from1", "to1")); +// ls.add_task(new Event("event2", "from2", "to2")); +// ls.add_task(new Todo("todo1")); +// ls.add_task(new Todo("todo2")); +// ls.add_task(new Deadline("deadline1", "by1")); +// ls.add_task(new Deadline("deadline2", "by2")); +// +// System.out.println(ls); +// +// System.out.println(ls.getList()); +// saveTasks(ls); +// System.out.println("Saved"); + + TaskList ls2 = loadTasks(); + System.out.println(ls2); } } From 1d0b813f36944b52aac4ae81074c723347014d53 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sat, 17 Feb 2024 05:07:15 +0800 Subject: [PATCH 047/153] Improved readability --- src/main/java/Utils/Storage.java | 33 +++----------------------------- 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/src/main/java/Utils/Storage.java b/src/main/java/Utils/Storage.java index 1cd94f38de..019e61e671 100644 --- a/src/main/java/Utils/Storage.java +++ b/src/main/java/Utils/Storage.java @@ -26,13 +26,9 @@ private static void createStorageIfNotExists() throws IOException, SecurityExcep File file = new File(filepath + filename); boolean fileExists = file.exists(); - //create the file if it does not exist + //save an empty task list to the file if it does not exist if (!fileExists) { - FileOutputStream fos = new FileOutputStream(filepath + filename); - java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(fos); - oos.writeObject(new ArrayList()); - oos.close(); - fos.close(); + saveTasks(new TaskList()); } } @@ -53,7 +49,6 @@ public static void deleteStorage() throws SecurityException{ public static void saveTasks(TaskList taskList) throws IOException, SecurityException{ - try{ FileOutputStream fos = new FileOutputStream(filepath + filename); java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(fos); @@ -61,13 +56,9 @@ public static void saveTasks(TaskList taskList) throws IOException, SecurityExce oos.close(); fos.close(); } - catch (FileNotFoundException e){ - throw new FileNotFoundException("The file to save the task list was not found."); - } catch (IOException e){ throw new IOException("An error occurred while saving the task list."); } - } /** @@ -89,9 +80,6 @@ public static TaskList loadTasks() throws IOException, ClassNotFoundException, S fis.close(); return TaskList.from(list); - - } catch (FileNotFoundException e) { - throw new FileNotFoundException("The file to load the task list was not found."); } catch (IOException e) { throw new IOException("An error occurred while loading the task list."); } catch (ClassNotFoundException e) { @@ -99,22 +87,7 @@ public static TaskList loadTasks() throws IOException, ClassNotFoundException, S } } - public static void main(String[] args) throws IOException, TaskListFullException, SecurityException, ClassNotFoundException { - // -// TaskList ls = new TaskList(); -// -// ls.add_task(new Event("event1", "from1", "to1")); -// ls.add_task(new Event("event2", "from2", "to2")); -// ls.add_task(new Todo("todo1")); -// ls.add_task(new Todo("todo2")); -// ls.add_task(new Deadline("deadline1", "by1")); -// ls.add_task(new Deadline("deadline2", "by2")); -// -// System.out.println(ls); -// -// System.out.println(ls.getList()); -// saveTasks(ls); -// System.out.println("Saved"); + public static void main(String[] args) throws IOException, SecurityException, ClassNotFoundException { TaskList ls2 = loadTasks(); System.out.println(ls2); From 331f8c8486ba5a467a7095851c893dcffc9ea4ef Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sat, 17 Feb 2024 05:22:05 +0800 Subject: [PATCH 048/153] Implemented Auto save --- src/main/java/Dude.java | 77 +++++++++++++++++++++++++++-------------- 1 file changed, 51 insertions(+), 26 deletions(-) diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index 0d74bccf79..6de2e3e305 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -4,13 +4,14 @@ import Tasks.Event; import Tasks.TaskList; import Tasks.Todo; +import Utils.Storage; import java.util.NoSuchElementException; import java.util.Scanner; public class Dude { - static TaskList taskList = new TaskList(); + private static TaskList taskList = null; static final String[] supported_commands = {"bye", "list", "mark", "unmark", "todo", "event", "deadline", "delete"}; @@ -28,6 +29,16 @@ public static void main(String[] args) { // System.out.println("--------------------------------------"); // System.out.println("Dude v1.0 by Tahsin Hasem.\n"); + + try { + taskList = Storage.loadTasks(); + } + catch (Exception e){ + System.out.println(echo("An error occurred while loading the tasks. Deleting the storage and starting with an empty task list.")); + Storage.deleteStorage(); + taskList = new TaskList(); + } + System.out.println(greet()); // Initialise Scanner to reach command line input @@ -50,32 +61,41 @@ public static void main(String[] args) { continue; } - switch (command){ - case "bye": - System.out.println(bye()); - return; - case "list": - System.out.println(list()); - break; - case "mark": - System.out.println(mark_as_done(msg)); - break; - case "unmark": - System.out.println(mark_as_undone(msg)); - break; - case "todo": - System.out.println(handle_todo_command(msg)); - break; - case "event": - System.out.println(handle_event_command(msg)); - break; - case "deadline": - System.out.println(handle_deadline_command(msg)); - break; - case "delete": - System.out.println(handle_delete_command(msg)); - break; + switch (command) { + case "bye": + System.out.println(bye()); + return; + case "list": + System.out.println(list()); + break; + case "mark": + System.out.println(mark_as_done(msg)); + break; + case "unmark": + System.out.println(mark_as_undone(msg)); + break; + case "todo": + System.out.println(handle_todo_command(msg)); + break; + case "event": + System.out.println(handle_event_command(msg)); + break; + case "deadline": + System.out.println(handle_deadline_command(msg)); + break; + case "delete": + System.out.println(handle_delete_command(msg)); + break; + } + + if (isCommandChangingState(command)) { + try { + Storage.saveTasks(taskList); + } catch (Exception e) { + System.out.println(echo("An error occurred while saving the tasks.")); + } } + } } @@ -208,4 +228,9 @@ private static String get_command(String msg) throws InvalidCommandException { throw new InvalidCommandException("I'm sorry, but I don't know what\n\tthat means :-("); } + private static boolean isCommandChangingState(String command){ + return command.equals("todo") || command.equals("event") || command.equals("deadline") + || command.equals("delete") || command.equals("mark") || command.equals("unmark"); + } + } From 2de57fc580bc758e0965ea8c40adea91f20e2c20 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sat, 17 Feb 2024 05:44:24 +0800 Subject: [PATCH 049/153] Implemented ENUMs for commands --- src/main/java/Dude.java | 63 +++++++++++++++++++------------- src/main/java/Utils/Command.java | 13 +++++++ 2 files changed, 51 insertions(+), 25 deletions(-) create mode 100644 src/main/java/Utils/Command.java diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index 6de2e3e305..07f04e45ca 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -4,6 +4,7 @@ import Tasks.Event; import Tasks.TaskList; import Tasks.Todo; +import Utils.Command; import Utils.Storage; import java.util.NoSuchElementException; @@ -53,39 +54,36 @@ public static void main(String[] args) { break; } - String command = ""; - try { - command = get_command(msg); - }catch (InvalidCommandException e){ - System.out.println(echo(e.getMessage())); - continue; - } + Command command = getCommand(msg); switch (command) { - case "bye": + case BYE: System.out.println(bye()); return; - case "list": + case LIST: System.out.println(list()); break; - case "mark": + case MARK: System.out.println(mark_as_done(msg)); break; - case "unmark": + case UNMARK: System.out.println(mark_as_undone(msg)); break; - case "todo": + case TODO: System.out.println(handle_todo_command(msg)); break; - case "event": + case EVENT: System.out.println(handle_event_command(msg)); break; - case "deadline": + case DEADLINE: System.out.println(handle_deadline_command(msg)); break; - case "delete": + case DELETE: System.out.println(handle_delete_command(msg)); break; + case INVALID: + System.out.println(echo("I'm sorry, but I don't know what that means :-(")); + break; } if (isCommandChangingState(command)) { @@ -217,20 +215,35 @@ private static String handle_delete_command(String msg){ } } - private static String get_command(String msg) throws InvalidCommandException { + private static boolean isCommandChangingState(Command command){ + return command == Command.TODO || command == Command.EVENT || command == Command.DEADLINE + || command == Command.DELETE || command == Command.MARK || command == Command.UNMARK; + } + + private static Command getCommand(String msg) { String cmd = msg.split(" ")[0]; - for (String supported_command : supported_commands) { - if (cmd.equals(supported_command)) { - return cmd; - } + switch(cmd) { + case "bye": + return Command.BYE; + case "list": + return Command.LIST; + case "mark": + return Command.MARK; + case "unmark": + return Command.UNMARK; + case "todo": + return Command.TODO; + case "event": + return Command.EVENT; + case "deadline": + return Command.DEADLINE; + case "delete": + return Command.DELETE; + default: + return Command.INVALID; } - throw new InvalidCommandException("I'm sorry, but I don't know what\n\tthat means :-("); - } - private static boolean isCommandChangingState(String command){ - return command.equals("todo") || command.equals("event") || command.equals("deadline") - || command.equals("delete") || command.equals("mark") || command.equals("unmark"); } } diff --git a/src/main/java/Utils/Command.java b/src/main/java/Utils/Command.java new file mode 100644 index 0000000000..0abc4e2215 --- /dev/null +++ b/src/main/java/Utils/Command.java @@ -0,0 +1,13 @@ +package Utils; + +public enum Command { + BYE, + LIST, + DELETE, + TODO, + DEADLINE, + EVENT, + MARK, + UNMARK, + INVALID +} From 28c57a3434bbb66ff3fcbcb0e2cc2ccfb8285078 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sat, 17 Feb 2024 23:12:05 +0800 Subject: [PATCH 050/153] Added parseDate and fotmatDate functions to Task class --- src/main/java/Tasks/Task.java | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/main/java/Tasks/Task.java b/src/main/java/Tasks/Task.java index ccd407b554..290aa48255 100644 --- a/src/main/java/Tasks/Task.java +++ b/src/main/java/Tasks/Task.java @@ -1,6 +1,10 @@ package Tasks; import java.io.Serializable; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; public class Task implements Serializable { private final String description; @@ -31,4 +35,25 @@ private String getStatusIcon() { public String toString() { return "[" + this.getStatusIcon() + "] " + this.description; } + + private static LocalDateTime parseDate(String string) throws DateTimeParseException { + String dateTimePattern = "\\d{1,2}/\\d{1,2}/\\d{4} \\d{1,2}:\\d{2}"; + String datePattern = "\\d{1,2}/\\d{1,2}/\\d{4}"; + + + if (string.matches(dateTimePattern)) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/yyyy H:m"); + return LocalDateTime.parse(string, formatter); + } else if (string.matches(datePattern)) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/yyyy"); + LocalDate date = LocalDate.parse(string, formatter); + return date.atStartOfDay(); + } else { + throw new DateTimeParseException("Invalid date format. Use d/M/yyyy or d/M/yyy H:m.", string, 0); + } + } + + private static String formatDate(LocalDateTime date) { + return date.format(DateTimeFormatter.ofPattern("d MMM yyyy h:mma")); + } } From aba0281b831a8d47744ce731b0a75f11c2571b55 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sat, 17 Feb 2024 23:19:21 +0800 Subject: [PATCH 051/153] Implemented parsing datetimes for Deadlines --- src/main/java/Tasks/Deadline.java | 18 +++++++++++++----- src/main/java/Tasks/Task.java | 4 ++-- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/main/java/Tasks/Deadline.java b/src/main/java/Tasks/Deadline.java index 4275308c54..372529d64d 100644 --- a/src/main/java/Tasks/Deadline.java +++ b/src/main/java/Tasks/Deadline.java @@ -5,6 +5,9 @@ import Exceptions.InvalidFormatException; import Utils.utils; +import java.time.LocalDateTime; +import java.time.format.DateTimeParseException; + public class Deadline extends Task { public static Deadline from(String s) throws InvalidFormatException, InvalidDescriptionException, InvalidArgumentException { @@ -40,14 +43,19 @@ public static Deadline from(String s) throws InvalidFormatException, InvalidDesc } by = by.trim(); if (by.isEmpty()){ - throw new InvalidArgumentException("The 'by' of a deadline cannot be empty. Follow this format: deadline /by "); + throw new InvalidArgumentException("The 'by' of a deadline cannot be empty. Follow this format: deadline /by "); } - return new Deadline(description, by); + try{ + LocalDateTime dt = parseDate(by); + return new Deadline(description, dt); + }catch (DateTimeParseException e){ + throw new InvalidFormatException("Invalid date format after '/by'. Use d/M/yyyy or d/M/yyy H:m."); + } } - private final String deadline_date; - public Deadline(String description, String by) { + private final LocalDateTime deadline_date; + public Deadline(String description, LocalDateTime by) { super(description); this.deadline_date = by; } @@ -67,7 +75,7 @@ public String toString() { return "[D]" + super.toString() + " (by: " + deadline_date + ")"; } - public String getBy() { + public LocalDateTime getBy() { return deadline_date; } } diff --git a/src/main/java/Tasks/Task.java b/src/main/java/Tasks/Task.java index 290aa48255..6e8710eff1 100644 --- a/src/main/java/Tasks/Task.java +++ b/src/main/java/Tasks/Task.java @@ -36,7 +36,7 @@ public String toString() { return "[" + this.getStatusIcon() + "] " + this.description; } - private static LocalDateTime parseDate(String string) throws DateTimeParseException { + protected static LocalDateTime parseDate(String string) throws DateTimeParseException { String dateTimePattern = "\\d{1,2}/\\d{1,2}/\\d{4} \\d{1,2}:\\d{2}"; String datePattern = "\\d{1,2}/\\d{1,2}/\\d{4}"; @@ -53,7 +53,7 @@ private static LocalDateTime parseDate(String string) throws DateTimeParseExcept } } - private static String formatDate(LocalDateTime date) { + protected static String formatDate(LocalDateTime date) { return date.format(DateTimeFormatter.ofPattern("d MMM yyyy h:mma")); } } From 83ff4fe8d41facf9eae148d02785dd7d2acffa89 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sat, 17 Feb 2024 23:26:38 +0800 Subject: [PATCH 052/153] implemented date formatting for deadlines --- src/main/java/Tasks/Deadline.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/Tasks/Deadline.java b/src/main/java/Tasks/Deadline.java index 372529d64d..400c6f5573 100644 --- a/src/main/java/Tasks/Deadline.java +++ b/src/main/java/Tasks/Deadline.java @@ -50,7 +50,7 @@ public static Deadline from(String s) throws InvalidFormatException, InvalidDesc LocalDateTime dt = parseDate(by); return new Deadline(description, dt); }catch (DateTimeParseException e){ - throw new InvalidFormatException("Invalid date format after '/by'. Use d/M/yyyy or d/M/yyy H:m."); + throw new InvalidFormatException("Invalid date format after '/by'. Use d/M/yyyy or d/M/yyy H:m in 24-hour format"); } } @@ -72,7 +72,7 @@ public void markAsUndone() { @Override public String toString() { - return "[D]" + super.toString() + " (by: " + deadline_date + ")"; + return "[D]" + super.toString() + " (by: " + formatDate(deadline_date) + ")"; } public LocalDateTime getBy() { From ee7624b0a886b540e63020b93b2f4f4b37d66890 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sat, 17 Feb 2024 23:30:11 +0800 Subject: [PATCH 053/153] Implemented DateTime parsing for Events --- src/main/java/Tasks/Event.java | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/main/java/Tasks/Event.java b/src/main/java/Tasks/Event.java index 06145eb355..5be6262421 100644 --- a/src/main/java/Tasks/Event.java +++ b/src/main/java/Tasks/Event.java @@ -4,10 +4,13 @@ import Exceptions.InvalidFormatException; import Utils.utils; +import java.time.LocalDateTime; +import java.time.format.DateTimeParseException; + public class Event extends Task { - private final String from_time; - private final String to_time; + private final LocalDateTime from_time; + private final LocalDateTime to_time; public static Event from(String s) throws InvalidArgumentException, InvalidFormatException, InvalidDescriptionException { @@ -67,10 +70,16 @@ public static Event from(String s) throws InvalidArgumentException, InvalidForma throw new InvalidArgumentException("The 'to_time' of an event cannot be empty."); } - return new Event(description, from_time, to_time); + try { + LocalDateTime from = parseDate(from_time); + LocalDateTime to = parseDate(to_time); + return new Event(description, from, to); + } catch (DateTimeParseException e) { + throw new InvalidFormatException("Invalid date format after '/from' or '/to'. Use d/M/yyyy or d/M/yyy H:m in 24-hour format"); + } } - public Event(String description, String from_time, String to_time){ + public Event(String description, LocalDateTime from_time, LocalDateTime to_time) { super(description); this.from_time = from_time; this.to_time = to_time; @@ -81,11 +90,11 @@ public String toString() { return "[E]" + super.toString() + " (from: " + from_time + " to: " + to_time + ")"; } - public String getFromTime() { + public LocalDateTime getFromTime() { return from_time; } - public String getToTime() { + public LocalDateTime getToTime() { return to_time; } } From 37721761559cbd17480371f00c6318809efe9d7b Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sat, 17 Feb 2024 23:31:54 +0800 Subject: [PATCH 054/153] Implemented formatting of dates for Events --- src/main/java/Tasks/Event.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/Tasks/Event.java b/src/main/java/Tasks/Event.java index 5be6262421..63edac5c4e 100644 --- a/src/main/java/Tasks/Event.java +++ b/src/main/java/Tasks/Event.java @@ -87,7 +87,7 @@ public Event(String description, LocalDateTime from_time, LocalDateTime to_time) @Override public String toString() { - return "[E]" + super.toString() + " (from: " + from_time + " to: " + to_time + ")"; + return "[E]" + super.toString() + " (from: " + formatDate(from_time) + " to: " + formatDate(to_time) + ")"; } public LocalDateTime getFromTime() { From 27a0db5e724288e95616189b40e7e3a4cb0902c3 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sat, 17 Feb 2024 23:33:54 +0800 Subject: [PATCH 055/153] Changed printing of time format to `MMM d, yyyy @ h:mma` --- src/main/java/Tasks/Task.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/Tasks/Task.java b/src/main/java/Tasks/Task.java index 6e8710eff1..59392f0291 100644 --- a/src/main/java/Tasks/Task.java +++ b/src/main/java/Tasks/Task.java @@ -54,6 +54,6 @@ protected static LocalDateTime parseDate(String string) throws DateTimeParseExce } protected static String formatDate(LocalDateTime date) { - return date.format(DateTimeFormatter.ofPattern("d MMM yyyy h:mma")); + return date.format(DateTimeFormatter.ofPattern("MMM d, yyyy @ h:mma")); } } From f88ca27f0b891a695da7cedb166b87f53388663b Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 18 Feb 2024 02:06:24 +0800 Subject: [PATCH 056/153] Changed Storage to take in save file location. Make it more OOP --- src/main/java/Dude.java | 7 +++--- src/main/java/Utils/Storage.java | 43 ++++++++++++++++++++++++-------- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index 07f04e45ca..c558362b2c 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -13,6 +13,7 @@ public class Dude { private static TaskList taskList = null; + private static Storage storage = new Storage("data/tasklist.ser"); static final String[] supported_commands = {"bye", "list", "mark", "unmark", "todo", "event", "deadline", "delete"}; @@ -32,11 +33,11 @@ public static void main(String[] args) { try { - taskList = Storage.loadTasks(); + taskList = storage.loadTasks(); } catch (Exception e){ System.out.println(echo("An error occurred while loading the tasks. Deleting the storage and starting with an empty task list.")); - Storage.deleteStorage(); + storage.deleteStorage(); taskList = new TaskList(); } @@ -88,7 +89,7 @@ public static void main(String[] args) { if (isCommandChangingState(command)) { try { - Storage.saveTasks(taskList); + storage.saveTasks(taskList); } catch (Exception e) { System.out.println(echo("An error occurred while saving the tasks.")); } diff --git a/src/main/java/Utils/Storage.java b/src/main/java/Utils/Storage.java index 019e61e671..c37536a78e 100644 --- a/src/main/java/Utils/Storage.java +++ b/src/main/java/Utils/Storage.java @@ -8,22 +8,28 @@ public class Storage { - static String filepath = "data/"; - static String filename = "tasklist.ser"; + private final String filepath; + private final String filename; + + public Storage(String fileLocation) { + + this.filepath = extractFilePath(fileLocation); + this.filename = extractFileName(fileLocation); + } /** * Creates a storage file if it does not exist. * @throws IOException, SecurityException */ - private static void createStorageIfNotExists() throws IOException, SecurityException{ - File path = new File(filepath); + private void createStorageIfNotExists() throws IOException, SecurityException { + File path = new File(this.filepath); //create the directory if it does not exist if (!path.exists()) { boolean created = path.mkdirs(); } - File file = new File(filepath + filename); + File file = new File(this.filepath + this.filename); boolean fileExists = file.exists(); //save an empty task list to the file if it does not exist @@ -37,8 +43,8 @@ private static void createStorageIfNotExists() throws IOException, SecurityExcep * Deletes the storage file if it exists. * @throws SecurityException */ - public static void deleteStorage() throws SecurityException{ - File file = new File(filepath + filename); + public void deleteStorage() throws SecurityException { + File file = new File(this.filepath + this.filename); boolean fileExists = file.exists(); @@ -48,7 +54,7 @@ public static void deleteStorage() throws SecurityException{ } - public static void saveTasks(TaskList taskList) throws IOException, SecurityException{ + public void saveTasks(TaskList taskList) throws IOException, SecurityException { try{ FileOutputStream fos = new FileOutputStream(filepath + filename); java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(fos); @@ -67,7 +73,7 @@ public static void saveTasks(TaskList taskList) throws IOException, SecurityExce * @throws IOException, ClassNotFoundException, SecurityException */ @SuppressWarnings("unchecked") //safe as only ArrayList is written to the file - public static TaskList loadTasks() throws IOException, ClassNotFoundException, SecurityException { + public TaskList loadTasks() throws IOException, ClassNotFoundException, SecurityException { createStorageIfNotExists(); ArrayList list = new ArrayList<>(); @@ -89,8 +95,25 @@ public static TaskList loadTasks() throws IOException, ClassNotFoundException, S public static void main(String[] args) throws IOException, SecurityException, ClassNotFoundException { - TaskList ls2 = loadTasks(); + Storage s = new Storage("data/tasks.ser"); + TaskList ls2 = s.loadTasks(); System.out.println(ls2); } + + private String extractFilePath(String fileLocation) { + String f = fileLocation.trim(); + String[] parts = f.split("/"); + String path = ""; + for (int i = 0; i < parts.length - 1; i++) { + path += parts[i] + "/"; + } + return path; + } + + private String extractFileName(String fileLocation) { + String f = fileLocation.trim(); + String[] parts = f.split("/"); + return parts[parts.length - 1]; + } } From 33a746fd8518ec5ca33e5d0989bcf3655efe4643 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 18 Feb 2024 02:11:38 +0800 Subject: [PATCH 057/153] removed main method from storage --- src/main/java/Utils/Storage.java | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/main/java/Utils/Storage.java b/src/main/java/Utils/Storage.java index c37536a78e..ae0f95fba1 100644 --- a/src/main/java/Utils/Storage.java +++ b/src/main/java/Utils/Storage.java @@ -1,8 +1,6 @@ package Utils; -import Exceptions.TaskListFullException; import Tasks.*; - import java.io.*; import java.util.ArrayList; @@ -56,7 +54,7 @@ public void deleteStorage() throws SecurityException { public void saveTasks(TaskList taskList) throws IOException, SecurityException { try{ - FileOutputStream fos = new FileOutputStream(filepath + filename); + FileOutputStream fos = new FileOutputStream(this.filepath + this.filename); java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(fos); oos.writeObject(taskList.getList()); oos.close(); @@ -78,7 +76,7 @@ public TaskList loadTasks() throws IOException, ClassNotFoundException, Security ArrayList list = new ArrayList<>(); try { - FileInputStream fis = new FileInputStream(filepath + filename); + FileInputStream fis = new FileInputStream(this.filepath + this.filename); ObjectInputStream ois = new ObjectInputStream(fis); list = (ArrayList) ois.readObject(); @@ -93,14 +91,6 @@ public TaskList loadTasks() throws IOException, ClassNotFoundException, Security } } - public static void main(String[] args) throws IOException, SecurityException, ClassNotFoundException { - - Storage s = new Storage("data/tasks.ser"); - TaskList ls2 = s.loadTasks(); - System.out.println(ls2); - - } - private String extractFilePath(String fileLocation) { String f = fileLocation.trim(); String[] parts = f.split("/"); From e4c2d2f1315445f89d99e36b281a56097e771ba6 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 18 Feb 2024 02:25:07 +0800 Subject: [PATCH 058/153] added skeleton for command package --- src/main/java/Commands/ByeCommand.java | 4 +++ src/main/java/Commands/Command.java | 23 ++++++++++++++ src/main/java/Commands/CommandParser.java | 31 +++++++++++++++++++ src/main/java/Dude.java | 31 +++++++++---------- .../Utils/{Command.java => CommandTypes.java} | 2 +- src/main/java/Utils/Ui.java | 20 ++++++++++++ 6 files changed, 94 insertions(+), 17 deletions(-) create mode 100644 src/main/java/Commands/ByeCommand.java create mode 100644 src/main/java/Commands/Command.java create mode 100644 src/main/java/Commands/CommandParser.java rename src/main/java/Utils/{Command.java => CommandTypes.java} (81%) create mode 100644 src/main/java/Utils/Ui.java diff --git a/src/main/java/Commands/ByeCommand.java b/src/main/java/Commands/ByeCommand.java new file mode 100644 index 0000000000..cffc514b24 --- /dev/null +++ b/src/main/java/Commands/ByeCommand.java @@ -0,0 +1,4 @@ +package Commands; + +public class ByeCommand { +} diff --git a/src/main/java/Commands/Command.java b/src/main/java/Commands/Command.java new file mode 100644 index 0000000000..df2868786b --- /dev/null +++ b/src/main/java/Commands/Command.java @@ -0,0 +1,23 @@ +package Commands; + +public abstract class Command { + + private final String format; + private final String regex; + + protected Command(String format, String regex) { + this.format = format; + this.regex = regex; + } + + public abstract String execute(); + + public String getFormat() { + return this.format; + } + + public String getRegex() { + return this.regex; + } + +} diff --git a/src/main/java/Commands/CommandParser.java b/src/main/java/Commands/CommandParser.java new file mode 100644 index 0000000000..7e532e593c --- /dev/null +++ b/src/main/java/Commands/CommandParser.java @@ -0,0 +1,31 @@ +package Commands; + +public class CommandParser { + + + public static parseCommand(String input) { + String[] command = input.split(" ", 2); + switch (command[0]) { + case "bye": + return new ByeCommand(); + case "list": + return new ListCommand(); + case "delete": + return new DeleteCommand(command[1]); + case "todo": + return new TodoCommand(command[1]); + case "deadline": + return new DeadlineCommand(command[1]); + case "event": + return new EventCommand(command[1]); + case "mark": + return new MarkCommand(command[1]); + case "unmark": + return new UnmarkCommand(command[1]); + default: + return new InvalidCommand(); + } + } + + +} diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index c558362b2c..a6ac2457f4 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -4,7 +4,7 @@ import Tasks.Event; import Tasks.TaskList; import Tasks.Todo; -import Utils.Command; +import Utils.CommandTypes; import Utils.Storage; import java.util.NoSuchElementException; @@ -55,7 +55,7 @@ public static void main(String[] args) { break; } - Command command = getCommand(msg); + CommandTypes command = getCommand(msg); switch (command) { case BYE: @@ -110,7 +110,6 @@ private static String list(){ return taskList.toString(); } - private static String bye(){ String bye_msg = "\t-----------------------------------"; bye_msg += "\n\tBye. Hope to see you again soon!"; @@ -216,33 +215,33 @@ private static String handle_delete_command(String msg){ } } - private static boolean isCommandChangingState(Command command){ - return command == Command.TODO || command == Command.EVENT || command == Command.DEADLINE - || command == Command.DELETE || command == Command.MARK || command == Command.UNMARK; + private static boolean isCommandChangingState(CommandTypes command) { + return command == CommandTypes.TODO || command == CommandTypes.EVENT || command == CommandTypes.DEADLINE + || command == CommandTypes.DELETE || command == CommandTypes.MARK || command == CommandTypes.UNMARK; } - private static Command getCommand(String msg) { + private static CommandTypes getCommand(String msg) { String cmd = msg.split(" ")[0]; switch(cmd) { case "bye": - return Command.BYE; + return CommandTypes.BYE; case "list": - return Command.LIST; + return CommandTypes.LIST; case "mark": - return Command.MARK; + return CommandTypes.MARK; case "unmark": - return Command.UNMARK; + return CommandTypes.UNMARK; case "todo": - return Command.TODO; + return CommandTypes.TODO; case "event": - return Command.EVENT; + return CommandTypes.EVENT; case "deadline": - return Command.DEADLINE; + return CommandTypes.DEADLINE; case "delete": - return Command.DELETE; + return CommandTypes.DELETE; default: - return Command.INVALID; + return CommandTypes.INVALID; } } diff --git a/src/main/java/Utils/Command.java b/src/main/java/Utils/CommandTypes.java similarity index 81% rename from src/main/java/Utils/Command.java rename to src/main/java/Utils/CommandTypes.java index 0abc4e2215..3f466c0b75 100644 --- a/src/main/java/Utils/Command.java +++ b/src/main/java/Utils/CommandTypes.java @@ -1,6 +1,6 @@ package Utils; -public enum Command { +public enum CommandTypes { BYE, LIST, DELETE, diff --git a/src/main/java/Utils/Ui.java b/src/main/java/Utils/Ui.java new file mode 100644 index 0000000000..37c038875d --- /dev/null +++ b/src/main/java/Utils/Ui.java @@ -0,0 +1,20 @@ +package Utils; + +public class Ui { + + + public void showWelcome() { + String msg = "\t-----------------------------------\n" + + "\tHello! I'm Dude\n" + + "\tWhat can I do for you?\n" + + "\t-----------------------------------\n"; + System.out.println(msg); + } + + public void showMessage(String msg) { + msg = "\t-----------------------------------\n" + + "\t" + msg + "\n" + + "\t-----------------------------------"; + System.out.println(msg); + } +} From 815d1c764ddbce09f3cfef7add776bdccee159f2 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 18 Feb 2024 04:03:09 +0800 Subject: [PATCH 059/153] Added Commands --- src/main/java/Commands/ByeCommand.java | 10 ++- src/main/java/Commands/Command.java | 4 +- src/main/java/Commands/CommandParser.java | 23 +++-- src/main/java/Commands/DeadlineCommand.java | 32 +++++++ src/main/java/Commands/DeleteCommand.java | 42 +++++++++ src/main/java/Commands/EventCommand.java | 34 +++++++ src/main/java/Commands/HelpCommand.java | 98 +++++++++++++++++++++ src/main/java/Commands/InvalidCommand.java | 13 +++ src/main/java/Commands/ListCommand.java | 17 ++++ src/main/java/Commands/MarkCommand.java | 40 +++++++++ src/main/java/Commands/TodoCommand.java | 33 +++++++ src/main/java/Commands/UnmarkCommand.java | 40 +++++++++ src/main/java/Dude.java | 18 +--- src/main/java/Tasks/TaskList.java | 14 +-- 14 files changed, 387 insertions(+), 31 deletions(-) create mode 100644 src/main/java/Commands/DeadlineCommand.java create mode 100644 src/main/java/Commands/DeleteCommand.java create mode 100644 src/main/java/Commands/EventCommand.java create mode 100644 src/main/java/Commands/HelpCommand.java create mode 100644 src/main/java/Commands/InvalidCommand.java create mode 100644 src/main/java/Commands/ListCommand.java create mode 100644 src/main/java/Commands/MarkCommand.java create mode 100644 src/main/java/Commands/TodoCommand.java create mode 100644 src/main/java/Commands/UnmarkCommand.java diff --git a/src/main/java/Commands/ByeCommand.java b/src/main/java/Commands/ByeCommand.java index cffc514b24..70d36a551c 100644 --- a/src/main/java/Commands/ByeCommand.java +++ b/src/main/java/Commands/ByeCommand.java @@ -1,4 +1,12 @@ package Commands; -public class ByeCommand { +public class ByeCommand extends Command { + + public ByeCommand() { + super("bye", "bye"); + } + + public String execute() { + return "Bye. Hope to see you again soon!"; + } } diff --git a/src/main/java/Commands/Command.java b/src/main/java/Commands/Command.java index df2868786b..6148314a84 100644 --- a/src/main/java/Commands/Command.java +++ b/src/main/java/Commands/Command.java @@ -1,5 +1,7 @@ package Commands; +import Exceptions.DudeException; + public abstract class Command { private final String format; @@ -10,7 +12,7 @@ protected Command(String format, String regex) { this.regex = regex; } - public abstract String execute(); + public abstract String execute() throws DudeException; public String getFormat() { return this.format; diff --git a/src/main/java/Commands/CommandParser.java b/src/main/java/Commands/CommandParser.java index 7e532e593c..2a4bb740b8 100644 --- a/src/main/java/Commands/CommandParser.java +++ b/src/main/java/Commands/CommandParser.java @@ -1,27 +1,32 @@ package Commands; -public class CommandParser { +import Exceptions.DudeException; +import Tasks.TaskList; +import Utils.Storage; +public class CommandParser { - public static parseCommand(String input) { + public static Command parseCommand(String input, TaskList tasklist) throws DudeException { String[] command = input.split(" ", 2); switch (command[0]) { case "bye": return new ByeCommand(); case "list": - return new ListCommand(); + return new ListCommand(tasklist); case "delete": - return new DeleteCommand(command[1]); + return new DeleteCommand(input, tasklist); case "todo": - return new TodoCommand(command[1]); + return new TodoCommand(input, tasklist); case "deadline": - return new DeadlineCommand(command[1]); + return new DeadlineCommand(input, tasklist); case "event": - return new EventCommand(command[1]); + return new EventCommand(input, tasklist); case "mark": - return new MarkCommand(command[1]); + return new MarkCommand(input, tasklist); case "unmark": - return new UnmarkCommand(command[1]); + return new UnmarkCommand(input, tasklist); + case "help": + return new HelpCommand(input); default: return new InvalidCommand(); } diff --git a/src/main/java/Commands/DeadlineCommand.java b/src/main/java/Commands/DeadlineCommand.java new file mode 100644 index 0000000000..a1594875ce --- /dev/null +++ b/src/main/java/Commands/DeadlineCommand.java @@ -0,0 +1,32 @@ +package Commands; + +import Exceptions.DudeException; +import Exceptions.InvalidFormatException; +import Tasks.Deadline; +import Tasks.TaskList; + +public class DeadlineCommand extends Command { + private final String input; + private final TaskList taskList; + + public DeadlineCommand(String input, TaskList tasklist) { + super("deadline /by ", "deadline .* /by .*"); + this.input = input; + this.taskList = tasklist; + } + + public String execute() throws DudeException { + boolean doesInputMatch = input.matches(this.getRegex()); + + //only catches basic format errors. date format errors are caught by Deadline.from() + if (!doesInputMatch) { + throw new InvalidFormatException("Invalid format for deadline command. Please use this format: " + this.getFormat()); + } + + Deadline deadline = Deadline.from(input); //throws different DukeExceptions + this.taskList.add_task(deadline); //throws TaskListFullException + return "Got it. I've added this task:\n" + + "\t " + deadline.toString() + "\n" + + "\tNow you have " + this.taskList.getSize() + " tasks in the list."; + } +} diff --git a/src/main/java/Commands/DeleteCommand.java b/src/main/java/Commands/DeleteCommand.java new file mode 100644 index 0000000000..4316c362fe --- /dev/null +++ b/src/main/java/Commands/DeleteCommand.java @@ -0,0 +1,42 @@ +package Commands; + +import Exceptions.DudeException; +import Exceptions.InvalidCommandIDException; +import Exceptions.InvalidFormatException; +import Tasks.TaskList; + +public class DeleteCommand extends Command { + private final String input; + private final TaskList taskList; + + public DeleteCommand(String input, TaskList tasklist) { + super("delete ", "delete \\d+"); + this.input = input.trim(); + this.taskList = tasklist; + } + + public String execute() throws DudeException { + boolean inputMatches = input.matches(this.getRegex()); + + //throw error if input does not match the format + if (!inputMatches) { + throw new InvalidFormatException("Invalid format for delete command. PLease use this format: " + this.getFormat()); + } + + int index = Integer.parseInt(this.input.split(" ")[1]); + + //re-throw exception if task does not exist + try { + this.taskList.remove_task(index); + + String msg = "Noted. I've removed this task:\n" + + "\t " + index + ". " + this.taskList.getTask(index - 1).toString() + "\n" + + "\tNow you have " + this.taskList.getSize() + " tasks in the list."; + + return msg; + } catch (DudeException e) { + throw new DudeException(e.getMessage()); + } + + } +} diff --git a/src/main/java/Commands/EventCommand.java b/src/main/java/Commands/EventCommand.java new file mode 100644 index 0000000000..3401042235 --- /dev/null +++ b/src/main/java/Commands/EventCommand.java @@ -0,0 +1,34 @@ +package Commands; + +import Exceptions.DudeException; +import Exceptions.InvalidFormatException; +import Tasks.Deadline; +import Tasks.Event; +import Tasks.TaskList; + +public class EventCommand extends Command { + private final String input; + private final TaskList taskList; + + public EventCommand(String input, TaskList tasklist) { + super("event /from /to ", "event .* /from .* /to .*"); + this.input = input; + this.taskList = tasklist; + } + + public String execute() throws DudeException { + boolean doesInputMatch = input.matches(this.getRegex()); + + //only catches basic format errors. date format errors are caught by Deadline.from() + if (!doesInputMatch) { + throw new InvalidFormatException("Invalid format for deadline command. Please use this format: " + this.getFormat()); + } + + Event event = Event.from(input); //throws different DukeExceptions + this.taskList.add_task(event); //throws TaskListFullException + return "Got it. I've added this task:\n" + + "\t " + event.toString() + "\n" + + "\tNow you have " + this.taskList.getSize() + " tasks in the list."; + } + +} diff --git a/src/main/java/Commands/HelpCommand.java b/src/main/java/Commands/HelpCommand.java new file mode 100644 index 0000000000..7f9a3db79b --- /dev/null +++ b/src/main/java/Commands/HelpCommand.java @@ -0,0 +1,98 @@ +package Commands; + +import Exceptions.DudeException; + +public class HelpCommand extends Command { + + private final String[] supportedCommands = new String[]{ + "list: Lists all the tasks in the task list.", + "todo: Adds a todo task to the task list.", + "deadline: Adds a deadline task to the task list.", + "event: Adds an event task to the task list.", + "mark: Marks a task as done.", + "unmark: Marks a task as undone.", + "delete: Deletes a task from the task list.", + "bye: Exits the program.", + "help: Provides help on the commands I support." + }; + + private final String input; + + public HelpCommand(String input) { + super("help ", "help"); + this.input = input.trim(); + } + + public String execute() throws DudeException { + if (input.equals("help")) { + return this.generateHelpMessage(); + } else { + return this.generateCommandHelpMessage(); + } + } + + private String generateHelpMessage() { + String helpMessage = "Here are the commands I support:\n"; + for (String command : supportedCommands) { + helpMessage += "\t" + command + "\n"; + } + helpMessage += "For more information on a specific command, type 'help '"; + return helpMessage; + } + + + private String generateCommandHelpMessage() { + String[] parts = input.split(" ", 2); + + //the length must be two, as the string is not equals to "help". + String command = parts[1]; + + switch (command) { + case "list": + return "list: Lists all the tasks in the task list." + + "\n\tFormat: list" + + "\n\tExample: list"; + case "todo": + return "todo: Adds a todo task to the task list." + + "\n\tFormat: todo " + + "\n\tExample: todo read book" + + "\n\tNote: The description cannot be empty."; + case "deadline": + return "deadline: Adds a deadline task to the task list." + + "\n\tFormat: deadline /by " + + "\n\tExample: deadline return book /by 09/09/2021 18:00" + + "\n\tExample (2): deadline get book /by 09/09/2021" + + "\n\t*Note: The description and date cannot be empty." + + "\n\t*Note: The date must be in the format d/M/yyyy H:m or d/M/yyyy"; + case "event": + return "event: Adds an event task to the task list." + + "\n\tFormat: event /from /to " + + "\n\tExample: event project meeting /from 09/09/2021 18:00 /to 09/09/2021 20:00" + + "\n\tExample (2): event project meeting /from 09/09/2021 /to 09/09/2021" + + "\n\t*Note: The description and date cannot be empty." + + "\n\t*Note: The date must be in the format d/M/yyyy H:m or d/M/yyyy"; + case "mark": + return "mark: Marks a task as done." + + "\n\tFormat: mark " + + "\n\tExample: mark 1" + + "\n\t*Note: The id must be a valid integer task id."; + case "unmark": + return "unmark: Marks a task as undone." + + "\n\tFormat: unmark " + + "\n\tExample: unmark 1" + + "\n\t*Note: The id must be a valid integer task id."; + case "delete": + return "delete: Deletes a task from the task list." + + "\n\tFormat: delete " + + "\n\tExample: delete 1" + + "\n\t*Note: The id must be a valid integer task id."; + case "bye": + return "bye: Exits the program." + + "\n\tFormat: bye" + + "\n\tExample: bye"; + } + + return "I'm sorry, I don't know what that command is. Please type 'help' to see the list of commands I support."; + } + +} diff --git a/src/main/java/Commands/InvalidCommand.java b/src/main/java/Commands/InvalidCommand.java new file mode 100644 index 0000000000..25bdf2daf8 --- /dev/null +++ b/src/main/java/Commands/InvalidCommand.java @@ -0,0 +1,13 @@ +package Commands; + +public class InvalidCommand extends Command { + + public InvalidCommand() { + super("", ""); + } + + public String execute() { + return "Sorry I don't understand that command. Please try again."; + } + +} diff --git a/src/main/java/Commands/ListCommand.java b/src/main/java/Commands/ListCommand.java new file mode 100644 index 0000000000..25fbe54f0b --- /dev/null +++ b/src/main/java/Commands/ListCommand.java @@ -0,0 +1,17 @@ +package Commands; + +import Tasks.TaskList; + +public class ListCommand extends Command { + + private final TaskList tasklist; + + public ListCommand(TaskList tasklist) { + super("list", "list"); + this.tasklist = tasklist; + } + + public String execute() { + return tasklist.toString(); + } +} diff --git a/src/main/java/Commands/MarkCommand.java b/src/main/java/Commands/MarkCommand.java new file mode 100644 index 0000000000..48fa52c16b --- /dev/null +++ b/src/main/java/Commands/MarkCommand.java @@ -0,0 +1,40 @@ +package Commands; + +import Exceptions.DudeException; +import Exceptions.InvalidFormatException; +import Tasks.TaskList; + +public class MarkCommand extends Command { + private final String input; + private final TaskList taskList; + + public MarkCommand(String input, TaskList tasklist) { + super("mark ", "mark \\d+"); + this.input = input.trim(); + this.taskList = tasklist; + } + + @Override + public String execute() throws DudeException { + boolean inputMatches = input.matches(this.getRegex()); + + //throw error if input does not match the format + if (!inputMatches) { + throw new InvalidFormatException("Invalid format for mark command. Please use this format: " + this.getFormat()); + } + + int index = Integer.parseInt(this.input.split(" ")[1]); + + //re-thow exception if task does not exist + try { + this.taskList.mark_as_done(index); + + String msg = "Nice! I've marked this task as done:\n" + + "\t " + index + ". " + this.taskList.getTask(index - 1).toString(); + + return msg; + } catch (DudeException e) { + throw new DudeException(e.getMessage()); + } + } +} diff --git a/src/main/java/Commands/TodoCommand.java b/src/main/java/Commands/TodoCommand.java new file mode 100644 index 0000000000..1777f2b6c0 --- /dev/null +++ b/src/main/java/Commands/TodoCommand.java @@ -0,0 +1,33 @@ +package Commands; + +import Exceptions.DudeException; +import Exceptions.InvalidDescriptionException; +import Exceptions.InvalidFormatException; +import Exceptions.TaskListFullException; +import Tasks.TaskList; +import Tasks.Todo; + +public class TodoCommand extends Command { + private final String input; + private final TaskList taskList; + + public TodoCommand(String input, TaskList tasklist) { + super("todo ", "todo .*"); + this.input = input; + this.taskList = tasklist; + } + + public String execute() throws DudeException { + boolean doesInputMatch = input.matches(this.getRegex()); + + if (!doesInputMatch) { + throw new InvalidFormatException("Invalid format for todo command. Please use this format: " + this.getFormat()); + } + + Todo todo = Todo.from(input); //throws InvalidDescriptionException + this.taskList.add_task(todo); //throws TaskListFullException + return "Got it. I've added this task:\n" + + "\t " + todo.toString() + "\n" + + "\tNow you have " + this.taskList.getSize() + " tasks in the list."; + } +} diff --git a/src/main/java/Commands/UnmarkCommand.java b/src/main/java/Commands/UnmarkCommand.java new file mode 100644 index 0000000000..c989722809 --- /dev/null +++ b/src/main/java/Commands/UnmarkCommand.java @@ -0,0 +1,40 @@ +package Commands; + +import Exceptions.DudeException; +import Exceptions.InvalidFormatException; +import Tasks.TaskList; + +public class UnmarkCommand extends Command { + private final String input; + private final TaskList taskList; + + public UnmarkCommand(String input, TaskList tasklist) { + super("mark ", "unmark \\d+"); + this.input = input.trim(); + this.taskList = tasklist; + } + + @Override + public String execute() throws DudeException { + boolean inputMatches = input.matches(this.getRegex()); + + //throw error if input does not match the format + if (!inputMatches) { + throw new InvalidFormatException("Invalid format for mark command. Please use this format: " + this.getFormat()); + } + + int index = Integer.parseInt(this.input.split(" ")[1]); + + //re-throw exception if task does not exist + try { + this.taskList.mark_as_undone(index); + + String msg = "Nice! I've unmarked this task as done:\n" + + "\t " + index + ". " + this.taskList.getTask(index - 1).toString(); + + return msg; + } catch (DudeException e) { + throw new DudeException(e.getMessage()); + } + } +} diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index a6ac2457f4..894d7eed08 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -1,3 +1,4 @@ +import Commands.DeleteCommand; import Exceptions.*; import Exceptions.TaskListFullException; import Tasks.Deadline; @@ -197,21 +198,10 @@ private static String handle_deadline_command(String msg){ } private static String handle_delete_command(String msg){ - int index = 0; - try{ - index = Integer.parseInt(msg.split(" ")[1]); - } catch (IndexOutOfBoundsException | NumberFormatException e) { - return "\t-----------------------------------\n" + - "\tPlease provide a valid task ID. Has to be an integer.\n" + - "\t-----------------------------------"; - } - try { - return taskList.remove_task(index); - } catch (IndexOutOfBoundsException e) { - return "\t-----------------------------------\n" + - "\t" + e.getMessage() +"\n" + - "\t-----------------------------------"; + return new DeleteCommand(msg, taskList).execute(); + } catch (DudeException e) { + return echo(e.getMessage()); } } diff --git a/src/main/java/Tasks/TaskList.java b/src/main/java/Tasks/TaskList.java index 323406b304..033f77ed87 100644 --- a/src/main/java/Tasks/TaskList.java +++ b/src/main/java/Tasks/TaskList.java @@ -1,5 +1,7 @@ package Tasks; +import Exceptions.DudeException; +import Exceptions.InvalidCommandIDException; import Tasks.Task; import java.util.ArrayList; @@ -34,9 +36,9 @@ public String add_task(Task task) throws TaskListFullException { "\t-----------------------------------"; } - public String remove_task(int index) throws IndexOutOfBoundsException { + public String remove_task(int index) throws DudeException { if (index > list.size() || index < 1) { - throw new IndexOutOfBoundsException("Sorry, the provided id is invalid."); + throw new DudeException("Sorry, the provided id is invalid."); } Task removed = list.remove(index - 1); return "\t-----------------------------------\n" + @@ -46,9 +48,9 @@ public String remove_task(int index) throws IndexOutOfBoundsException { "\t-----------------------------------"; } - public String mark_as_done(int index) throws IndexOutOfBoundsException{ + public String mark_as_done(int index) throws DudeException { if (index > list.size() || index < 1) { - throw new IndexOutOfBoundsException("Sorry, the provided id is invalid."); + throw new DudeException("Sorry, the provided id is invalid."); } list.get(index - 1).markAsDone(); return "\t-----------------------------------\n" + @@ -57,9 +59,9 @@ public String mark_as_done(int index) throws IndexOutOfBoundsException{ "\t-----------------------------------"; } - public String mark_as_undone(int index) throws IndexOutOfBoundsException { + public String mark_as_undone(int index) throws DudeException { if (index > list.size() || index < 1) { - throw new IndexOutOfBoundsException("Sorry, the provided id is invalid."); + throw new DudeException("Sorry, the provided id is invalid."); } list.get(index - 1).markAsUndone(); return "\t-----------------------------------\n" + From 234ea0ccdc4921faf6602aa1b09f2868eae4007f Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 18 Feb 2024 04:12:44 +0800 Subject: [PATCH 060/153] Added Command Type Enums --- src/main/java/Commands/ByeCommand.java | 7 + src/main/java/Commands/Command.java | 2 + src/main/java/Commands/CommandParser.java | 2 +- src/main/java/Commands/DeadlineCommand.java | 11 +- src/main/java/Commands/DeleteCommand.java | 6 +- src/main/java/Commands/EventCommand.java | 6 + src/main/java/Commands/HelpCommand.java | 5 + src/main/java/Commands/InvalidCommand.java | 6 + src/main/java/Commands/ListCommand.java | 6 + src/main/java/Commands/MarkCommand.java | 6 + src/main/java/Commands/TodoCommand.java | 6 + src/main/java/Commands/UnmarkCommand.java | 6 + src/main/java/Dude.java | 190 ++------------------ src/main/java/Tasks/TaskList.java | 5 +- src/main/java/Utils/CommandTypes.java | 1 + 15 files changed, 83 insertions(+), 182 deletions(-) diff --git a/src/main/java/Commands/ByeCommand.java b/src/main/java/Commands/ByeCommand.java index 70d36a551c..9c8fd77335 100644 --- a/src/main/java/Commands/ByeCommand.java +++ b/src/main/java/Commands/ByeCommand.java @@ -1,5 +1,7 @@ package Commands; +import Utils.CommandTypes; + public class ByeCommand extends Command { public ByeCommand() { @@ -9,4 +11,9 @@ public ByeCommand() { public String execute() { return "Bye. Hope to see you again soon!"; } + + @Override + public CommandTypes getCommandType() { + return CommandTypes.BYE; + } } diff --git a/src/main/java/Commands/Command.java b/src/main/java/Commands/Command.java index 6148314a84..f845e55a68 100644 --- a/src/main/java/Commands/Command.java +++ b/src/main/java/Commands/Command.java @@ -1,6 +1,7 @@ package Commands; import Exceptions.DudeException; +import Utils.CommandTypes; public abstract class Command { @@ -22,4 +23,5 @@ public String getRegex() { return this.regex; } + public abstract CommandTypes getCommandType(); } diff --git a/src/main/java/Commands/CommandParser.java b/src/main/java/Commands/CommandParser.java index 2a4bb740b8..1b4e629f82 100644 --- a/src/main/java/Commands/CommandParser.java +++ b/src/main/java/Commands/CommandParser.java @@ -6,7 +6,7 @@ public class CommandParser { - public static Command parseCommand(String input, TaskList tasklist) throws DudeException { + public static Command parseCommand(String input, TaskList tasklist) { String[] command = input.split(" ", 2); switch (command[0]) { case "bye": diff --git a/src/main/java/Commands/DeadlineCommand.java b/src/main/java/Commands/DeadlineCommand.java index a1594875ce..638e02728d 100644 --- a/src/main/java/Commands/DeadlineCommand.java +++ b/src/main/java/Commands/DeadlineCommand.java @@ -4,13 +4,16 @@ import Exceptions.InvalidFormatException; import Tasks.Deadline; import Tasks.TaskList; +import Utils.CommandTypes; public class DeadlineCommand extends Command { private final String input; private final TaskList taskList; + public static final String FORMAT = "deadline /by "; + public static final String REGEX = "deadline .* /by .*"; public DeadlineCommand(String input, TaskList tasklist) { - super("deadline /by ", "deadline .* /by .*"); + super(FORMAT, REGEX); this.input = input; this.taskList = tasklist; } @@ -29,4 +32,10 @@ public String execute() throws DudeException { + "\t " + deadline.toString() + "\n" + "\tNow you have " + this.taskList.getSize() + " tasks in the list."; } + + @Override + public CommandTypes getCommandType() { + return CommandTypes.DEADLINE; + } + } diff --git a/src/main/java/Commands/DeleteCommand.java b/src/main/java/Commands/DeleteCommand.java index 4316c362fe..951e3262b6 100644 --- a/src/main/java/Commands/DeleteCommand.java +++ b/src/main/java/Commands/DeleteCommand.java @@ -1,9 +1,9 @@ package Commands; import Exceptions.DudeException; -import Exceptions.InvalidCommandIDException; import Exceptions.InvalidFormatException; import Tasks.TaskList; +import Utils.CommandTypes; public class DeleteCommand extends Command { private final String input; @@ -37,6 +37,10 @@ public String execute() throws DudeException { } catch (DudeException e) { throw new DudeException(e.getMessage()); } + } + @Override + public CommandTypes getCommandType() { + return CommandTypes.DELETE; } } diff --git a/src/main/java/Commands/EventCommand.java b/src/main/java/Commands/EventCommand.java index 3401042235..47ae7c3861 100644 --- a/src/main/java/Commands/EventCommand.java +++ b/src/main/java/Commands/EventCommand.java @@ -5,6 +5,7 @@ import Tasks.Deadline; import Tasks.Event; import Tasks.TaskList; +import Utils.CommandTypes; public class EventCommand extends Command { private final String input; @@ -31,4 +32,9 @@ public String execute() throws DudeException { + "\tNow you have " + this.taskList.getSize() + " tasks in the list."; } + @Override + public CommandTypes getCommandType() { + return CommandTypes.EVENT; + } + } diff --git a/src/main/java/Commands/HelpCommand.java b/src/main/java/Commands/HelpCommand.java index 7f9a3db79b..b107d41347 100644 --- a/src/main/java/Commands/HelpCommand.java +++ b/src/main/java/Commands/HelpCommand.java @@ -1,6 +1,7 @@ package Commands; import Exceptions.DudeException; +import Utils.CommandTypes; public class HelpCommand extends Command { @@ -95,4 +96,8 @@ private String generateCommandHelpMessage() { return "I'm sorry, I don't know what that command is. Please type 'help' to see the list of commands I support."; } + @Override + public CommandTypes getCommandType() { + return CommandTypes.HELP; + } } diff --git a/src/main/java/Commands/InvalidCommand.java b/src/main/java/Commands/InvalidCommand.java index 25bdf2daf8..b22f4fe2ad 100644 --- a/src/main/java/Commands/InvalidCommand.java +++ b/src/main/java/Commands/InvalidCommand.java @@ -1,5 +1,7 @@ package Commands; +import Utils.CommandTypes; + public class InvalidCommand extends Command { public InvalidCommand() { @@ -10,4 +12,8 @@ public String execute() { return "Sorry I don't understand that command. Please try again."; } + @Override + public CommandTypes getCommandType() { + return CommandTypes.INVALID; + } } diff --git a/src/main/java/Commands/ListCommand.java b/src/main/java/Commands/ListCommand.java index 25fbe54f0b..5067884c81 100644 --- a/src/main/java/Commands/ListCommand.java +++ b/src/main/java/Commands/ListCommand.java @@ -1,6 +1,7 @@ package Commands; import Tasks.TaskList; +import Utils.CommandTypes; public class ListCommand extends Command { @@ -14,4 +15,9 @@ public ListCommand(TaskList tasklist) { public String execute() { return tasklist.toString(); } + + @Override + public CommandTypes getCommandType() { + return CommandTypes.LIST; + } } diff --git a/src/main/java/Commands/MarkCommand.java b/src/main/java/Commands/MarkCommand.java index 48fa52c16b..cd9a767cee 100644 --- a/src/main/java/Commands/MarkCommand.java +++ b/src/main/java/Commands/MarkCommand.java @@ -3,6 +3,7 @@ import Exceptions.DudeException; import Exceptions.InvalidFormatException; import Tasks.TaskList; +import Utils.CommandTypes; public class MarkCommand extends Command { private final String input; @@ -37,4 +38,9 @@ public String execute() throws DudeException { throw new DudeException(e.getMessage()); } } + + @Override + public CommandTypes getCommandType() { + return CommandTypes.MARK; + } } diff --git a/src/main/java/Commands/TodoCommand.java b/src/main/java/Commands/TodoCommand.java index 1777f2b6c0..a2cfc607bf 100644 --- a/src/main/java/Commands/TodoCommand.java +++ b/src/main/java/Commands/TodoCommand.java @@ -6,6 +6,7 @@ import Exceptions.TaskListFullException; import Tasks.TaskList; import Tasks.Todo; +import Utils.CommandTypes; public class TodoCommand extends Command { private final String input; @@ -30,4 +31,9 @@ public String execute() throws DudeException { + "\t " + todo.toString() + "\n" + "\tNow you have " + this.taskList.getSize() + " tasks in the list."; } + + @Override + public CommandTypes getCommandType() { + return CommandTypes.TODO; + } } diff --git a/src/main/java/Commands/UnmarkCommand.java b/src/main/java/Commands/UnmarkCommand.java index c989722809..298f1a32ca 100644 --- a/src/main/java/Commands/UnmarkCommand.java +++ b/src/main/java/Commands/UnmarkCommand.java @@ -3,6 +3,7 @@ import Exceptions.DudeException; import Exceptions.InvalidFormatException; import Tasks.TaskList; +import Utils.CommandTypes; public class UnmarkCommand extends Command { private final String input; @@ -37,4 +38,9 @@ public String execute() throws DudeException { throw new DudeException(e.getMessage()); } } + + @Override + public CommandTypes getCommandType() { + return CommandTypes.UNMARK; + } } diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index 894d7eed08..be46db61ae 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -1,3 +1,5 @@ +import Commands.Command; +import Commands.CommandParser; import Commands.DeleteCommand; import Exceptions.*; import Exceptions.TaskListFullException; @@ -7,6 +9,7 @@ import Tasks.Todo; import Utils.CommandTypes; import Utils.Storage; +import Utils.Ui; import java.util.NoSuchElementException; import java.util.Scanner; @@ -32,17 +35,17 @@ public static void main(String[] args) { // System.out.println("--------------------------------------"); // System.out.println("Dude v1.0 by Tahsin Hasem.\n"); + Ui ui = new Ui(); try { taskList = storage.loadTasks(); - } - catch (Exception e){ - System.out.println(echo("An error occurred while loading the tasks. Deleting the storage and starting with an empty task list.")); + } catch (Exception e) { //Thrown when file gets corrupted + ui.showMessage("An error occurred while loading the tasks. Deleting the storage and starting with an empty task list."); storage.deleteStorage(); taskList = new TaskList(); } - System.out.println(greet()); + ui.showWelcome(); // Initialise Scanner to reach command line input Scanner sc = new Scanner(System.in); @@ -56,184 +59,21 @@ public static void main(String[] args) { break; } - CommandTypes command = getCommand(msg); + Command command = CommandParser.parseCommand(msg, taskList); - switch (command) { - case BYE: - System.out.println(bye()); - return; - case LIST: - System.out.println(list()); - break; - case MARK: - System.out.println(mark_as_done(msg)); - break; - case UNMARK: - System.out.println(mark_as_undone(msg)); - break; - case TODO: - System.out.println(handle_todo_command(msg)); - break; - case EVENT: - System.out.println(handle_event_command(msg)); - break; - case DEADLINE: - System.out.println(handle_deadline_command(msg)); - break; - case DELETE: - System.out.println(handle_delete_command(msg)); - break; - case INVALID: - System.out.println(echo("I'm sorry, but I don't know what that means :-(")); - break; + try { + String response = command.execute(); + ui.showMessage(response); + } catch (DudeException e) { + ui.showMessage(e.getMessage()); } - if (isCommandChangingState(command)) { - try { - storage.saveTasks(taskList); - } catch (Exception e) { - System.out.println(echo("An error occurred while saving the tasks.")); - } + if (command.getCommandType() == CommandTypes.BYE) { + break; } } } - private static String greet(){ - return "\t-----------------------------------\n" + - "\tHello! I'm Dude\n" + - "\tWhat can I do for you?\n" + - "\t-----------------------------------\n"; - } - - private static String list(){ - return taskList.toString(); - } - - private static String bye(){ - String bye_msg = "\t-----------------------------------"; - bye_msg += "\n\tBye. Hope to see you again soon!"; - bye_msg += "\n\t-----------------------------------"; - - return bye_msg; - } - - private static String mark_as_done(String msg){ - //TODO: Write logic for commands with multiple parameters. Eg: mark 1 2 3 - //Try to retrieve the index - int index = 0; - try{ - index = Integer.parseInt(msg.split(" ")[1]); - } catch (IndexOutOfBoundsException | NumberFormatException e) { - return "\t-----------------------------------\n" + - "\tPlease provide a valid task ID. Has to be an integer.\n" + - "\t-----------------------------------"; - } - - //This will run only when the index is valid, as catch block will return the error message - try { - return taskList.mark_as_done(index); - } catch (IndexOutOfBoundsException e) { - return "\t-----------------------------------\n" + - "\t" + e.getMessage() +"\n" + - "\t-----------------------------------"; - } - } - - private static String mark_as_undone(String msg){ - //TODO: Write logic for commands with multiple parameters. Eg: unmark 1 2 3 - //Try to retrieve the index - int index = 0; - try{ - index = Integer.parseInt(msg.split(" ")[1]); - } catch (IndexOutOfBoundsException | NumberFormatException e) { - return "\t-----------------------------------\n" + - "\tPlease provide a valid task ID. Has to be an integer.\n" + - "\t-----------------------------------"; - } - - //This will run only when the index is valid, as catch block will return the error message - try { - return taskList.mark_as_undone(index); - } catch (IndexOutOfBoundsException e) { - return "\t-----------------------------------\n" + - "\t" + e.getMessage() +"\n" + - "\t-----------------------------------"; - } - } - - private static String echo(String msg){ - return "\t-----------------------------------\n" + - "\t" + msg + "\n" + - "\t-----------------------------------"; - } - - - private static String handle_todo_command(String msg){ - try{ - Todo task = Todo.from(msg); - return taskList.add_task(task); - }catch (InvalidDescriptionException | TaskListFullException e) { - return echo(e.getMessage()); - } - } - - private static String handle_event_command(String msg){ - try{ - Event task = Event.from(msg); - return taskList.add_task(task); - }catch (InvalidDescriptionException | InvalidFormatException | InvalidArgumentException | TaskListFullException e) { - return echo(e.getMessage()); - } - } - - private static String handle_deadline_command(String msg){ - try{ - Deadline task = Deadline.from(msg); - return taskList.add_task(task); - }catch (InvalidFormatException | InvalidArgumentException | InvalidDescriptionException | TaskListFullException e) { - return echo(e.getMessage()); - } - } - - private static String handle_delete_command(String msg){ - try { - return new DeleteCommand(msg, taskList).execute(); - } catch (DudeException e) { - return echo(e.getMessage()); - } - } - - private static boolean isCommandChangingState(CommandTypes command) { - return command == CommandTypes.TODO || command == CommandTypes.EVENT || command == CommandTypes.DEADLINE - || command == CommandTypes.DELETE || command == CommandTypes.MARK || command == CommandTypes.UNMARK; - } - - private static CommandTypes getCommand(String msg) { - String cmd = msg.split(" ")[0]; - - switch(cmd) { - case "bye": - return CommandTypes.BYE; - case "list": - return CommandTypes.LIST; - case "mark": - return CommandTypes.MARK; - case "unmark": - return CommandTypes.UNMARK; - case "todo": - return CommandTypes.TODO; - case "event": - return CommandTypes.EVENT; - case "deadline": - return CommandTypes.DEADLINE; - case "delete": - return CommandTypes.DELETE; - default: - return CommandTypes.INVALID; - } - - } - } diff --git a/src/main/java/Tasks/TaskList.java b/src/main/java/Tasks/TaskList.java index 033f77ed87..8ffad62f31 100644 --- a/src/main/java/Tasks/TaskList.java +++ b/src/main/java/Tasks/TaskList.java @@ -1,9 +1,6 @@ package Tasks; import Exceptions.DudeException; -import Exceptions.InvalidCommandIDException; -import Tasks.Task; - import java.util.ArrayList; import Exceptions.TaskListFullException; @@ -12,7 +9,7 @@ public class TaskList { private final ArrayList list; public TaskList(){ - list = new ArrayList<>(); + list = new ArrayList(); } public static TaskList from(ArrayList tasks) { diff --git a/src/main/java/Utils/CommandTypes.java b/src/main/java/Utils/CommandTypes.java index 3f466c0b75..d2034306b2 100644 --- a/src/main/java/Utils/CommandTypes.java +++ b/src/main/java/Utils/CommandTypes.java @@ -9,5 +9,6 @@ public enum CommandTypes { EVENT, MARK, UNMARK, + HELP, INVALID } From a67819f75c96625f52385a71e0b6e5b5837c3b78 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 18 Feb 2024 04:34:03 +0800 Subject: [PATCH 061/153] Changed getTask to take in ID instead of index --- src/main/java/Commands/DeleteCommand.java | 9 ++++++--- src/main/java/Commands/HelpCommand.java | 6 +++--- src/main/java/Commands/MarkCommand.java | 8 +++++--- src/main/java/Commands/UnmarkCommand.java | 8 +++++--- src/main/java/Dude.java | 1 - src/main/java/Tasks/TaskList.java | 22 +++++++++++++--------- src/main/java/Utils/Ui.java | 14 +++++++++----- 7 files changed, 41 insertions(+), 27 deletions(-) diff --git a/src/main/java/Commands/DeleteCommand.java b/src/main/java/Commands/DeleteCommand.java index 951e3262b6..64a2c46f42 100644 --- a/src/main/java/Commands/DeleteCommand.java +++ b/src/main/java/Commands/DeleteCommand.java @@ -2,6 +2,7 @@ import Exceptions.DudeException; import Exceptions.InvalidFormatException; +import Tasks.Task; import Tasks.TaskList; import Utils.CommandTypes; @@ -23,14 +24,16 @@ public String execute() throws DudeException { throw new InvalidFormatException("Invalid format for delete command. PLease use this format: " + this.getFormat()); } - int index = Integer.parseInt(this.input.split(" ")[1]); + int id = Integer.parseInt(this.input.split(" ")[1]); //re-throw exception if task does not exist try { - this.taskList.remove_task(index); + Task task = this.taskList.getTask(id); + + this.taskList.remove_task(id); String msg = "Noted. I've removed this task:\n" - + "\t " + index + ". " + this.taskList.getTask(index - 1).toString() + "\n" + + "\t " + id + ". " + task.toString() + "\n" + "\tNow you have " + this.taskList.getSize() + " tasks in the list."; return msg; diff --git a/src/main/java/Commands/HelpCommand.java b/src/main/java/Commands/HelpCommand.java index b107d41347..6ea7e741c3 100644 --- a/src/main/java/Commands/HelpCommand.java +++ b/src/main/java/Commands/HelpCommand.java @@ -33,11 +33,11 @@ public String execute() throws DudeException { } private String generateHelpMessage() { - String helpMessage = "Here are the commands I support:\n"; + String helpMessage = "Here are the commands I support:"; for (String command : supportedCommands) { - helpMessage += "\t" + command + "\n"; + helpMessage += "\n\t" + command; } - helpMessage += "For more information on a specific command, type 'help '"; + helpMessage += "\nFor more information on a specific command, type 'help '"; return helpMessage; } diff --git a/src/main/java/Commands/MarkCommand.java b/src/main/java/Commands/MarkCommand.java index cd9a767cee..486763483b 100644 --- a/src/main/java/Commands/MarkCommand.java +++ b/src/main/java/Commands/MarkCommand.java @@ -2,6 +2,7 @@ import Exceptions.DudeException; import Exceptions.InvalidFormatException; +import Tasks.Task; import Tasks.TaskList; import Utils.CommandTypes; @@ -24,14 +25,15 @@ public String execute() throws DudeException { throw new InvalidFormatException("Invalid format for mark command. Please use this format: " + this.getFormat()); } - int index = Integer.parseInt(this.input.split(" ")[1]); + int id = Integer.parseInt(this.input.split(" ")[1]); //re-thow exception if task does not exist try { - this.taskList.mark_as_done(index); + Task task = this.taskList.getTask(id); + this.taskList.mark_as_done(id); String msg = "Nice! I've marked this task as done:\n" - + "\t " + index + ". " + this.taskList.getTask(index - 1).toString(); + + "\t " + id + ". " + task.toString(); return msg; } catch (DudeException e) { diff --git a/src/main/java/Commands/UnmarkCommand.java b/src/main/java/Commands/UnmarkCommand.java index 298f1a32ca..1d2e1582c9 100644 --- a/src/main/java/Commands/UnmarkCommand.java +++ b/src/main/java/Commands/UnmarkCommand.java @@ -2,6 +2,7 @@ import Exceptions.DudeException; import Exceptions.InvalidFormatException; +import Tasks.Task; import Tasks.TaskList; import Utils.CommandTypes; @@ -24,14 +25,15 @@ public String execute() throws DudeException { throw new InvalidFormatException("Invalid format for mark command. Please use this format: " + this.getFormat()); } - int index = Integer.parseInt(this.input.split(" ")[1]); + int id = Integer.parseInt(this.input.split(" ")[1]); //re-throw exception if task does not exist try { - this.taskList.mark_as_undone(index); + Task task = taskList.getTask(id); + this.taskList.mark_as_undone(id); String msg = "Nice! I've unmarked this task as done:\n" - + "\t " + index + ". " + this.taskList.getTask(index - 1).toString(); + + "\t " + id + ". " + task.toString(); return msg; } catch (DudeException e) { diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index be46db61ae..5b6d18740b 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -71,7 +71,6 @@ public static void main(String[] args) { if (command.getCommandType() == CommandTypes.BYE) { break; } - } } diff --git a/src/main/java/Tasks/TaskList.java b/src/main/java/Tasks/TaskList.java index 8ffad62f31..425f1f03f1 100644 --- a/src/main/java/Tasks/TaskList.java +++ b/src/main/java/Tasks/TaskList.java @@ -33,11 +33,11 @@ public String add_task(Task task) throws TaskListFullException { "\t-----------------------------------"; } - public String remove_task(int index) throws DudeException { - if (index > list.size() || index < 1) { + public String remove_task(int taskID) throws DudeException { + if (taskID > list.size() || taskID < 1) { throw new DudeException("Sorry, the provided id is invalid."); } - Task removed = list.remove(index - 1); + Task removed = list.remove(taskID - 1); return "\t-----------------------------------\n" + "\tNoted. I've removed this task:\n" + "\t " + removed.toString() + "\n" + @@ -70,11 +70,15 @@ public String mark_as_undone(int index) throws DudeException { @Override public String toString() { - String result = "\t-----------------------------------\n"; + String result = ""; for (int i = 0; i < list.size(); i++) { - result += "\t" + (i + 1) + ". " + list.get(i).toString() + "\n"; + //if it is the last task, do not add a new line + if (i == list.size() - 1) { + result += (i + 1) + ". " + list.get(i).toString(); + break; + } + result += (i + 1) + ". " + list.get(i).toString() + "\n"; } - result += "\t-----------------------------------"; return result; } @@ -102,10 +106,10 @@ public int getSize() { return list.size(); } - public Task getTask(int index) throws IndexOutOfBoundsException{ - if (index < 0 || index >= list.size()) { + public Task getTask(int taskID) throws IndexOutOfBoundsException { + if (taskID <= 0 || taskID >= list.size()) { throw new IndexOutOfBoundsException("Sorry, the provided id is invalid."); } - return list.get(index); + return list.get(taskID - 1); } } diff --git a/src/main/java/Utils/Ui.java b/src/main/java/Utils/Ui.java index 37c038875d..87a9023c96 100644 --- a/src/main/java/Utils/Ui.java +++ b/src/main/java/Utils/Ui.java @@ -5,16 +5,20 @@ public class Ui { public void showWelcome() { String msg = "\t-----------------------------------\n" + - "\tHello! I'm Dude\n" + - "\tWhat can I do for you?\n" + + "\t\tHello! I'm Dude\n" + + "\t\tWhat can I do for you?\n" + "\t-----------------------------------\n"; System.out.println(msg); } public void showMessage(String msg) { - msg = "\t-----------------------------------\n" + - "\t" + msg + "\n" + + + String temp = msg; + + temp = temp.replaceAll("\n", "\n\t\t"); + temp = "\t-----------------------------------\n" + + "\t\t" + temp + "\n" + "\t-----------------------------------"; - System.out.println(msg); + System.out.println(temp); } } From 04f467afa1b31b66db781fabe59de6f841f535e5 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 18 Feb 2024 04:35:48 +0800 Subject: [PATCH 062/153] Dixed bug --- src/main/java/Tasks/TaskList.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/Tasks/TaskList.java b/src/main/java/Tasks/TaskList.java index 425f1f03f1..ec313b5182 100644 --- a/src/main/java/Tasks/TaskList.java +++ b/src/main/java/Tasks/TaskList.java @@ -107,7 +107,7 @@ public int getSize() { } public Task getTask(int taskID) throws IndexOutOfBoundsException { - if (taskID <= 0 || taskID >= list.size()) { + if (taskID <= 0 || taskID > list.size()) { throw new IndexOutOfBoundsException("Sorry, the provided id is invalid."); } return list.get(taskID - 1); From b0e24055d3b67dffaf97ff00e467cfe048bd91de Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 18 Feb 2024 05:11:33 +0800 Subject: [PATCH 063/153] Working duke in static context --- src/main/java/Commands/ByeCommand.java | 4 ++- src/main/java/Commands/DeadlineCommand.java | 8 ++--- src/main/java/Commands/DeleteCommand.java | 6 ++-- src/main/java/Commands/EventCommand.java | 6 ++-- src/main/java/Commands/HelpCommand.java | 2 ++ src/main/java/Commands/ListCommand.java | 1 + src/main/java/Commands/MarkCommand.java | 6 ++-- src/main/java/Commands/TodoCommand.java | 6 ++-- src/main/java/Commands/UnmarkCommand.java | 6 ++-- src/main/java/Dude.java | 32 +++++++++++-------- .../Exceptions/InvalidFormatException.java | 16 ++++++++-- src/main/java/Tasks/Deadline.java | 2 +- src/main/java/Tasks/Event.java | 6 ++-- src/main/java/Tasks/TaskList.java | 3 +- 14 files changed, 69 insertions(+), 35 deletions(-) diff --git a/src/main/java/Commands/ByeCommand.java b/src/main/java/Commands/ByeCommand.java index 9c8fd77335..dd5821cab8 100644 --- a/src/main/java/Commands/ByeCommand.java +++ b/src/main/java/Commands/ByeCommand.java @@ -4,8 +4,10 @@ public class ByeCommand extends Command { + static final String COMMAND_FORMAT = "bye"; + public ByeCommand() { - super("bye", "bye"); + super(COMMAND_FORMAT, "bye"); } public String execute() { diff --git a/src/main/java/Commands/DeadlineCommand.java b/src/main/java/Commands/DeadlineCommand.java index 638e02728d..8522f2375b 100644 --- a/src/main/java/Commands/DeadlineCommand.java +++ b/src/main/java/Commands/DeadlineCommand.java @@ -9,11 +9,11 @@ public class DeadlineCommand extends Command { private final String input; private final TaskList taskList; - public static final String FORMAT = "deadline /by "; - public static final String REGEX = "deadline .* /by .*"; + + static final String COMMAND_FORMAT = "deadline /by "; public DeadlineCommand(String input, TaskList tasklist) { - super(FORMAT, REGEX); + super(COMMAND_FORMAT, "deadline .* /by .*"); this.input = input; this.taskList = tasklist; } @@ -23,7 +23,7 @@ public String execute() throws DudeException { //only catches basic format errors. date format errors are caught by Deadline.from() if (!doesInputMatch) { - throw new InvalidFormatException("Invalid format for deadline command. Please use this format: " + this.getFormat()); + throw new InvalidFormatException("deadline", COMMAND_FORMAT); } Deadline deadline = Deadline.from(input); //throws different DukeExceptions diff --git a/src/main/java/Commands/DeleteCommand.java b/src/main/java/Commands/DeleteCommand.java index 64a2c46f42..8025b482c4 100644 --- a/src/main/java/Commands/DeleteCommand.java +++ b/src/main/java/Commands/DeleteCommand.java @@ -10,8 +10,10 @@ public class DeleteCommand extends Command { private final String input; private final TaskList taskList; + private static final String COMMAND_FORMAT = "delete "; + public DeleteCommand(String input, TaskList tasklist) { - super("delete ", "delete \\d+"); + super(COMMAND_FORMAT, "delete \\d+"); this.input = input.trim(); this.taskList = tasklist; } @@ -21,7 +23,7 @@ public String execute() throws DudeException { //throw error if input does not match the format if (!inputMatches) { - throw new InvalidFormatException("Invalid format for delete command. PLease use this format: " + this.getFormat()); + throw new InvalidFormatException("delete", COMMAND_FORMAT); } int id = Integer.parseInt(this.input.split(" ")[1]); diff --git a/src/main/java/Commands/EventCommand.java b/src/main/java/Commands/EventCommand.java index 47ae7c3861..3ae8fb2d40 100644 --- a/src/main/java/Commands/EventCommand.java +++ b/src/main/java/Commands/EventCommand.java @@ -11,8 +11,10 @@ public class EventCommand extends Command { private final String input; private final TaskList taskList; + public static final String COMMAND_FORMAT = "event /from /to "; + public EventCommand(String input, TaskList tasklist) { - super("event /from /to ", "event .* /from .* /to .*"); + super(COMMAND_FORMAT, "event .* /from .* /to .*"); this.input = input; this.taskList = tasklist; } @@ -22,7 +24,7 @@ public String execute() throws DudeException { //only catches basic format errors. date format errors are caught by Deadline.from() if (!doesInputMatch) { - throw new InvalidFormatException("Invalid format for deadline command. Please use this format: " + this.getFormat()); + throw new InvalidFormatException("event", COMMAND_FORMAT); } Event event = Event.from(input); //throws different DukeExceptions diff --git a/src/main/java/Commands/HelpCommand.java b/src/main/java/Commands/HelpCommand.java index 6ea7e741c3..1a65a90288 100644 --- a/src/main/java/Commands/HelpCommand.java +++ b/src/main/java/Commands/HelpCommand.java @@ -5,6 +5,8 @@ public class HelpCommand extends Command { + private static final String COMMAND_FORMAT = "help "; + private final String[] supportedCommands = new String[]{ "list: Lists all the tasks in the task list.", "todo: Adds a todo task to the task list.", diff --git a/src/main/java/Commands/ListCommand.java b/src/main/java/Commands/ListCommand.java index 5067884c81..8b023a914a 100644 --- a/src/main/java/Commands/ListCommand.java +++ b/src/main/java/Commands/ListCommand.java @@ -5,6 +5,7 @@ public class ListCommand extends Command { + static final String COMMAND_FORMAT = "list"; private final TaskList tasklist; public ListCommand(TaskList tasklist) { diff --git a/src/main/java/Commands/MarkCommand.java b/src/main/java/Commands/MarkCommand.java index 486763483b..09fbd2a335 100644 --- a/src/main/java/Commands/MarkCommand.java +++ b/src/main/java/Commands/MarkCommand.java @@ -7,11 +7,13 @@ import Utils.CommandTypes; public class MarkCommand extends Command { + + public static final String COMMAND_FORMAT = "mark "; private final String input; private final TaskList taskList; public MarkCommand(String input, TaskList tasklist) { - super("mark ", "mark \\d+"); + super(COMMAND_FORMAT, "mark \\d+"); this.input = input.trim(); this.taskList = tasklist; } @@ -22,7 +24,7 @@ public String execute() throws DudeException { //throw error if input does not match the format if (!inputMatches) { - throw new InvalidFormatException("Invalid format for mark command. Please use this format: " + this.getFormat()); + throw new InvalidFormatException("mark", COMMAND_FORMAT); } int id = Integer.parseInt(this.input.split(" ")[1]); diff --git a/src/main/java/Commands/TodoCommand.java b/src/main/java/Commands/TodoCommand.java index a2cfc607bf..50ef5b6041 100644 --- a/src/main/java/Commands/TodoCommand.java +++ b/src/main/java/Commands/TodoCommand.java @@ -9,11 +9,13 @@ import Utils.CommandTypes; public class TodoCommand extends Command { + + public static final String COMMAND_FORMAT = "todo "; private final String input; private final TaskList taskList; public TodoCommand(String input, TaskList tasklist) { - super("todo ", "todo .*"); + super(COMMAND_FORMAT, "todo .*"); this.input = input; this.taskList = tasklist; } @@ -22,7 +24,7 @@ public String execute() throws DudeException { boolean doesInputMatch = input.matches(this.getRegex()); if (!doesInputMatch) { - throw new InvalidFormatException("Invalid format for todo command. Please use this format: " + this.getFormat()); + throw new InvalidFormatException("todo", COMMAND_FORMAT); } Todo todo = Todo.from(input); //throws InvalidDescriptionException diff --git a/src/main/java/Commands/UnmarkCommand.java b/src/main/java/Commands/UnmarkCommand.java index 1d2e1582c9..3bf35140a6 100644 --- a/src/main/java/Commands/UnmarkCommand.java +++ b/src/main/java/Commands/UnmarkCommand.java @@ -7,11 +7,13 @@ import Utils.CommandTypes; public class UnmarkCommand extends Command { + + public static final String COMMAND_FORMAT = "unmark "; private final String input; private final TaskList taskList; public UnmarkCommand(String input, TaskList tasklist) { - super("mark ", "unmark \\d+"); + super(COMMAND_FORMAT, "unmark \\d+"); this.input = input.trim(); this.taskList = tasklist; } @@ -22,7 +24,7 @@ public String execute() throws DudeException { //throw error if input does not match the format if (!inputMatches) { - throw new InvalidFormatException("Invalid format for mark command. Please use this format: " + this.getFormat()); + throw new InvalidFormatException("unmark", COMMAND_FORMAT); } int id = Integer.parseInt(this.input.split(" ")[1]); diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index 5b6d18740b..e8145109a8 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -19,21 +19,14 @@ public class Dude { private static TaskList taskList = null; private static Storage storage = new Storage("data/tasklist.ser"); - static final String[] supported_commands = {"bye", "list", "mark", "unmark", "todo", "event", "deadline", "delete"}; - public static void main(String[] args) { + public void run() { + + } -// String logo = "888888ba dP \n" + -// "88 `8b 88 \n" + -// "88 88 dP dP .d888b88 .d8888b. \n" + -// "88 88 88 88 88' `88 88ooood8 \n" + -// "88 .8P 88. .88 88. .88 88. ... \n" + -// "8888888P `88888P' `88888P8 `88888P'"; -// -// System.out.println("--------------------------------------\n"); -// System.out.println(logo + "\n"); -// System.out.println("--------------------------------------"); -// System.out.println("Dude v1.0 by Tahsin Hasem.\n"); + + + public static void main(String[] args) { Ui ui = new Ui(); @@ -64,10 +57,21 @@ public static void main(String[] args) { try { String response = command.execute(); ui.showMessage(response); - } catch (DudeException e) { + } catch (DudeException | IndexOutOfBoundsException e) { ui.showMessage(e.getMessage()); } + boolean isListCommand = command.getCommandType() == CommandTypes.LIST; + boolean isByeCommand = command.getCommandType() == CommandTypes.BYE; + + if (!(isListCommand || isByeCommand)) { + try { + storage.saveTasks(taskList); + } catch (Exception e) { + ui.showMessage("An error occurred while saving the tasks."); + } + } + if (command.getCommandType() == CommandTypes.BYE) { break; } diff --git a/src/main/java/Exceptions/InvalidFormatException.java b/src/main/java/Exceptions/InvalidFormatException.java index 039ee37dfa..5801663535 100644 --- a/src/main/java/Exceptions/InvalidFormatException.java +++ b/src/main/java/Exceptions/InvalidFormatException.java @@ -3,8 +3,20 @@ import Exceptions.DudeException; public class InvalidFormatException extends DudeException { - //Used to indicate that the format is invalid + public InvalidFormatException(String message) { super(message); } -} + + //Used to indicate that the format is invalid + public InvalidFormatException(String command, String format) { + super("Invalid format for " + command + " command. \nPlease use this format: " + format + ",\n or type help for more information."); + } + + public InvalidFormatException(String command, String format, String note) { + super("Invalid format for " + command + " command. " + + "\nPlease use this format: " + format + "," + + "\n or type help for more information." + + "\nNote: " + note); + } +} \ No newline at end of file diff --git a/src/main/java/Tasks/Deadline.java b/src/main/java/Tasks/Deadline.java index 400c6f5573..7ee1ab9d38 100644 --- a/src/main/java/Tasks/Deadline.java +++ b/src/main/java/Tasks/Deadline.java @@ -21,7 +21,7 @@ public static Deadline from(String s) throws InvalidFormatException, InvalidDesc int by_occurences = utils.countOccurrences(arr, "/by"); if (by_occurences == 0 || by_occurences > 1){ - throw new InvalidFormatException("Invalid format. Follow this format: deadline /by . Provide one and only one '/by'."); + throw new InvalidFormatException("deadline", "format: deadline /by . Provide one and only one '/by'."); } //they will not be -1 as I have already checked for their occurences diff --git a/src/main/java/Tasks/Event.java b/src/main/java/Tasks/Event.java index 63edac5c4e..0f9517d8e8 100644 --- a/src/main/java/Tasks/Event.java +++ b/src/main/java/Tasks/Event.java @@ -1,4 +1,6 @@ package Tasks; + +import Commands.EventCommand; import Exceptions.InvalidArgumentException; import Exceptions.InvalidDescriptionException; import Exceptions.InvalidFormatException; @@ -25,13 +27,13 @@ public static Event from(String s) throws InvalidArgumentException, InvalidForma int from_occurences = utils.countOccurrences(arr, "/from"); if (from_occurences == 0 || from_occurences > 1){ - throw new InvalidFormatException("Invalid format. Follow this format: event /from /to . Provide one and only one '/from'."); + throw new InvalidFormatException("Invalid format. Follow this format :" + EventCommand.COMMAND_FORMAT + ". Provide one and only one '/from'."); } int to_occurences = utils.countOccurrences(arr, "/to"); if (to_occurences == 0 || to_occurences > 1){ - throw new InvalidFormatException("Invalid format. Follow this format: event /from /to . Provide one and only one '/to'."); + throw new InvalidFormatException("Invalid format. Follow this format: " + EventCommand.COMMAND_FORMAT + ". Provide one and only one '/to'."); } //they will not be -1 as I have already checked for their occurences diff --git a/src/main/java/Tasks/TaskList.java b/src/main/java/Tasks/TaskList.java index ec313b5182..b752df433d 100644 --- a/src/main/java/Tasks/TaskList.java +++ b/src/main/java/Tasks/TaskList.java @@ -108,7 +108,8 @@ public int getSize() { public Task getTask(int taskID) throws IndexOutOfBoundsException { if (taskID <= 0 || taskID > list.size()) { - throw new IndexOutOfBoundsException("Sorry, the provided id is invalid."); + throw new IndexOutOfBoundsException("Sorry, the provided id is invalid. " + + "Use the list command to see the list of tasks."); } return list.get(taskID - 1); } From adc493f3f5fa9d2248ca7826a439e2d2fa992b6f Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 18 Feb 2024 05:32:08 +0800 Subject: [PATCH 064/153] Better code quality --- src/main/java/Commands/CommandParser.java | 4 +- src/main/java/Dude.java | 101 +++++++++++----------- 2 files changed, 53 insertions(+), 52 deletions(-) diff --git a/src/main/java/Commands/CommandParser.java b/src/main/java/Commands/CommandParser.java index 1b4e629f82..bd7236a901 100644 --- a/src/main/java/Commands/CommandParser.java +++ b/src/main/java/Commands/CommandParser.java @@ -1,12 +1,10 @@ package Commands; -import Exceptions.DudeException; import Tasks.TaskList; -import Utils.Storage; public class CommandParser { - public static Command parseCommand(String input, TaskList tasklist) { + public static Command parse(String input, TaskList tasklist) { String[] command = input.split(" ", 2); switch (command[0]) { case "bye": diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index e8145109a8..f2daecedfd 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -1,12 +1,7 @@ import Commands.Command; import Commands.CommandParser; -import Commands.DeleteCommand; import Exceptions.*; -import Exceptions.TaskListFullException; -import Tasks.Deadline; -import Tasks.Event; import Tasks.TaskList; -import Tasks.Todo; import Utils.CommandTypes; import Utils.Storage; import Utils.Ui; @@ -15,68 +10,76 @@ import java.util.Scanner; public class Dude { + private final TaskList taskList; + private final Storage storage; + private final Ui ui; - private static TaskList taskList = null; - private static Storage storage = new Storage("data/tasklist.ser"); + private boolean isRunning = true; + public Dude(String filePath){ + this.storage = new Storage(filePath); + this.ui = new Ui(); - public void run() { - - } - - - - public static void main(String[] args) { - - Ui ui = new Ui(); - + TaskList temp = null; try { - taskList = storage.loadTasks(); + temp = this.storage.loadTasks(); } catch (Exception e) { //Thrown when file gets corrupted ui.showMessage("An error occurred while loading the tasks. Deleting the storage and starting with an empty task list."); - storage.deleteStorage(); - taskList = new TaskList(); + this.storage.deleteStorage(); + temp = new TaskList(); } - ui.showWelcome(); + this.taskList = temp; + } + + public void run() { - // Initialise Scanner to reach command line input + ui.showWelcome(); Scanner sc = new Scanner(System.in); - while(true){ - - String msg = ""; - try { - msg = sc.nextLine(); - }catch(NoSuchElementException e){ - //this will not be handled. - break; - } + while(this.isRunning){ - Command command = CommandParser.parseCommand(msg, taskList); + String input = extractInput(sc); + Command command = CommandParser.parse(input, taskList); - try { - String response = command.execute(); - ui.showMessage(response); - } catch (DudeException | IndexOutOfBoundsException e) { - ui.showMessage(e.getMessage()); - } + String response = executeCommand(command); + ui.showMessage(response); - boolean isListCommand = command.getCommandType() == CommandTypes.LIST; - boolean isByeCommand = command.getCommandType() == CommandTypes.BYE; - - if (!(isListCommand || isByeCommand)) { - try { - storage.saveTasks(taskList); - } catch (Exception e) { - ui.showMessage("An error occurred while saving the tasks."); - } - } + saveToDisk(); if (command.getCommandType() == CommandTypes.BYE) { - break; + this.isRunning = false; } } + } + private static String extractInput(Scanner sc) { + String input = ""; + try { + input = sc.nextLine(); + }catch(NoSuchElementException e){ + //this will not be handled. App will only exit at bye command. + input = ""; + } + return input; } + private static String executeCommand(Command command) { + try { + return command.execute(); + } catch (DudeException | IndexOutOfBoundsException e) { + return e.getMessage(); + } + } + + private void saveToDisk() { + try { + this.storage.saveTasks(taskList); + } catch (Exception e) { + this.ui.showMessage("An error occurred while saving the tasks."); + } + } + + public static void main(String[] args) { + new Dude("data/tasklist.ser").run(); + } } From 5b5d9f9e224c398c37407dec78ab06a18d3f0690 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 18 Feb 2024 05:35:18 +0800 Subject: [PATCH 065/153] renamed CommandParser to Parser. Moved CommandTypes to Command Package --- src/main/java/Commands/ByeCommand.java | 2 -- src/main/java/Commands/Command.java | 1 - src/main/java/{Utils => Commands}/CommandTypes.java | 2 +- src/main/java/Commands/DeadlineCommand.java | 1 - src/main/java/Commands/DeleteCommand.java | 1 - src/main/java/Commands/EventCommand.java | 2 -- src/main/java/Commands/HelpCommand.java | 1 - src/main/java/Commands/InvalidCommand.java | 2 -- src/main/java/Commands/ListCommand.java | 1 - src/main/java/Commands/MarkCommand.java | 1 - src/main/java/Commands/{CommandParser.java => Parser.java} | 2 +- src/main/java/Commands/TodoCommand.java | 3 --- src/main/java/Commands/UnmarkCommand.java | 1 - src/main/java/Dude.java | 6 +++--- 14 files changed, 5 insertions(+), 21 deletions(-) rename src/main/java/{Utils => Commands}/CommandTypes.java (88%) rename src/main/java/Commands/{CommandParser.java => Parser.java} (96%) diff --git a/src/main/java/Commands/ByeCommand.java b/src/main/java/Commands/ByeCommand.java index dd5821cab8..aa320fd50a 100644 --- a/src/main/java/Commands/ByeCommand.java +++ b/src/main/java/Commands/ByeCommand.java @@ -1,7 +1,5 @@ package Commands; -import Utils.CommandTypes; - public class ByeCommand extends Command { static final String COMMAND_FORMAT = "bye"; diff --git a/src/main/java/Commands/Command.java b/src/main/java/Commands/Command.java index f845e55a68..babd5360aa 100644 --- a/src/main/java/Commands/Command.java +++ b/src/main/java/Commands/Command.java @@ -1,7 +1,6 @@ package Commands; import Exceptions.DudeException; -import Utils.CommandTypes; public abstract class Command { diff --git a/src/main/java/Utils/CommandTypes.java b/src/main/java/Commands/CommandTypes.java similarity index 88% rename from src/main/java/Utils/CommandTypes.java rename to src/main/java/Commands/CommandTypes.java index d2034306b2..9aa6306dc9 100644 --- a/src/main/java/Utils/CommandTypes.java +++ b/src/main/java/Commands/CommandTypes.java @@ -1,4 +1,4 @@ -package Utils; +package Commands; public enum CommandTypes { BYE, diff --git a/src/main/java/Commands/DeadlineCommand.java b/src/main/java/Commands/DeadlineCommand.java index 8522f2375b..fdc9cc4560 100644 --- a/src/main/java/Commands/DeadlineCommand.java +++ b/src/main/java/Commands/DeadlineCommand.java @@ -4,7 +4,6 @@ import Exceptions.InvalidFormatException; import Tasks.Deadline; import Tasks.TaskList; -import Utils.CommandTypes; public class DeadlineCommand extends Command { private final String input; diff --git a/src/main/java/Commands/DeleteCommand.java b/src/main/java/Commands/DeleteCommand.java index 8025b482c4..366b9fb598 100644 --- a/src/main/java/Commands/DeleteCommand.java +++ b/src/main/java/Commands/DeleteCommand.java @@ -4,7 +4,6 @@ import Exceptions.InvalidFormatException; import Tasks.Task; import Tasks.TaskList; -import Utils.CommandTypes; public class DeleteCommand extends Command { private final String input; diff --git a/src/main/java/Commands/EventCommand.java b/src/main/java/Commands/EventCommand.java index 3ae8fb2d40..1d92b65e73 100644 --- a/src/main/java/Commands/EventCommand.java +++ b/src/main/java/Commands/EventCommand.java @@ -2,10 +2,8 @@ import Exceptions.DudeException; import Exceptions.InvalidFormatException; -import Tasks.Deadline; import Tasks.Event; import Tasks.TaskList; -import Utils.CommandTypes; public class EventCommand extends Command { private final String input; diff --git a/src/main/java/Commands/HelpCommand.java b/src/main/java/Commands/HelpCommand.java index 1a65a90288..af9f9715f4 100644 --- a/src/main/java/Commands/HelpCommand.java +++ b/src/main/java/Commands/HelpCommand.java @@ -1,7 +1,6 @@ package Commands; import Exceptions.DudeException; -import Utils.CommandTypes; public class HelpCommand extends Command { diff --git a/src/main/java/Commands/InvalidCommand.java b/src/main/java/Commands/InvalidCommand.java index b22f4fe2ad..d39606e75b 100644 --- a/src/main/java/Commands/InvalidCommand.java +++ b/src/main/java/Commands/InvalidCommand.java @@ -1,7 +1,5 @@ package Commands; -import Utils.CommandTypes; - public class InvalidCommand extends Command { public InvalidCommand() { diff --git a/src/main/java/Commands/ListCommand.java b/src/main/java/Commands/ListCommand.java index 8b023a914a..d114dd2f64 100644 --- a/src/main/java/Commands/ListCommand.java +++ b/src/main/java/Commands/ListCommand.java @@ -1,7 +1,6 @@ package Commands; import Tasks.TaskList; -import Utils.CommandTypes; public class ListCommand extends Command { diff --git a/src/main/java/Commands/MarkCommand.java b/src/main/java/Commands/MarkCommand.java index 09fbd2a335..bccd6f97e7 100644 --- a/src/main/java/Commands/MarkCommand.java +++ b/src/main/java/Commands/MarkCommand.java @@ -4,7 +4,6 @@ import Exceptions.InvalidFormatException; import Tasks.Task; import Tasks.TaskList; -import Utils.CommandTypes; public class MarkCommand extends Command { diff --git a/src/main/java/Commands/CommandParser.java b/src/main/java/Commands/Parser.java similarity index 96% rename from src/main/java/Commands/CommandParser.java rename to src/main/java/Commands/Parser.java index bd7236a901..4bc620ad6e 100644 --- a/src/main/java/Commands/CommandParser.java +++ b/src/main/java/Commands/Parser.java @@ -2,7 +2,7 @@ import Tasks.TaskList; -public class CommandParser { +public class Parser { public static Command parse(String input, TaskList tasklist) { String[] command = input.split(" ", 2); diff --git a/src/main/java/Commands/TodoCommand.java b/src/main/java/Commands/TodoCommand.java index 50ef5b6041..34c808a394 100644 --- a/src/main/java/Commands/TodoCommand.java +++ b/src/main/java/Commands/TodoCommand.java @@ -1,12 +1,9 @@ package Commands; import Exceptions.DudeException; -import Exceptions.InvalidDescriptionException; import Exceptions.InvalidFormatException; -import Exceptions.TaskListFullException; import Tasks.TaskList; import Tasks.Todo; -import Utils.CommandTypes; public class TodoCommand extends Command { diff --git a/src/main/java/Commands/UnmarkCommand.java b/src/main/java/Commands/UnmarkCommand.java index 3bf35140a6..dfead4c5a9 100644 --- a/src/main/java/Commands/UnmarkCommand.java +++ b/src/main/java/Commands/UnmarkCommand.java @@ -4,7 +4,6 @@ import Exceptions.InvalidFormatException; import Tasks.Task; import Tasks.TaskList; -import Utils.CommandTypes; public class UnmarkCommand extends Command { diff --git a/src/main/java/Dude.java b/src/main/java/Dude.java index f2daecedfd..fb6f4b4fe9 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/Dude.java @@ -1,8 +1,8 @@ import Commands.Command; -import Commands.CommandParser; +import Commands.Parser; import Exceptions.*; import Tasks.TaskList; -import Utils.CommandTypes; +import Commands.CommandTypes; import Utils.Storage; import Utils.Ui; @@ -39,7 +39,7 @@ public void run() { while(this.isRunning){ String input = extractInput(sc); - Command command = CommandParser.parse(input, taskList); + Command command = Parser.parse(input, taskList); String response = executeCommand(command); ui.showMessage(response); From 7dad305a4113df2cfa0177f76bde4e0a0e10753c Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 18 Feb 2024 05:47:49 +0800 Subject: [PATCH 066/153] moved all classes to dude package --- .../java/{ => dude}/Commands/ByeCommand.java | 2 +- src/main/java/{ => dude}/Commands/Command.java | 4 ++-- .../java/{ => dude}/Commands/CommandTypes.java | 2 +- .../{ => dude}/Commands/DeadlineCommand.java | 10 +++++----- .../java/{ => dude}/Commands/DeleteCommand.java | 10 +++++----- .../java/{ => dude}/Commands/EventCommand.java | 10 +++++----- .../java/{ => dude}/Commands/HelpCommand.java | 4 ++-- .../java/{ => dude}/Commands/InvalidCommand.java | 2 +- .../java/{ => dude}/Commands/ListCommand.java | 4 ++-- .../java/{ => dude}/Commands/MarkCommand.java | 10 +++++----- src/main/java/{ => dude}/Commands/Parser.java | 4 ++-- .../java/{ => dude}/Commands/TodoCommand.java | 10 +++++----- .../java/{ => dude}/Commands/UnmarkCommand.java | 10 +++++----- src/main/java/{ => dude}/Dude.java | 16 +++++++++------- .../{ => dude}/Exceptions/DudeException.java | 2 +- .../Exceptions/InvalidArgumentException.java | 4 +--- .../Exceptions/InvalidCommandException.java | 4 +--- .../Exceptions/InvalidDescriptionException.java | 4 +--- .../Exceptions/InvalidFormatException.java | 4 +--- .../Exceptions/TaskListFullException.java | 4 +--- src/main/java/{ => dude}/Tasks/Deadline.java | 10 +++++----- src/main/java/{ => dude}/Tasks/Event.java | 12 ++++++------ src/main/java/{ => dude}/Tasks/Task.java | 2 +- src/main/java/{ => dude}/Tasks/TaskList.java | 7 ++++--- src/main/java/{ => dude}/Tasks/Todo.java | 7 ++++--- src/main/java/{ => dude}/Utils/Storage.java | 5 ++--- src/main/java/{ => dude}/Utils/Ui.java | 4 ++-- src/main/java/{ => dude}/Utils/utils.java | 2 +- text-ui-test/EXPECTED.TXT | 2 +- text-ui-test/runtest.bat | 2 +- 30 files changed, 83 insertions(+), 90 deletions(-) rename src/main/java/{ => dude}/Commands/ByeCommand.java (93%) rename src/main/java/{ => dude}/Commands/Command.java (88%) rename src/main/java/{ => dude}/Commands/CommandTypes.java (85%) rename src/main/java/{ => dude}/Commands/DeadlineCommand.java (87%) rename src/main/java/{ => dude}/Commands/DeleteCommand.java (89%) rename src/main/java/{ => dude}/Commands/EventCommand.java (87%) rename src/main/java/{ => dude}/Commands/HelpCommand.java (98%) rename src/main/java/{ => dude}/Commands/InvalidCommand.java (93%) rename src/main/java/{ => dude}/Commands/ListCommand.java (89%) rename src/main/java/{ => dude}/Commands/MarkCommand.java (88%) rename src/main/java/{ => dude}/Commands/Parser.java (94%) rename src/main/java/{ => dude}/Commands/TodoCommand.java (86%) rename src/main/java/{ => dude}/Commands/UnmarkCommand.java (88%) rename src/main/java/{ => dude}/Dude.java (90%) rename src/main/java/{ => dude}/Exceptions/DudeException.java (82%) rename src/main/java/{ => dude}/Exceptions/InvalidArgumentException.java (80%) rename src/main/java/{ => dude}/Exceptions/InvalidCommandException.java (78%) rename src/main/java/{ => dude}/Exceptions/InvalidDescriptionException.java (79%) rename src/main/java/{ => dude}/Exceptions/InvalidFormatException.java (92%) rename src/main/java/{ => dude}/Exceptions/TaskListFullException.java (78%) rename src/main/java/{ => dude}/Tasks/Deadline.java (92%) rename src/main/java/{ => dude}/Tasks/Event.java (93%) rename src/main/java/{ => dude}/Tasks/Task.java (98%) rename src/main/java/{ => dude}/Tasks/TaskList.java (97%) rename src/main/java/{ => dude}/Tasks/Todo.java (89%) rename src/main/java/{ => dude}/Utils/Storage.java (98%) rename src/main/java/{ => dude}/Utils/Ui.java (89%) rename src/main/java/{ => dude}/Utils/utils.java (98%) diff --git a/src/main/java/Commands/ByeCommand.java b/src/main/java/dude/Commands/ByeCommand.java similarity index 93% rename from src/main/java/Commands/ByeCommand.java rename to src/main/java/dude/Commands/ByeCommand.java index aa320fd50a..d1297032c2 100644 --- a/src/main/java/Commands/ByeCommand.java +++ b/src/main/java/dude/Commands/ByeCommand.java @@ -1,4 +1,4 @@ -package Commands; +package dude.Commands; public class ByeCommand extends Command { diff --git a/src/main/java/Commands/Command.java b/src/main/java/dude/Commands/Command.java similarity index 88% rename from src/main/java/Commands/Command.java rename to src/main/java/dude/Commands/Command.java index babd5360aa..46d90fcf6b 100644 --- a/src/main/java/Commands/Command.java +++ b/src/main/java/dude/Commands/Command.java @@ -1,6 +1,6 @@ -package Commands; +package dude.Commands; -import Exceptions.DudeException; +import dude.Exceptions.DudeException; public abstract class Command { diff --git a/src/main/java/Commands/CommandTypes.java b/src/main/java/dude/Commands/CommandTypes.java similarity index 85% rename from src/main/java/Commands/CommandTypes.java rename to src/main/java/dude/Commands/CommandTypes.java index 9aa6306dc9..db5f47fe95 100644 --- a/src/main/java/Commands/CommandTypes.java +++ b/src/main/java/dude/Commands/CommandTypes.java @@ -1,4 +1,4 @@ -package Commands; +package dude.Commands; public enum CommandTypes { BYE, diff --git a/src/main/java/Commands/DeadlineCommand.java b/src/main/java/dude/Commands/DeadlineCommand.java similarity index 87% rename from src/main/java/Commands/DeadlineCommand.java rename to src/main/java/dude/Commands/DeadlineCommand.java index fdc9cc4560..d85c7b5d38 100644 --- a/src/main/java/Commands/DeadlineCommand.java +++ b/src/main/java/dude/Commands/DeadlineCommand.java @@ -1,9 +1,9 @@ -package Commands; +package dude.Commands; -import Exceptions.DudeException; -import Exceptions.InvalidFormatException; -import Tasks.Deadline; -import Tasks.TaskList; +import dude.Exceptions.DudeException; +import dude.Exceptions.InvalidFormatException; +import dude.Tasks.Deadline; +import dude.Tasks.TaskList; public class DeadlineCommand extends Command { private final String input; diff --git a/src/main/java/Commands/DeleteCommand.java b/src/main/java/dude/Commands/DeleteCommand.java similarity index 89% rename from src/main/java/Commands/DeleteCommand.java rename to src/main/java/dude/Commands/DeleteCommand.java index 366b9fb598..b83e976bcf 100644 --- a/src/main/java/Commands/DeleteCommand.java +++ b/src/main/java/dude/Commands/DeleteCommand.java @@ -1,9 +1,9 @@ -package Commands; +package dude.Commands; -import Exceptions.DudeException; -import Exceptions.InvalidFormatException; -import Tasks.Task; -import Tasks.TaskList; +import dude.Exceptions.DudeException; +import dude.Exceptions.InvalidFormatException; +import dude.Tasks.Task; +import dude.Tasks.TaskList; public class DeleteCommand extends Command { private final String input; diff --git a/src/main/java/Commands/EventCommand.java b/src/main/java/dude/Commands/EventCommand.java similarity index 87% rename from src/main/java/Commands/EventCommand.java rename to src/main/java/dude/Commands/EventCommand.java index 1d92b65e73..a8308f2f9f 100644 --- a/src/main/java/Commands/EventCommand.java +++ b/src/main/java/dude/Commands/EventCommand.java @@ -1,9 +1,9 @@ -package Commands; +package dude.Commands; -import Exceptions.DudeException; -import Exceptions.InvalidFormatException; -import Tasks.Event; -import Tasks.TaskList; +import dude.Exceptions.DudeException; +import dude.Exceptions.InvalidFormatException; +import dude.Tasks.Event; +import dude.Tasks.TaskList; public class EventCommand extends Command { private final String input; diff --git a/src/main/java/Commands/HelpCommand.java b/src/main/java/dude/Commands/HelpCommand.java similarity index 98% rename from src/main/java/Commands/HelpCommand.java rename to src/main/java/dude/Commands/HelpCommand.java index af9f9715f4..f241fc5530 100644 --- a/src/main/java/Commands/HelpCommand.java +++ b/src/main/java/dude/Commands/HelpCommand.java @@ -1,6 +1,6 @@ -package Commands; +package dude.Commands; -import Exceptions.DudeException; +import dude.Exceptions.DudeException; public class HelpCommand extends Command { diff --git a/src/main/java/Commands/InvalidCommand.java b/src/main/java/dude/Commands/InvalidCommand.java similarity index 93% rename from src/main/java/Commands/InvalidCommand.java rename to src/main/java/dude/Commands/InvalidCommand.java index d39606e75b..0bfe9df0d8 100644 --- a/src/main/java/Commands/InvalidCommand.java +++ b/src/main/java/dude/Commands/InvalidCommand.java @@ -1,4 +1,4 @@ -package Commands; +package dude.Commands; public class InvalidCommand extends Command { diff --git a/src/main/java/Commands/ListCommand.java b/src/main/java/dude/Commands/ListCommand.java similarity index 89% rename from src/main/java/Commands/ListCommand.java rename to src/main/java/dude/Commands/ListCommand.java index d114dd2f64..66d48eb603 100644 --- a/src/main/java/Commands/ListCommand.java +++ b/src/main/java/dude/Commands/ListCommand.java @@ -1,6 +1,6 @@ -package Commands; +package dude.Commands; -import Tasks.TaskList; +import dude.Tasks.TaskList; public class ListCommand extends Command { diff --git a/src/main/java/Commands/MarkCommand.java b/src/main/java/dude/Commands/MarkCommand.java similarity index 88% rename from src/main/java/Commands/MarkCommand.java rename to src/main/java/dude/Commands/MarkCommand.java index bccd6f97e7..5771a16487 100644 --- a/src/main/java/Commands/MarkCommand.java +++ b/src/main/java/dude/Commands/MarkCommand.java @@ -1,9 +1,9 @@ -package Commands; +package dude.Commands; -import Exceptions.DudeException; -import Exceptions.InvalidFormatException; -import Tasks.Task; -import Tasks.TaskList; +import dude.Exceptions.DudeException; +import dude.Exceptions.InvalidFormatException; +import dude.Tasks.Task; +import dude.Tasks.TaskList; public class MarkCommand extends Command { diff --git a/src/main/java/Commands/Parser.java b/src/main/java/dude/Commands/Parser.java similarity index 94% rename from src/main/java/Commands/Parser.java rename to src/main/java/dude/Commands/Parser.java index 4bc620ad6e..31294f2841 100644 --- a/src/main/java/Commands/Parser.java +++ b/src/main/java/dude/Commands/Parser.java @@ -1,6 +1,6 @@ -package Commands; +package dude.Commands; -import Tasks.TaskList; +import dude.Tasks.TaskList; public class Parser { diff --git a/src/main/java/Commands/TodoCommand.java b/src/main/java/dude/Commands/TodoCommand.java similarity index 86% rename from src/main/java/Commands/TodoCommand.java rename to src/main/java/dude/Commands/TodoCommand.java index 34c808a394..22b3a4656e 100644 --- a/src/main/java/Commands/TodoCommand.java +++ b/src/main/java/dude/Commands/TodoCommand.java @@ -1,9 +1,9 @@ -package Commands; +package dude.Commands; -import Exceptions.DudeException; -import Exceptions.InvalidFormatException; -import Tasks.TaskList; -import Tasks.Todo; +import dude.Exceptions.DudeException; +import dude.Exceptions.InvalidFormatException; +import dude.Tasks.TaskList; +import dude.Tasks.Todo; public class TodoCommand extends Command { diff --git a/src/main/java/Commands/UnmarkCommand.java b/src/main/java/dude/Commands/UnmarkCommand.java similarity index 88% rename from src/main/java/Commands/UnmarkCommand.java rename to src/main/java/dude/Commands/UnmarkCommand.java index dfead4c5a9..e1f24b0b84 100644 --- a/src/main/java/Commands/UnmarkCommand.java +++ b/src/main/java/dude/Commands/UnmarkCommand.java @@ -1,9 +1,9 @@ -package Commands; +package dude.Commands; -import Exceptions.DudeException; -import Exceptions.InvalidFormatException; -import Tasks.Task; -import Tasks.TaskList; +import dude.Exceptions.DudeException; +import dude.Exceptions.InvalidFormatException; +import dude.Tasks.Task; +import dude.Tasks.TaskList; public class UnmarkCommand extends Command { diff --git a/src/main/java/Dude.java b/src/main/java/dude/Dude.java similarity index 90% rename from src/main/java/Dude.java rename to src/main/java/dude/Dude.java index fb6f4b4fe9..02a3c9bff6 100644 --- a/src/main/java/Dude.java +++ b/src/main/java/dude/Dude.java @@ -1,10 +1,12 @@ -import Commands.Command; -import Commands.Parser; -import Exceptions.*; -import Tasks.TaskList; -import Commands.CommandTypes; -import Utils.Storage; -import Utils.Ui; +package dude; + +import dude.Commands.Command; +import dude.Commands.Parser; +import dude.Exceptions.*; +import dude.Tasks.TaskList; +import dude.Commands.CommandTypes; +import dude.Utils.Storage; +import dude.Utils.Ui; import java.util.NoSuchElementException; import java.util.Scanner; diff --git a/src/main/java/Exceptions/DudeException.java b/src/main/java/dude/Exceptions/DudeException.java similarity index 82% rename from src/main/java/Exceptions/DudeException.java rename to src/main/java/dude/Exceptions/DudeException.java index 75cbd46164..0211d5b689 100644 --- a/src/main/java/Exceptions/DudeException.java +++ b/src/main/java/dude/Exceptions/DudeException.java @@ -1,4 +1,4 @@ -package Exceptions; +package dude.Exceptions; public class DudeException extends Exception{ public DudeException(String message) { diff --git a/src/main/java/Exceptions/InvalidArgumentException.java b/src/main/java/dude/Exceptions/InvalidArgumentException.java similarity index 80% rename from src/main/java/Exceptions/InvalidArgumentException.java rename to src/main/java/dude/Exceptions/InvalidArgumentException.java index 4ae96e6e18..d36cd9294f 100644 --- a/src/main/java/Exceptions/InvalidArgumentException.java +++ b/src/main/java/dude/Exceptions/InvalidArgumentException.java @@ -1,6 +1,4 @@ -package Exceptions; - -import Exceptions.DudeException; +package dude.Exceptions; public class InvalidArgumentException extends DudeException { //Used to indicate that an argument for the command is invalid diff --git a/src/main/java/Exceptions/InvalidCommandException.java b/src/main/java/dude/Exceptions/InvalidCommandException.java similarity index 78% rename from src/main/java/Exceptions/InvalidCommandException.java rename to src/main/java/dude/Exceptions/InvalidCommandException.java index ab9093b7a8..5e99fe9898 100644 --- a/src/main/java/Exceptions/InvalidCommandException.java +++ b/src/main/java/dude/Exceptions/InvalidCommandException.java @@ -1,6 +1,4 @@ -package Exceptions; - -import Exceptions.DudeException; +package dude.Exceptions; public class InvalidCommandException extends DudeException { //Used to indicate that the command is invalid diff --git a/src/main/java/Exceptions/InvalidDescriptionException.java b/src/main/java/dude/Exceptions/InvalidDescriptionException.java similarity index 79% rename from src/main/java/Exceptions/InvalidDescriptionException.java rename to src/main/java/dude/Exceptions/InvalidDescriptionException.java index 16c720f560..67e8cc33cd 100644 --- a/src/main/java/Exceptions/InvalidDescriptionException.java +++ b/src/main/java/dude/Exceptions/InvalidDescriptionException.java @@ -1,6 +1,4 @@ -package Exceptions; - -import Exceptions.DudeException; +package dude.Exceptions; public class InvalidDescriptionException extends DudeException { //Used to indicate that the description is invalid diff --git a/src/main/java/Exceptions/InvalidFormatException.java b/src/main/java/dude/Exceptions/InvalidFormatException.java similarity index 92% rename from src/main/java/Exceptions/InvalidFormatException.java rename to src/main/java/dude/Exceptions/InvalidFormatException.java index 5801663535..a43853ef36 100644 --- a/src/main/java/Exceptions/InvalidFormatException.java +++ b/src/main/java/dude/Exceptions/InvalidFormatException.java @@ -1,6 +1,4 @@ -package Exceptions; - -import Exceptions.DudeException; +package dude.Exceptions; public class InvalidFormatException extends DudeException { diff --git a/src/main/java/Exceptions/TaskListFullException.java b/src/main/java/dude/Exceptions/TaskListFullException.java similarity index 78% rename from src/main/java/Exceptions/TaskListFullException.java rename to src/main/java/dude/Exceptions/TaskListFullException.java index d0dcb5e18e..ae77ecc3cf 100644 --- a/src/main/java/Exceptions/TaskListFullException.java +++ b/src/main/java/dude/Exceptions/TaskListFullException.java @@ -1,6 +1,4 @@ -package Exceptions; - -import Exceptions.DudeException; +package dude.Exceptions; public class TaskListFullException extends DudeException { //Used to indicate that the task list is full diff --git a/src/main/java/Tasks/Deadline.java b/src/main/java/dude/Tasks/Deadline.java similarity index 92% rename from src/main/java/Tasks/Deadline.java rename to src/main/java/dude/Tasks/Deadline.java index 7ee1ab9d38..ba4ce8d973 100644 --- a/src/main/java/Tasks/Deadline.java +++ b/src/main/java/dude/Tasks/Deadline.java @@ -1,9 +1,9 @@ -package Tasks; +package dude.Tasks; -import Exceptions.InvalidArgumentException; -import Exceptions.InvalidDescriptionException; -import Exceptions.InvalidFormatException; -import Utils.utils; +import dude.Exceptions.InvalidArgumentException; +import dude.Exceptions.InvalidDescriptionException; +import dude.Exceptions.InvalidFormatException; +import dude.Utils.utils; import java.time.LocalDateTime; import java.time.format.DateTimeParseException; diff --git a/src/main/java/Tasks/Event.java b/src/main/java/dude/Tasks/Event.java similarity index 93% rename from src/main/java/Tasks/Event.java rename to src/main/java/dude/Tasks/Event.java index 0f9517d8e8..dfba355d21 100644 --- a/src/main/java/Tasks/Event.java +++ b/src/main/java/dude/Tasks/Event.java @@ -1,10 +1,10 @@ -package Tasks; +package dude.Tasks; -import Commands.EventCommand; -import Exceptions.InvalidArgumentException; -import Exceptions.InvalidDescriptionException; -import Exceptions.InvalidFormatException; -import Utils.utils; +import dude.Commands.EventCommand; +import dude.Exceptions.InvalidArgumentException; +import dude.Exceptions.InvalidDescriptionException; +import dude.Exceptions.InvalidFormatException; +import dude.Utils.utils; import java.time.LocalDateTime; import java.time.format.DateTimeParseException; diff --git a/src/main/java/Tasks/Task.java b/src/main/java/dude/Tasks/Task.java similarity index 98% rename from src/main/java/Tasks/Task.java rename to src/main/java/dude/Tasks/Task.java index 59392f0291..0fe8362216 100644 --- a/src/main/java/Tasks/Task.java +++ b/src/main/java/dude/Tasks/Task.java @@ -1,4 +1,4 @@ -package Tasks; +package dude.Tasks; import java.io.Serializable; import java.time.LocalDate; diff --git a/src/main/java/Tasks/TaskList.java b/src/main/java/dude/Tasks/TaskList.java similarity index 97% rename from src/main/java/Tasks/TaskList.java rename to src/main/java/dude/Tasks/TaskList.java index b752df433d..31a4403319 100644 --- a/src/main/java/Tasks/TaskList.java +++ b/src/main/java/dude/Tasks/TaskList.java @@ -1,8 +1,9 @@ -package Tasks; +package dude.Tasks; -import Exceptions.DudeException; +import dude.Exceptions.DudeException; import java.util.ArrayList; -import Exceptions.TaskListFullException; + +import dude.Exceptions.TaskListFullException; public class TaskList { diff --git a/src/main/java/Tasks/Todo.java b/src/main/java/dude/Tasks/Todo.java similarity index 89% rename from src/main/java/Tasks/Todo.java rename to src/main/java/dude/Tasks/Todo.java index 36000c680a..75e35cc3d8 100644 --- a/src/main/java/Tasks/Todo.java +++ b/src/main/java/dude/Tasks/Todo.java @@ -1,6 +1,7 @@ -package Tasks; -import Exceptions.InvalidDescriptionException; -import Utils.utils; +package dude.Tasks; + +import dude.Exceptions.InvalidDescriptionException; +import dude.Utils.utils; public class Todo extends Task { diff --git a/src/main/java/Utils/Storage.java b/src/main/java/dude/Utils/Storage.java similarity index 98% rename from src/main/java/Utils/Storage.java rename to src/main/java/dude/Utils/Storage.java index ae0f95fba1..c7caadd5a4 100644 --- a/src/main/java/Utils/Storage.java +++ b/src/main/java/dude/Utils/Storage.java @@ -1,6 +1,6 @@ -package Utils; +package dude.Utils; -import Tasks.*; +import dude.Tasks.*; import java.io.*; import java.util.ArrayList; @@ -29,7 +29,6 @@ private void createStorageIfNotExists() throws IOException, SecurityException { File file = new File(this.filepath + this.filename); boolean fileExists = file.exists(); - //save an empty task list to the file if it does not exist if (!fileExists) { saveTasks(new TaskList()); diff --git a/src/main/java/Utils/Ui.java b/src/main/java/dude/Utils/Ui.java similarity index 89% rename from src/main/java/Utils/Ui.java rename to src/main/java/dude/Utils/Ui.java index 87a9023c96..9082588b28 100644 --- a/src/main/java/Utils/Ui.java +++ b/src/main/java/dude/Utils/Ui.java @@ -1,11 +1,11 @@ -package Utils; +package dude.Utils; public class Ui { public void showWelcome() { String msg = "\t-----------------------------------\n" + - "\t\tHello! I'm Dude\n" + + "\t\tHello! I'm dude.Dude\n" + "\t\tWhat can I do for you?\n" + "\t-----------------------------------\n"; System.out.println(msg); diff --git a/src/main/java/Utils/utils.java b/src/main/java/dude/Utils/utils.java similarity index 98% rename from src/main/java/Utils/utils.java rename to src/main/java/dude/Utils/utils.java index 756320dd0c..acb9f4a242 100644 --- a/src/main/java/Utils/utils.java +++ b/src/main/java/dude/Utils/utils.java @@ -1,4 +1,4 @@ -package Utils; +package dude.Utils; public class utils { diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 1c4f3d7f6e..6aacbef2fa 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,5 +1,5 @@ ----------------------------------- - Hello! I'm Dude + Hello! I'm dude.Dude What can I do for you? ----------------------------------- diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat index bd6d4bcdca..056b3f9c60 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 Dude < input.txt > ACTUAL.TXT +java -classpath ..\bin dude.Dude < input.txt > ACTUAL.TXT REM compare the output to the expected output FC ACTUAL.TXT EXPECTED.TXT From 4f20ed0b04abbb05963a650cc23c3e106233a9f1 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 18 Feb 2024 19:10:05 +0800 Subject: [PATCH 067/153] updated build.gradle --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index a388517ae1..bd63e649fc 100644 --- a/build.gradle +++ b/build.gradle @@ -28,11 +28,11 @@ test { } application { - mainClass.set("seedu.duke.Duke") + mainClass.set("ip.dude.Dude") } shadowJar { - archiveBaseName = "duke" + archiveBaseName = "dude" archiveClassifier = null dependsOn("distZip", "distTar") } From 7fef014a6d8c03ea722a130a9321f80e9b48dd74 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 18 Feb 2024 19:29:22 +0800 Subject: [PATCH 068/153] Added Checksyle. Changed Style for Dude.java --- build.gradle | 5 + config/checkstyle/checkstyle.xml | 435 +++++++++++++++++++++++++++++ config/checkstyle/suppressions.xml | 10 + src/main/java/dude/Dude.java | 18 +- 4 files changed, 459 insertions(+), 9 deletions(-) create mode 100644 config/checkstyle/checkstyle.xml create mode 100644 config/checkstyle/suppressions.xml diff --git a/build.gradle b/build.gradle index bd63e649fc..9ce0bfbdce 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' } @@ -40,3 +41,7 @@ shadowJar { run{ standardInput = System.in } + +checkstyle { + toolVersion = '10.2' +} diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml new file mode 100644 index 0000000000..d732949de8 --- /dev/null +++ b/config/checkstyle/checkstyle.xml @@ -0,0 +1,435 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/checkstyle/suppressions.xml b/config/checkstyle/suppressions.xml new file mode 100644 index 0000000000..135ea49ee0 --- /dev/null +++ b/config/checkstyle/suppressions.xml @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/src/main/java/dude/Dude.java b/src/main/java/dude/Dude.java index 02a3c9bff6..14033c7ecb 100644 --- a/src/main/java/dude/Dude.java +++ b/src/main/java/dude/Dude.java @@ -1,24 +1,25 @@ package dude; +import java.util.NoSuchElementException; +import java.util.Scanner; + import dude.Commands.Command; +import dude.Commands.CommandTypes; import dude.Commands.Parser; -import dude.Exceptions.*; +import dude.Exceptions.DudeException; import dude.Tasks.TaskList; -import dude.Commands.CommandTypes; import dude.Utils.Storage; import dude.Utils.Ui; -import java.util.NoSuchElementException; -import java.util.Scanner; -public class Dude { +public class Dude { private final TaskList taskList; private final Storage storage; private final Ui ui; private boolean isRunning = true; - public Dude(String filePath){ + public Dude(String filePath) { this.storage = new Storage(filePath); this.ui = new Ui(); @@ -38,8 +39,7 @@ public void run() { ui.showWelcome(); Scanner sc = new Scanner(System.in); - while(this.isRunning){ - + while (this.isRunning) { String input = extractInput(sc); Command command = Parser.parse(input, taskList); @@ -58,7 +58,7 @@ private static String extractInput(Scanner sc) { String input = ""; try { input = sc.nextLine(); - }catch(NoSuchElementException e){ + } catch (NoSuchElementException e) { //this will not be handled. App will only exit at bye command. input = ""; } From bceb8f0648bb8dfc4a8e6160c413905eabe75c82 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 26 Feb 2024 20:50:37 +0800 Subject: [PATCH 069/153] Added tests for Storage and Parser --- src/test/java/dude/Commands/ParserTest.java | 89 +++++++++++++++++++++ src/test/java/dude/DudeTest.java | 4 + src/test/java/dude/Utils/StorageTest.java | 46 +++++++++++ 3 files changed, 139 insertions(+) create mode 100644 src/test/java/dude/Commands/ParserTest.java create mode 100644 src/test/java/dude/DudeTest.java create mode 100644 src/test/java/dude/Utils/StorageTest.java diff --git a/src/test/java/dude/Commands/ParserTest.java b/src/test/java/dude/Commands/ParserTest.java new file mode 100644 index 0000000000..9c42a8480e --- /dev/null +++ b/src/test/java/dude/Commands/ParserTest.java @@ -0,0 +1,89 @@ +package dude.Commands; + +import dude.Exceptions.DudeException; +import dude.Exceptions.InvalidDescriptionException; +import dude.Exceptions.TaskListFullException; +import dude.Tasks.TaskList; +import dude.Tasks.Todo; +import org.junit.jupiter.api.Test; + +public class ParserTest { + + @Test + public void testParsingListCommand() { + TaskList taskList = new TaskList(); + String input = "list"; + + Command command = Parser.parse(input, taskList); + assert (command instanceof ListCommand); + } + + @Test + public void testParsingByeCommand() { + TaskList taskList = new TaskList(); + String input = "bye"; + + Command command = Parser.parse(input, taskList); + assert (command instanceof ByeCommand); + } + + @Test + public void testParsingDeleteCommand() throws DudeException { + + //add a task to the tasklist + TaskList taskList = new TaskList(); + taskList.add_task(Todo.from("todo test")); + + String input = "delete 1"; + + Command command = Parser.parse(input, taskList); + assert (command instanceof DeleteCommand); + } + + @Test + public void testParsingTodoCommand() { + TaskList taskList = new TaskList(); + String input = "todo test"; + + Command command = Parser.parse(input, taskList); + assert (command instanceof TodoCommand); + } + + @Test + public void testParsingDeadlineCommand() { + TaskList taskList = new TaskList(); + String input = "deadline test /by 2020-12-12"; + + Command command = Parser.parse(input, taskList); + assert (command instanceof DeadlineCommand); + } + + @Test + public void testParsingEventCommand() { + TaskList taskList = new TaskList(); + String input = "event test /from 2/12/2020 1800 /to 2/12/2020 1900"; + + Command command = Parser.parse(input, taskList); + assert (command instanceof EventCommand); + } + + @Test + public void testParsingMarkCommand() throws InvalidDescriptionException, TaskListFullException { + TaskList taskList = new TaskList(); + taskList.add_task(Todo.from("todo test")); + String input = "mark 1"; + + Command command = Parser.parse(input, taskList); + assert (command instanceof MarkCommand); + } + + @Test + public void testParsingUnmarkCommand() throws InvalidDescriptionException, TaskListFullException { + TaskList taskList = new TaskList(); + taskList.add_task(Todo.from("todo test")); + String input = "unmark 1"; + + Command command = Parser.parse(input, taskList); + assert (command instanceof UnmarkCommand); + } +} diff --git a/src/test/java/dude/DudeTest.java b/src/test/java/dude/DudeTest.java new file mode 100644 index 0000000000..781692e6af --- /dev/null +++ b/src/test/java/dude/DudeTest.java @@ -0,0 +1,4 @@ +package dude; + +public class DudeTest { +} diff --git a/src/test/java/dude/Utils/StorageTest.java b/src/test/java/dude/Utils/StorageTest.java new file mode 100644 index 0000000000..59698200ed --- /dev/null +++ b/src/test/java/dude/Utils/StorageTest.java @@ -0,0 +1,46 @@ +package dude.Utils; + +import dude.Exceptions.TaskListFullException; +import dude.Tasks.Task; +import dude.Tasks.TaskList; +import dude.Tasks.Todo; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class StorageTest { + + @Test + public void testSavingAndLoadingTasks() throws TaskListFullException { + Storage storage = new Storage("data/testdata.ser"); + + TaskList taskList = new TaskList(); + taskList.add_task(new Todo("test")); + taskList.add_task(new Todo("test2")); + taskList.add_task(new Todo("test3")); + + try { + storage.saveTasks(taskList); + } catch (Exception e) { + assert (false); + } + + TaskList loadedTaskList = null; + try { + loadedTaskList = storage.loadTasks(); + } catch (Exception e) { + assert (false); + } + + //checked if the loaded tasks from the + ArrayList expected = taskList.getList(); + ArrayList actual = loadedTaskList.getList(); + + System.out.println(expected); + System.out.println(actual); + + assertEquals(taskList.getList(), loadedTaskList.getList()); + } +} From 1749a88da8acb5d7e8c8ff351ff586e5d4325b30 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 26 Feb 2024 20:52:00 +0800 Subject: [PATCH 070/153] Added .equals for Todo --- src/main/java/dude/Tasks/Todo.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/main/java/dude/Tasks/Todo.java b/src/main/java/dude/Tasks/Todo.java index 75e35cc3d8..e61d8e5ce3 100644 --- a/src/main/java/dude/Tasks/Todo.java +++ b/src/main/java/dude/Tasks/Todo.java @@ -36,4 +36,13 @@ public void markAsUndone() { public String toString() { return "[T]" + super.toString(); } + + @Override + public boolean equals(Object o) { + if (o instanceof Todo) { + Todo t = (Todo) o; + return t.getDescription().equals(this.getDescription()); + } + return false; + } } From a78c4907b0ad1b2efe19b1216cad32cd1ac5abf6 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 26 Feb 2024 20:59:09 +0800 Subject: [PATCH 071/153] Added Test cases for Todo Task --- src/test/java/dude/Tasks/TodoTest.java | 28 ++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/test/java/dude/Tasks/TodoTest.java diff --git a/src/test/java/dude/Tasks/TodoTest.java b/src/test/java/dude/Tasks/TodoTest.java new file mode 100644 index 0000000000..cc51e51de8 --- /dev/null +++ b/src/test/java/dude/Tasks/TodoTest.java @@ -0,0 +1,28 @@ +package dude.Tasks; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class TodoTest { + + @Test + public void testToString() { + Todo todo = new Todo("test"); + assertEquals(todo.toString(), "[T][ ] test"); + } + + @Test + public void testEqualsForSameDescription() { + Todo todo = new Todo("test description"); + Todo todo2 = new Todo("test description"); + assertEquals(todo, todo2); + } + + @Test + public void testEqualsForDifferentDescription() { + Todo todo = new Todo("test description"); + Todo todo2 = new Todo("other description"); + assertNotEquals(todo, todo2); + } +} From d111cfd208837bb46536e9190a3a885b9251dc04 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 26 Feb 2024 21:04:48 +0800 Subject: [PATCH 072/153] Added Test cases for Deadline --- src/main/java/dude/Tasks/Deadline.java | 9 ++++++ src/test/java/dude/Tasks/DeadlineTest.java | 35 ++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 src/test/java/dude/Tasks/DeadlineTest.java diff --git a/src/main/java/dude/Tasks/Deadline.java b/src/main/java/dude/Tasks/Deadline.java index ba4ce8d973..b24bc2d2cc 100644 --- a/src/main/java/dude/Tasks/Deadline.java +++ b/src/main/java/dude/Tasks/Deadline.java @@ -78,4 +78,13 @@ public String toString() { public LocalDateTime getBy() { return deadline_date; } + + @Override + public boolean equals(Object o) { + if (o instanceof Deadline) { + Deadline t = (Deadline) o; + return t.getDescription().equals(this.getDescription()) && t.getBy().equals(this.getBy()); + } + return false; + } } diff --git a/src/test/java/dude/Tasks/DeadlineTest.java b/src/test/java/dude/Tasks/DeadlineTest.java new file mode 100644 index 0000000000..9398a1dfd2 --- /dev/null +++ b/src/test/java/dude/Tasks/DeadlineTest.java @@ -0,0 +1,35 @@ +package dude.Tasks; + +import org.junit.jupiter.api.Test; + +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.*; + +public class DeadlineTest { + + @Test + public void testToString() { + LocalDateTime dt = LocalDateTime.parse("2020-12-12T18:00"); + Deadline deadline = new Deadline("test", dt); + assertEquals("[D][ ] test (by: Dec 12, 2020 @ 6:00PM)", deadline.toString()); + } + + @Test + public void testEqualsCorretScenario() { + LocalDateTime dt = LocalDateTime.parse("2020-12-12T18:00"); + Deadline deadline = new Deadline("test", dt); + Deadline deadline2 = new Deadline("test", dt); + assertEquals(deadline, deadline2); + } + + @Test + public void testEqualsWrongScenario() { + LocalDateTime dt = LocalDateTime.parse("2020-12-12T18:00"); + Deadline deadline = new Deadline("test", dt); + Deadline deadline2 = new Deadline("test2", dt); + assertNotEquals(deadline, deadline2); + } + + +} From 273dc75c0b8ebf3cff609c5d8c32341367b342c3 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 26 Feb 2024 21:11:56 +0800 Subject: [PATCH 073/153] Added equals method --- src/main/java/dude/Tasks/Event.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/dude/Tasks/Event.java b/src/main/java/dude/Tasks/Event.java index dfba355d21..94c57414e3 100644 --- a/src/main/java/dude/Tasks/Event.java +++ b/src/main/java/dude/Tasks/Event.java @@ -99,4 +99,18 @@ public LocalDateTime getFromTime() { public LocalDateTime getToTime() { return to_time; } + + @Override + public boolean equals(Object o) { + if (o instanceof Event) { + Event t = (Event) o; + + boolean isDescriptionEqual = t.getDescription().equals(this.getDescription()); + boolean isFromTimeEqual = t.getFromTime().equals(this.getFromTime()); + boolean isToTimeEqual = t.getToTime().equals(this.getToTime()); + + return isDescriptionEqual && isFromTimeEqual && isToTimeEqual; + } + return false; + } } From a30505e46519192b85830f458641b9f66fc07abd Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 26 Feb 2024 21:12:16 +0800 Subject: [PATCH 074/153] changed method spelling mistake for deadline test --- src/test/java/dude/Tasks/DeadlineTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/dude/Tasks/DeadlineTest.java b/src/test/java/dude/Tasks/DeadlineTest.java index 9398a1dfd2..065b271d7d 100644 --- a/src/test/java/dude/Tasks/DeadlineTest.java +++ b/src/test/java/dude/Tasks/DeadlineTest.java @@ -16,7 +16,7 @@ public void testToString() { } @Test - public void testEqualsCorretScenario() { + public void testEqualsCorrectScenario() { LocalDateTime dt = LocalDateTime.parse("2020-12-12T18:00"); Deadline deadline = new Deadline("test", dt); Deadline deadline2 = new Deadline("test", dt); From cea57bda2a2542a1944f73043d08c4132d017388 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 26 Feb 2024 21:12:37 +0800 Subject: [PATCH 075/153] Added test cases for event class --- src/test/java/dude/Tasks/EventTest.java | 45 +++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/test/java/dude/Tasks/EventTest.java diff --git a/src/test/java/dude/Tasks/EventTest.java b/src/test/java/dude/Tasks/EventTest.java new file mode 100644 index 0000000000..1f4ffc3bb6 --- /dev/null +++ b/src/test/java/dude/Tasks/EventTest.java @@ -0,0 +1,45 @@ +package dude.Tasks; + +import org.junit.jupiter.api.Test; + +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; + +public class EventTest { + + @Test + public void testToString() { + LocalDateTime from = LocalDateTime.parse("2020-12-12T18:00"); + LocalDateTime to = LocalDateTime.parse("2020-12-18T20:00"); + Event event = new Event("test", from, to); + assertEquals("[E][ ] test (from: Dec 12, 2020 @ 6:00PM to: Dec 18, 2020 @ 8:00PM)", event.toString()); + } + + @Test + public void testEqualsCorrectScenario() { + LocalDateTime from = LocalDateTime.parse("2020-12-12T18:00"); + LocalDateTime to = LocalDateTime.parse("2020-12-18T20:00"); + Event event = new Event("test", from, to); + Event event2 = new Event("test", from, to); + assertEquals(event, event2); + } + + @Test + public void testEqualsWrongScenario() { + LocalDateTime from = LocalDateTime.parse("2020-12-12T18:00"); + LocalDateTime to = LocalDateTime.parse("2020-12-18T20:00"); + Event event = new Event("test", from, to); + Event event2 = new Event("test other description", from, to); + assertNotEquals(event, event2); + + LocalDateTime from2 = LocalDateTime.parse("2020-12-10T18:00"); + Event event3 = new Event("test", from2, to); + assertNotEquals(event, event3); + + LocalDateTime to2 = LocalDateTime.parse("2020-12-21T20:01"); + Event event4 = new Event("test", from, to2); + assertNotEquals(event, event4); + } +} From 5722427ff0bbe3c3e5b96f2e8283e683052acdb9 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 26 Feb 2024 21:30:14 +0800 Subject: [PATCH 076/153] Fixed main class not found bug. Fixed shadowJar error --- build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9ce0bfbdce..9316b94279 100644 --- a/build.gradle +++ b/build.gradle @@ -29,11 +29,12 @@ test { } application { - mainClass.set("ip.dude.Dude") + mainClass.set("dude.Dude") } shadowJar { archiveBaseName = "dude" + archiveFileName = "dude.jar" archiveClassifier = null dependsOn("distZip", "distTar") } From 801b077f0b5d1bf3cb6253b12b3a43049ce938db Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 26 Feb 2024 21:50:55 +0800 Subject: [PATCH 077/153] Added JavaDoc for Dude and Storage Classes --- src/main/java/dude/Dude.java | 23 +++++++++++++++++- src/main/java/dude/Utils/Storage.java | 34 ++++++++++++++++++++------- 2 files changed, 47 insertions(+), 10 deletions(-) diff --git a/src/main/java/dude/Dude.java b/src/main/java/dude/Dude.java index 14033c7ecb..89948b0d84 100644 --- a/src/main/java/dude/Dude.java +++ b/src/main/java/dude/Dude.java @@ -11,7 +11,14 @@ import dude.Utils.Storage; import dude.Utils.Ui; - +/** + * The main class of the Duke application. + *

+ * This class is responsible for the main logic of the application. + *

+ * The main loop of the application is responsible for reading user input, + * parsing it into a command, executing the command and saving the task list to disk. + **/ public class Dude { private final TaskList taskList; private final Storage storage; @@ -19,6 +26,14 @@ public class Dude { private boolean isRunning = true; + /** + * Constructor for the Dude class. + *

+ * The constructor initializes the storage and UI components of the application. + * It also loads the task list from the storage. + * + * @param filePath The file path to the storage file. + */ public Dude(String filePath) { this.storage = new Storage(filePath); this.ui = new Ui(); @@ -35,6 +50,12 @@ public Dude(String filePath) { this.taskList = temp; } + /** + * This method runs the main loop of the application. + *

+ * This method is responsible for reading user input, parsing it into a command, + * executing the command and saving the task list to disk. + */ public void run() { ui.showWelcome(); diff --git a/src/main/java/dude/Utils/Storage.java b/src/main/java/dude/Utils/Storage.java index c7caadd5a4..2db40d0f34 100644 --- a/src/main/java/dude/Utils/Storage.java +++ b/src/main/java/dude/Utils/Storage.java @@ -4,20 +4,29 @@ import java.io.*; import java.util.ArrayList; +/** + * The Storage class handles the loading and saving of task data to a storage file. + */ public class Storage { private final String filepath; private final String filename; + /** + * Constructor for the Storage class. + * + * @param fileLocation The file path to the storage file. + */ public Storage(String fileLocation) { - this.filepath = extractFilePath(fileLocation); this.filename = extractFileName(fileLocation); } /** * Creates a storage file if it does not exist. - * @throws IOException, SecurityException + * + * @throws IOException if an I/O error occurs + * @throws SecurityException if a security manager exists and its checkWrite method denies write access to the file. */ private void createStorageIfNotExists() throws IOException, SecurityException { File path = new File(this.filepath); @@ -38,7 +47,8 @@ private void createStorageIfNotExists() throws IOException, SecurityException { /** * Deletes the storage file if it exists. - * @throws SecurityException + * + * @throws SecurityException if a security manager exists and its checkWrite method denies write access to the file. */ public void deleteStorage() throws SecurityException { File file = new File(this.filepath + this.filename); @@ -50,26 +60,31 @@ public void deleteStorage() throws SecurityException { } } - + /** + * Saves the task list to the storage file. + * + * @param taskList The task list to be saved. + * @throws IOException if an I/O error occurs + * @throws SecurityException if a security manager exists and its checkWrite method denies write access to the file. + */ public void saveTasks(TaskList taskList) throws IOException, SecurityException { - try{ + try { FileOutputStream fos = new FileOutputStream(this.filepath + this.filename); - java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(fos); + ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(taskList.getList()); oos.close(); fos.close(); - } - catch (IOException e){ + } catch (IOException e) { throw new IOException("An error occurred while saving the task list."); } } /** * Loads the task list from the storage file. Returns empty task list if no task data is found. + * * @return TaskList * @throws IOException, ClassNotFoundException, SecurityException */ - @SuppressWarnings("unchecked") //safe as only ArrayList is written to the file public TaskList loadTasks() throws IOException, ClassNotFoundException, SecurityException { createStorageIfNotExists(); @@ -78,6 +93,7 @@ public TaskList loadTasks() throws IOException, ClassNotFoundException, Security FileInputStream fis = new FileInputStream(this.filepath + this.filename); ObjectInputStream ois = new ObjectInputStream(fis); + //noinspection unchecked list = (ArrayList) ois.readObject(); ois.close(); fis.close(); From 7bb835029f4b0f30fcbe1e4e01973d8cecaf8261 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 26 Feb 2024 21:56:14 +0800 Subject: [PATCH 078/153] added JavaDoc and coding style changes --- src/main/java/dude/Utils/Ui.java | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/main/java/dude/Utils/Ui.java b/src/main/java/dude/Utils/Ui.java index 9082588b28..ada4a13168 100644 --- a/src/main/java/dude/Utils/Ui.java +++ b/src/main/java/dude/Utils/Ui.java @@ -1,24 +1,34 @@ package dude.Utils; +/** + * The Ui class handles the user interface of the application. + */ public class Ui { + /** + * Displays the welcome message to system print stream. + */ public void showWelcome() { - String msg = "\t-----------------------------------\n" + - "\t\tHello! I'm dude.Dude\n" + - "\t\tWhat can I do for you?\n" + - "\t-----------------------------------\n"; + String msg = "\t-----------------------------------\n" + + "\t\tHello! I'm dude.Dude\n" + + "\t\tWhat can I do for you?\n" + + "\t-----------------------------------\n"; System.out.println(msg); } + /** + * Display a message to system print stream. + * + * @param msg The message to be displayed. + */ public void showMessage(String msg) { String temp = msg; temp = temp.replaceAll("\n", "\n\t\t"); - temp = "\t-----------------------------------\n" + - "\t\t" + temp + "\n" + - "\t-----------------------------------"; + temp = "\t\t" + "\t-----------------------------------\n" + temp + + "\n\t-----------------------------------"; System.out.println(temp); } } From 0d38f71f524eb44922a14034265657f016eadecf Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 26 Feb 2024 21:58:53 +0800 Subject: [PATCH 079/153] Fixed ordering of import statements following coding standard --- src/main/java/dude/Utils/Storage.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/dude/Utils/Storage.java b/src/main/java/dude/Utils/Storage.java index 2db40d0f34..120a2deed4 100644 --- a/src/main/java/dude/Utils/Storage.java +++ b/src/main/java/dude/Utils/Storage.java @@ -1,9 +1,17 @@ package dude.Utils; -import dude.Tasks.*; -import java.io.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.util.ArrayList; +import dude.Tasks.Task; +import dude.Tasks.TaskList; + + /** * The Storage class handles the loading and saving of task data to a storage file. */ From 12401197849baeeaf3539372a6afa1254ccf2234 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 26 Feb 2024 22:24:15 +0800 Subject: [PATCH 080/153] Added Javadoc to the Tasks package --- src/main/java/dude/Tasks/Deadline.java | 67 ++++++++++----- src/main/java/dude/Tasks/Event.java | 56 +++++++++++-- src/main/java/dude/Tasks/Task.java | 112 ++++++++++++++++--------- src/main/java/dude/Tasks/TaskList.java | 78 +++++++++++++---- src/main/java/dude/Tasks/Todo.java | 54 +++++++----- 5 files changed, 266 insertions(+), 101 deletions(-) diff --git a/src/main/java/dude/Tasks/Deadline.java b/src/main/java/dude/Tasks/Deadline.java index b24bc2d2cc..ebaf1cb5c9 100644 --- a/src/main/java/dude/Tasks/Deadline.java +++ b/src/main/java/dude/Tasks/Deadline.java @@ -8,8 +8,33 @@ import java.time.LocalDateTime; import java.time.format.DateTimeParseException; +/** + * The Deadline class represents a task with a description and a deadline. + */ public class Deadline extends Task { + private final LocalDateTime deadline_date; + + /** + * Constructor for the Deadline class. + * + * @param description The description of the deadline. + * @param by The deadline of the deadline. + */ + public Deadline(String description, LocalDateTime by) { + super(description); + this.deadline_date = by; + } + + /** + * Static method to create a Deadline object from parsing a string. + * + * @param s The string to be parsed into a Deadline object. + * @return The Deadline object created from the string. + * @throws InvalidFormatException If the format of the string is invalid. + * @throws InvalidDescriptionException If the description of the deadline is empty. + * @throws InvalidArgumentException If the 'by' of the deadline is empty. + */ public static Deadline from(String s) throws InvalidFormatException, InvalidDescriptionException, InvalidArgumentException { //Expects a string in the format "deadline /by " @@ -54,35 +79,35 @@ public static Deadline from(String s) throws InvalidFormatException, InvalidDesc } } - private final LocalDateTime deadline_date; - public Deadline(String description, LocalDateTime by) { - super(description); - this.deadline_date = by; - } - - @Override - public void markAsDone() { - super.markAsDone(); - } - - @Override - public void markAsUndone() { - super.markAsUndone(); + /** + * Returns the deadline of the Deadline object. + * + * @return The deadline date-time of the Deadline object. + */ + public LocalDateTime getBy() { + return deadline_date; } + /** + * Returns a string representation of the Deadline object. + * + * @return A string representation of the Deadline object. + */ @Override public String toString() { return "[D]" + super.toString() + " (by: " + formatDate(deadline_date) + ")"; } - public LocalDateTime getBy() { - return deadline_date; - } - + /** + * Returns whether the object is equal to this object. + * + * @param object The object to be compared. + * @return Whether the object is equal to this object. + */ @Override - public boolean equals(Object o) { - if (o instanceof Deadline) { - Deadline t = (Deadline) o; + public boolean equals(Object object) { + if (object instanceof Deadline) { + Deadline t = (Deadline) object; return t.getDescription().equals(this.getDescription()) && t.getBy().equals(this.getBy()); } return false; diff --git a/src/main/java/dude/Tasks/Event.java b/src/main/java/dude/Tasks/Event.java index 94c57414e3..f7a97cc500 100644 --- a/src/main/java/dude/Tasks/Event.java +++ b/src/main/java/dude/Tasks/Event.java @@ -9,12 +9,36 @@ import java.time.LocalDateTime; import java.time.format.DateTimeParseException; +/** + * The Event class represents a task with a description, start and end time. + */ public class Event extends Task { private final LocalDateTime from_time; private final LocalDateTime to_time; + /** + * Constructor for the Event class. + * + * @param description The description of the event. + * @param from_time The start time of the event. + * @param to_time The end time of the event. + */ + public Event(String description, LocalDateTime from_time, LocalDateTime to_time) { + super(description); + this.from_time = from_time; + this.to_time = to_time; + } + /** + * Static method to create an Event object from parsing a string. + * + * @param s The string to be parsed into an Event object. + * @return The Event object created from the string. + * @throws InvalidArgumentException If the 'from_time' or 'to_time' of the event is empty. + * @throws InvalidFormatException If the format of the string is invalid. + * @throws InvalidDescriptionException If the description of the event is empty. + */ public static Event from(String s) throws InvalidArgumentException, InvalidFormatException, InvalidDescriptionException { //Expects a string in the format "event /at to " @@ -81,29 +105,45 @@ public static Event from(String s) throws InvalidArgumentException, InvalidForma } } - public Event(String description, LocalDateTime from_time, LocalDateTime to_time) { - super(description); - this.from_time = from_time; - this.to_time = to_time; - } + /** + * Returns a string representation of the Event object. + * + * @return A string representation of the Event object. + */ @Override public String toString() { return "[E]" + super.toString() + " (from: " + formatDate(from_time) + " to: " + formatDate(to_time) + ")"; } + /** + * Returns the start time of the event. + * + * @return The start date-time of the event. + */ public LocalDateTime getFromTime() { return from_time; } + /** + * Returns the end date-time of the event. + * + * @return The end date-time of the event. + */ public LocalDateTime getToTime() { return to_time; } + /** + * Returns whether the object is equal to this object. + * + * @param object The object to be compared. + * @return Whether the object is equal to this object. + */ @Override - public boolean equals(Object o) { - if (o instanceof Event) { - Event t = (Event) o; + public boolean equals(Object object) { + if (object instanceof Event) { + Event t = (Event) object; boolean isDescriptionEqual = t.getDescription().equals(this.getDescription()); boolean isFromTimeEqual = t.getFromTime().equals(this.getFromTime()); diff --git a/src/main/java/dude/Tasks/Task.java b/src/main/java/dude/Tasks/Task.java index 0fe8362216..2f5058b4f2 100644 --- a/src/main/java/dude/Tasks/Task.java +++ b/src/main/java/dude/Tasks/Task.java @@ -10,50 +10,86 @@ public class Task implements Serializable { private final String description; private boolean isDone; - public Task(String description) { - this.description = description; - this.isDone = false; - } + /** + * Constructor for the Task class. + * + * @param description The description of the task. + */ + public Task(String description) { + this.description = description; + this.isDone = false; + } - public void markAsDone() { - this.isDone = true; - } + /** + * Mark the task as done. + */ + public void markAsDone() { + this.isDone = true; + } - public void markAsUndone() { - this.isDone = false; - } + /** + * Mark the task as undone. + */ + public void markAsUndone() { + this.isDone = false; + } - public String getDescription() { - return this.description; - } + /** + * Get the description of the task. + * + * @return The string description of the task. + */ + public String getDescription() { + return this.description; + } - private String getStatusIcon() { - return (isDone ? "X" : " "); // mark done task with X - } + private String getStatusIcon() { + return (isDone ? "X" : " "); // mark done task with X + } - @Override - public String toString() { - return "[" + this.getStatusIcon() + "] " + this.description; - } + /** + * Returns a string representation of the Task object. + * + * @return A string representation of the Task object. + */ + @Override + public String toString() { + return "[" + this.getStatusIcon() + "] " + this.description; + } - protected static LocalDateTime parseDate(String string) throws DateTimeParseException { - String dateTimePattern = "\\d{1,2}/\\d{1,2}/\\d{4} \\d{1,2}:\\d{2}"; - String datePattern = "\\d{1,2}/\\d{1,2}/\\d{4}"; - - - if (string.matches(dateTimePattern)) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/yyyy H:m"); - return LocalDateTime.parse(string, formatter); - } else if (string.matches(datePattern)) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/yyyy"); - LocalDate date = LocalDate.parse(string, formatter); - return date.atStartOfDay(); - } else { - throw new DateTimeParseException("Invalid date format. Use d/M/yyyy or d/M/yyy H:m.", string, 0); - } - } + /** + * Method to get a LocalDateTime object by parsing a string. + * + * @param string The string representation of the date and time to be parsed into a LocalDateTime object. + *

+ * String format should be or "d/M/yyyy" or "d/M/yyyy H:m". + * @return The LocalDateTime object parsed from the string. + * @throws DateTimeParseException If the date format is invalid. + */ + protected static LocalDateTime parseDate(String string) throws DateTimeParseException { + String dateTimePattern = "\\d{1,2}/\\d{1,2}/\\d{4} \\d{1,2}:\\d{2}"; + String datePattern = "\\d{1,2}/\\d{1,2}/\\d{4}"; - protected static String formatDate(LocalDateTime date) { - return date.format(DateTimeFormatter.ofPattern("MMM d, yyyy @ h:mma")); + + if (string.matches(dateTimePattern)) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/yyyy H:m"); + return LocalDateTime.parse(string, formatter); + } else if (string.matches(datePattern)) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/yyyy"); + LocalDate date = LocalDate.parse(string, formatter); + return date.atStartOfDay(); + } else { + throw new DateTimeParseException("Invalid date format. Use d/M/yyyy or d/M/yyy H:m.", string, 0); } + } + + /** + * Method to format a LocalDateTime object into a string. + * + * @param date The LocalDateTime object to be formatted into a string. + * @return The string representation of the LocalDateTime object in "MMM d, yyyy @ h:mma" format. + */ + protected static String formatDate(LocalDateTime date) { + return date.format(DateTimeFormatter.ofPattern("MMM d, yyyy @ h:mma")); + } } diff --git a/src/main/java/dude/Tasks/TaskList.java b/src/main/java/dude/Tasks/TaskList.java index 31a4403319..0bd50cc2df 100644 --- a/src/main/java/dude/Tasks/TaskList.java +++ b/src/main/java/dude/Tasks/TaskList.java @@ -5,20 +5,40 @@ import dude.Exceptions.TaskListFullException; +/** + * The TaskList class handles keeping track of the list of tasks. + * It also provides methods to add, remove, mark as done, mark as undone and get tasks from the list. + */ public class TaskList { private final ArrayList list; - public TaskList(){ + /** + * Constructor for the TaskList class. + */ + public TaskList() { list = new ArrayList(); } + /** + * Static method to create a TaskList object from an ArrayList of Task objects. + * + * @param tasks The ArrayList of Task objects to be converted into a TaskList object. + * @return The TaskList object created from the ArrayList of Task objects. + */ public static TaskList from(ArrayList tasks) { TaskList taskList = new TaskList(); taskList.list.addAll(tasks); return taskList; } + /** + * Adds a task to the list of tasks. + * + * @param task The task to be added to the list of tasks. + * @return A string representation of the task added to the list of tasks. + * @throws TaskListFullException if the task list is full. + */ public String add_task(Task task) throws TaskListFullException { if ( list.size() >= 100) { @@ -34,6 +54,13 @@ public String add_task(Task task) throws TaskListFullException { "\t-----------------------------------"; } + /** + * Removes a task from the list of tasks. + * + * @param taskID The id of the task to be removed from the list of tasks. + * @return A string representation of the task removed from the list of tasks. + * @throws DudeException if the task id is invalid. + */ public String remove_task(int taskID) throws DudeException { if (taskID > list.size() || taskID < 1) { throw new DudeException("Sorry, the provided id is invalid."); @@ -46,29 +73,38 @@ public String remove_task(int taskID) throws DudeException { "\t-----------------------------------"; } - public String mark_as_done(int index) throws DudeException { - if (index > list.size() || index < 1) { + /** + * Marks a task as done. + * + * @param id The id of the task to be marked as done. + * @throws DudeException if the task id is invalid. + */ + public void mark_as_done(int id) throws DudeException { + if (id > list.size() || id < 1) { throw new DudeException("Sorry, the provided id is invalid."); } - list.get(index - 1).markAsDone(); - return "\t-----------------------------------\n" + - "\tNice! I've marked this task as done:\n" + - "\t " + index + ". " + list.get(index - 1).toString() + "\n" + - "\t-----------------------------------"; + list.get(id - 1).markAsDone(); } - public String mark_as_undone(int index) throws DudeException { - if (index > list.size() || index < 1) { + /** + * Marks a task as undone. + * + * @param id The id of the task to be marked as undone. + * @throws DudeException if the task id is invalid. + */ + public void mark_as_undone(int id) throws DudeException { + if (id > list.size() || id < 1) { throw new DudeException("Sorry, the provided id is invalid."); } - list.get(index - 1).markAsUndone(); - return "\t-----------------------------------\n" + - "\tNice! I've marked this task as undone:\n" + - "\t " + index + ". " + list.get(index - 1).toString() + "\n" + - "\t-----------------------------------"; + list.get(id - 1).markAsUndone(); } + /** + * Returns a string representation of the list of tasks. + * + * @return A string representation of the list of tasks. + */ @Override public String toString() { String result = ""; @@ -103,10 +139,22 @@ public ArrayList getList() { return copy; } + /** + * Returns the number of tasks in the list. + * + * @return The number of tasks in the list. + */ public int getSize() { return list.size(); } + /** + * Returns the task with the given id. + * + * @param taskID The id of the task to be returned. + * @return The task with the given id. + * @throws IndexOutOfBoundsException if the task id is invalid. + */ public Task getTask(int taskID) throws IndexOutOfBoundsException { if (taskID <= 0 || taskID > list.size()) { throw new IndexOutOfBoundsException("Sorry, the provided id is invalid. " + diff --git a/src/main/java/dude/Tasks/Todo.java b/src/main/java/dude/Tasks/Todo.java index e61d8e5ce3..e251c0624f 100644 --- a/src/main/java/dude/Tasks/Todo.java +++ b/src/main/java/dude/Tasks/Todo.java @@ -3,44 +3,60 @@ import dude.Exceptions.InvalidDescriptionException; import dude.Utils.utils; +/** + * The Todo class represents a task with a description. + */ public class Todo extends Task { + /** + * Constructor for the Todo class. + * + * @param description The description of the todo. + */ + public Todo(String description) { + super(description); + } + + + /** + * Static method to create a Todo object from parsing a string. + * + * @param s The string to be parsed into a Todo object. + * @return The Todo object created from the string. + * @throws InvalidDescriptionException if the description of the todo is empty. + */ public static Todo from(String s) throws InvalidDescriptionException { - //Expects a string in the format "todo " //get rid of the command String description = utils.discardFirstWord(s.trim()).trim(); if (!description.isEmpty()){ return new Todo(description); - }else { + } else { throw new InvalidDescriptionException("The description of a todo cannot be empty."); } } - public Todo(String description) { - super(description); - } - - @Override - public void markAsDone() { - super.markAsDone(); - } - - @Override - public void markAsUndone() { - super.markAsUndone(); - } - + /** + * Returns a string representation of the Todo object. + * + * @return A string representation of the Todo object. + */ @Override public String toString() { return "[T]" + super.toString(); } + /** + * Returns whether the object is equal to this object. + * + * @param object The object to be compared. + * @return Whether the object is equal to this object. + */ @Override - public boolean equals(Object o) { - if (o instanceof Todo) { - Todo t = (Todo) o; + public boolean equals(Object object) { + if (object instanceof Todo) { + Todo t = (Todo) object; return t.getDescription().equals(this.getDescription()); } return false; From 255488f3deda01c4597fd8d7e287a8e7f66b397a Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 26 Feb 2024 22:28:13 +0800 Subject: [PATCH 081/153] Added Javadoc to the Exceptions package --- .../java/dude/Exceptions/DudeException.java | 11 +++++++++- .../Exceptions/InvalidArgumentException.java | 10 ++++++++- .../Exceptions/InvalidCommandException.java | 9 ++++++++ .../InvalidDescriptionException.java | 10 ++++++++- .../Exceptions/InvalidFormatException.java | 22 ++++++++++++++++++- .../Exceptions/TaskListFullException.java | 10 ++++++++- 6 files changed, 67 insertions(+), 5 deletions(-) diff --git a/src/main/java/dude/Exceptions/DudeException.java b/src/main/java/dude/Exceptions/DudeException.java index 0211d5b689..614b2f4a90 100644 --- a/src/main/java/dude/Exceptions/DudeException.java +++ b/src/main/java/dude/Exceptions/DudeException.java @@ -1,6 +1,15 @@ package dude.Exceptions; -public class DudeException extends Exception{ +/** + * The DudeException class represents an exception that is specific to the Dude application. + */ +public class DudeException extends Exception { + + /** + * Constructor for the DudeException class. + * + * @param message The message of the exception. + */ public DudeException(String message) { super(message); } diff --git a/src/main/java/dude/Exceptions/InvalidArgumentException.java b/src/main/java/dude/Exceptions/InvalidArgumentException.java index d36cd9294f..b8905f8bb5 100644 --- a/src/main/java/dude/Exceptions/InvalidArgumentException.java +++ b/src/main/java/dude/Exceptions/InvalidArgumentException.java @@ -1,7 +1,15 @@ package dude.Exceptions; +/** + * The InvalidArgumentException class represents an exception that is thrown when an argument for a command is invalid. + */ public class InvalidArgumentException extends DudeException { - //Used to indicate that an argument for the command is invalid + + /** + * Constructor for the InvalidArgumentException class. + * + * @param message The message of the exception. + */ public InvalidArgumentException(String message) { super(message); } diff --git a/src/main/java/dude/Exceptions/InvalidCommandException.java b/src/main/java/dude/Exceptions/InvalidCommandException.java index 5e99fe9898..09aefc86de 100644 --- a/src/main/java/dude/Exceptions/InvalidCommandException.java +++ b/src/main/java/dude/Exceptions/InvalidCommandException.java @@ -1,7 +1,16 @@ package dude.Exceptions; +/** + * The InvalidCommandException class represents an exception that is thrown when the command is invalid. + */ public class InvalidCommandException extends DudeException { //Used to indicate that the command is invalid + + /** + * Constructor for the InvalidCommandException class. + * + * @param message The message of the exception. + */ public InvalidCommandException(String message) { super(message); } diff --git a/src/main/java/dude/Exceptions/InvalidDescriptionException.java b/src/main/java/dude/Exceptions/InvalidDescriptionException.java index 67e8cc33cd..0ce6a8106b 100644 --- a/src/main/java/dude/Exceptions/InvalidDescriptionException.java +++ b/src/main/java/dude/Exceptions/InvalidDescriptionException.java @@ -1,7 +1,15 @@ package dude.Exceptions; +/** + * The InvalidDescriptionException class represents an exception that is thrown when the description for a task is invalid. + */ public class InvalidDescriptionException extends DudeException { - //Used to indicate that the description is invalid + + /** + * Constructor for the InvalidDescriptionException class. + * + * @param message The message of the exception. + */ public InvalidDescriptionException(String message) { super(message); } diff --git a/src/main/java/dude/Exceptions/InvalidFormatException.java b/src/main/java/dude/Exceptions/InvalidFormatException.java index a43853ef36..2f526bffe7 100644 --- a/src/main/java/dude/Exceptions/InvalidFormatException.java +++ b/src/main/java/dude/Exceptions/InvalidFormatException.java @@ -1,16 +1,36 @@ package dude.Exceptions; +/** + * The InvalidFormatException class represents an exception that is thrown when the format is invalid. + */ public class InvalidFormatException extends DudeException { + /** + * Constructor for the InvalidFormatException class. + * + * @param message The message of the exception. + */ public InvalidFormatException(String message) { super(message); } - //Used to indicate that the format is invalid + /** + * Constructor for the InvalidFormatException class. + * + * @param command The command that was used. + * @param format The format that should be used. + */ public InvalidFormatException(String command, String format) { super("Invalid format for " + command + " command. \nPlease use this format: " + format + ",\n or type help for more information."); } + /** + * Constructor for the InvalidFormatException class. + * + * @param command The command that was used. + * @param format The format that should be used. + * @param note The note to be added to the exception message. + */ public InvalidFormatException(String command, String format, String note) { super("Invalid format for " + command + " command. " + "\nPlease use this format: " + format + "," + diff --git a/src/main/java/dude/Exceptions/TaskListFullException.java b/src/main/java/dude/Exceptions/TaskListFullException.java index ae77ecc3cf..41e12a79c5 100644 --- a/src/main/java/dude/Exceptions/TaskListFullException.java +++ b/src/main/java/dude/Exceptions/TaskListFullException.java @@ -1,7 +1,15 @@ package dude.Exceptions; +/** + * The TaskListFullException class represents an exception that is thrown when the task list is full. + */ public class TaskListFullException extends DudeException { - //Used to indicate that the task list is full + + /** + * Constructor for the TaskListFullException class. + * + * @param message The message of the exception. + */ public TaskListFullException(String message) { super(message); } From a00cbb4bcc1e11e906651bb65eff38e94f53c5ff Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 26 Feb 2024 22:50:19 +0800 Subject: [PATCH 082/153] Added Javadoc to the Commands package --- src/main/java/dude/Commands/ByeCommand.java | 6 ++++ src/main/java/dude/Commands/Command.java | 30 +++++++++++++++++++ src/main/java/dude/Commands/CommandTypes.java | 3 ++ .../java/dude/Commands/DeadlineCommand.java | 20 +++++++++++-- .../java/dude/Commands/DeleteCommand.java | 16 ++++++++++ src/main/java/dude/Commands/EventCommand.java | 16 ++++++++++ src/main/java/dude/Commands/HelpCommand.java | 15 ++++++++++ .../java/dude/Commands/InvalidCommand.java | 11 +++++++ src/main/java/dude/Commands/ListCommand.java | 14 +++++++++ src/main/java/dude/Commands/MarkCommand.java | 16 ++++++++++ src/main/java/dude/Commands/Parser.java | 10 +++++++ src/main/java/dude/Commands/TodoCommand.java | 16 ++++++++++ .../java/dude/Commands/UnmarkCommand.java | 16 ++++++++++ 13 files changed, 187 insertions(+), 2 deletions(-) diff --git a/src/main/java/dude/Commands/ByeCommand.java b/src/main/java/dude/Commands/ByeCommand.java index d1297032c2..105eb788cf 100644 --- a/src/main/java/dude/Commands/ByeCommand.java +++ b/src/main/java/dude/Commands/ByeCommand.java @@ -1,9 +1,15 @@ package dude.Commands; +/** + * The ByeCommand class represents a command to exit the program. + */ public class ByeCommand extends Command { static final String COMMAND_FORMAT = "bye"; + /** + * Constructor for the ByeCommand class. Returns a command object to exit the program upon execution. + */ public ByeCommand() { super(COMMAND_FORMAT, "bye"); } diff --git a/src/main/java/dude/Commands/Command.java b/src/main/java/dude/Commands/Command.java index 46d90fcf6b..6461c24d30 100644 --- a/src/main/java/dude/Commands/Command.java +++ b/src/main/java/dude/Commands/Command.java @@ -2,25 +2,55 @@ import dude.Exceptions.DudeException; +/** + * The Command class represents a command that can be executed by the user. + */ public abstract class Command { private final String format; private final String regex; + /** + * Constructor for the Command class. + * + * @param format The format of the command. + * @param regex The regex of the command. + */ protected Command(String format, String regex) { this.format = format; this.regex = regex; } + /** + * Executes the command. + * + * @return The string message from the execution of the command. + * @throws DudeException If the command execution fails. + */ public abstract String execute() throws DudeException; + /** + * Gets the format of the command. + * + * @return The format of the command. + */ public String getFormat() { return this.format; } + /** + * Gets the regex of the command. + * + * @return The regex of the command. + */ public String getRegex() { return this.regex; } + /** + * Gets the type of the command. + * + * @return The type of the command. + */ public abstract CommandTypes getCommandType(); } diff --git a/src/main/java/dude/Commands/CommandTypes.java b/src/main/java/dude/Commands/CommandTypes.java index db5f47fe95..e08aef9b14 100644 --- a/src/main/java/dude/Commands/CommandTypes.java +++ b/src/main/java/dude/Commands/CommandTypes.java @@ -1,5 +1,8 @@ package dude.Commands; +/** + * The CommandTypes enum represents the types of commands that can be used in the application. + */ public enum CommandTypes { BYE, LIST, diff --git a/src/main/java/dude/Commands/DeadlineCommand.java b/src/main/java/dude/Commands/DeadlineCommand.java index d85c7b5d38..5af6938f56 100644 --- a/src/main/java/dude/Commands/DeadlineCommand.java +++ b/src/main/java/dude/Commands/DeadlineCommand.java @@ -5,18 +5,34 @@ import dude.Tasks.Deadline; import dude.Tasks.TaskList; +/** + * The DeadlineCommand class represents a command to add a deadline task to the TaskList object. + */ public class DeadlineCommand extends Command { - private final String input; - private final TaskList taskList; static final String COMMAND_FORMAT = "deadline /by "; + private final String input; + private final TaskList taskList; + /** + * Constructor for the DeadlineCommand class. Returns a command object to add a deadline task to the TaskList object upon + * execution. + * + * @param input The input string that resulted in the creation of this command. + * @param tasklist The TaskList object to which the deadline task is to be added. + */ public DeadlineCommand(String input, TaskList tasklist) { super(COMMAND_FORMAT, "deadline .* /by .*"); this.input = input; this.taskList = tasklist; } + /** + * Add a deadline task to the TaskList object. + * + * @return The string message from the execution of the command. + * @throws DudeException If the command execution fails. + */ public String execute() throws DudeException { boolean doesInputMatch = input.matches(this.getRegex()); diff --git a/src/main/java/dude/Commands/DeleteCommand.java b/src/main/java/dude/Commands/DeleteCommand.java index b83e976bcf..a61f7c90bb 100644 --- a/src/main/java/dude/Commands/DeleteCommand.java +++ b/src/main/java/dude/Commands/DeleteCommand.java @@ -5,18 +5,34 @@ import dude.Tasks.Task; import dude.Tasks.TaskList; +/** + * The DeleteCommand class represents a command to delete a task from the TaskList object. + */ public class DeleteCommand extends Command { private final String input; private final TaskList taskList; private static final String COMMAND_FORMAT = "delete "; + /** + * Constructor for the DeleteCommand class. Returns a command object to delete a task from the TaskList object upon + * execution. + * + * @param input The input string that resulted in the creation of this command. + * @param tasklist The TaskList object from which the task is to be deleted. + */ public DeleteCommand(String input, TaskList tasklist) { super(COMMAND_FORMAT, "delete \\d+"); this.input = input.trim(); this.taskList = tasklist; } + /** + * Deletes a task from the TaskList object. + * + * @return The string message from the execution of the command. + * @throws DudeException If the command execution fails. + */ public String execute() throws DudeException { boolean inputMatches = input.matches(this.getRegex()); diff --git a/src/main/java/dude/Commands/EventCommand.java b/src/main/java/dude/Commands/EventCommand.java index a8308f2f9f..5cb8641160 100644 --- a/src/main/java/dude/Commands/EventCommand.java +++ b/src/main/java/dude/Commands/EventCommand.java @@ -5,18 +5,34 @@ import dude.Tasks.Event; import dude.Tasks.TaskList; +/** + * The EventCommand class represents a command that adds an event to the TaskList object. + */ public class EventCommand extends Command { private final String input; private final TaskList taskList; public static final String COMMAND_FORMAT = "event /from /to "; + /** + * Constructor for the EventCommand class. Returns a command object to add an event to the TaskList object upon + * execution. + * + * @param input The input string that resulted in the creation of this command. + * @param tasklist The TaskList object to which the event is to be added. + */ public EventCommand(String input, TaskList tasklist) { super(COMMAND_FORMAT, "event .* /from .* /to .*"); this.input = input; this.taskList = tasklist; } + /** + * Add an event to the TaskList object. + * + * @return The string message from the execution of the command. + * @throws DudeException If the command execution fails. + */ public String execute() throws DudeException { boolean doesInputMatch = input.matches(this.getRegex()); diff --git a/src/main/java/dude/Commands/HelpCommand.java b/src/main/java/dude/Commands/HelpCommand.java index f241fc5530..ad976ba44d 100644 --- a/src/main/java/dude/Commands/HelpCommand.java +++ b/src/main/java/dude/Commands/HelpCommand.java @@ -2,6 +2,9 @@ import dude.Exceptions.DudeException; +/** + * The HelpCommand class represents a command that provides help on the commands the application supports. + */ public class HelpCommand extends Command { private static final String COMMAND_FORMAT = "help "; @@ -20,11 +23,23 @@ public class HelpCommand extends Command { private final String input; + /** + * Constructor for the HelpCommand class. Returns a command object to provide help on the commands the application + * supports upon execution. + * + * @param input The input string that resulted in the creation of this command. + */ public HelpCommand(String input) { super("help ", "help"); this.input = input.trim(); } + /** + * Provides help on the commands the application supports. + * + * @return The string message from the execution of the command. + * @throws DudeException If the command execution fails. + */ public String execute() throws DudeException { if (input.equals("help")) { return this.generateHelpMessage(); diff --git a/src/main/java/dude/Commands/InvalidCommand.java b/src/main/java/dude/Commands/InvalidCommand.java index 0bfe9df0d8..cc77e6f027 100644 --- a/src/main/java/dude/Commands/InvalidCommand.java +++ b/src/main/java/dude/Commands/InvalidCommand.java @@ -1,11 +1,22 @@ package dude.Commands; +/** + * The InvalidCommand class represents a command that is invalid. + */ public class InvalidCommand extends Command { + /** + * Constructor for the InvalidCommand class. Returns a command object that is used to represent an invalid command. + */ public InvalidCommand() { super("", ""); } + /** + * Does nothing + * + * @return The string message for an invalid command. + */ public String execute() { return "Sorry I don't understand that command. Please try again."; } diff --git a/src/main/java/dude/Commands/ListCommand.java b/src/main/java/dude/Commands/ListCommand.java index 66d48eb603..5c1babff20 100644 --- a/src/main/java/dude/Commands/ListCommand.java +++ b/src/main/java/dude/Commands/ListCommand.java @@ -2,16 +2,30 @@ import dude.Tasks.TaskList; +/** + * The ListCommand class represents a command to list all the tasks in the TaskList object. + */ public class ListCommand extends Command { static final String COMMAND_FORMAT = "list"; private final TaskList tasklist; + /** + * Constructor for the ListCommand class. Returns a command object to list all the tasks in the given TaskList object upon + * execution. + * + * @param tasklist The TaskList object to be listed. + */ public ListCommand(TaskList tasklist) { super("list", "list"); this.tasklist = tasklist; } + /** + * Returns a string representation of the list of tasks in the TaskList object. + * + * @return The string message from the execution of the command. + */ public String execute() { return tasklist.toString(); } diff --git a/src/main/java/dude/Commands/MarkCommand.java b/src/main/java/dude/Commands/MarkCommand.java index 5771a16487..f18c8dfded 100644 --- a/src/main/java/dude/Commands/MarkCommand.java +++ b/src/main/java/dude/Commands/MarkCommand.java @@ -5,18 +5,34 @@ import dude.Tasks.Task; import dude.Tasks.TaskList; +/** + * The MarkCommand class represents a command to mark a task as done in the TaskList object. + */ public class MarkCommand extends Command { public static final String COMMAND_FORMAT = "mark "; private final String input; private final TaskList taskList; + /** + * Constructor for the MarkCommand class. Returns a command object to mark a task as done in the TaskList object upon + * execution. + * + * @param input The input string that resulted in the creation of this command. + * @param tasklist The TaskList object in which the task is to be marked as done. + */ public MarkCommand(String input, TaskList tasklist) { super(COMMAND_FORMAT, "mark \\d+"); this.input = input.trim(); this.taskList = tasklist; } + /** + * Marks a task as done in the TaskList object. + * + * @return The string message from the execution of the command. + * @throws DudeException If the command execution fails. + */ @Override public String execute() throws DudeException { boolean inputMatches = input.matches(this.getRegex()); diff --git a/src/main/java/dude/Commands/Parser.java b/src/main/java/dude/Commands/Parser.java index 31294f2841..45be667d36 100644 --- a/src/main/java/dude/Commands/Parser.java +++ b/src/main/java/dude/Commands/Parser.java @@ -2,8 +2,18 @@ import dude.Tasks.TaskList; +/** + * The Parser class is responsible for parsing the user input and returning the appropriate command. + */ public class Parser { + /** + * Parses the user input and returns the appropriate command. + * + * @param input The user input. + * @param tasklist The TaskList to be used by the command. + * @return The parsed command from the user input. + */ public static Command parse(String input, TaskList tasklist) { String[] command = input.split(" ", 2); switch (command[0]) { diff --git a/src/main/java/dude/Commands/TodoCommand.java b/src/main/java/dude/Commands/TodoCommand.java index 22b3a4656e..34259d538b 100644 --- a/src/main/java/dude/Commands/TodoCommand.java +++ b/src/main/java/dude/Commands/TodoCommand.java @@ -5,18 +5,34 @@ import dude.Tasks.TaskList; import dude.Tasks.Todo; +/** + * The TodoCommand class represents a command to add a todo task to the TaskList object. + */ public class TodoCommand extends Command { public static final String COMMAND_FORMAT = "todo "; private final String input; private final TaskList taskList; + /** + * Constructor for the TodoCommand class. Returns a command object to add a todo task to the TaskList object + * upon execution. + * + * @param input The input string that resulted in the creation of this command. + * @param tasklist The TaskList object to which the todo task is to be added. + */ public TodoCommand(String input, TaskList tasklist) { super(COMMAND_FORMAT, "todo .*"); this.input = input; this.taskList = tasklist; } + /** + * Add a todo task to the TaskList object. + * + * @return The string message from the execution of the command. + * @throws DudeException If the command execution fails. + */ public String execute() throws DudeException { boolean doesInputMatch = input.matches(this.getRegex()); diff --git a/src/main/java/dude/Commands/UnmarkCommand.java b/src/main/java/dude/Commands/UnmarkCommand.java index e1f24b0b84..e7ee4a352a 100644 --- a/src/main/java/dude/Commands/UnmarkCommand.java +++ b/src/main/java/dude/Commands/UnmarkCommand.java @@ -5,18 +5,34 @@ import dude.Tasks.Task; import dude.Tasks.TaskList; +/** + * The UnmarkCommand class represents a command to mark a task as not done in the task list. + */ public class UnmarkCommand extends Command { public static final String COMMAND_FORMAT = "unmark "; private final String input; private final TaskList taskList; + /** + * Constructor for the UnmarkCommand class. Returns a command object to mark a task as not done in the task list upon + * execution. + * + * @param input The input string that resulted in the creation of this command. + * @param tasklist The TaskList object in which the task is to be marked as not done. + */ public UnmarkCommand(String input, TaskList tasklist) { super(COMMAND_FORMAT, "unmark \\d+"); this.input = input.trim(); this.taskList = tasklist; } + /** + * Marks a task as not done in the task list. + * + * @return The string message from the execution of the command. + * @throws DudeException If the command execution fails. + */ @Override public String execute() throws DudeException { boolean inputMatches = input.matches(this.getRegex()); From 76dcd504eb239af0a93db4f53f5df932eae6440d Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 26 Feb 2024 23:22:34 +0800 Subject: [PATCH 083/153] Implemented find function --- src/main/java/dude/Tasks/TaskList.java | 68 ++++++++++++++------------ 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/src/main/java/dude/Tasks/TaskList.java b/src/main/java/dude/Tasks/TaskList.java index 0bd50cc2df..e60269f167 100644 --- a/src/main/java/dude/Tasks/TaskList.java +++ b/src/main/java/dude/Tasks/TaskList.java @@ -7,7 +7,7 @@ /** * The TaskList class handles keeping track of the list of tasks. - * It also provides methods to add, remove, mark as done, mark as undone and get tasks from the list. + * It also provides various methods to interact with the list of tasks. */ public class TaskList { @@ -36,41 +36,26 @@ public static TaskList from(ArrayList tasks) { * Adds a task to the list of tasks. * * @param task The task to be added to the list of tasks. - * @return A string representation of the task added to the list of tasks. * @throws TaskListFullException if the task list is full. */ - public String add_task(Task task) throws TaskListFullException { - - if ( list.size() >= 100) { + public void add_task(Task task) throws TaskListFullException { + if (list.size() >= 100) { throw new TaskListFullException("Sorry, the task list is full."); } - list.add(task); - - return "\t-----------------------------------\n" + - "\tGot it. I've added this task:\n" + - "\t\t" + task.toString() + "\n" + - "\tNow you have " + list.size() + " tasks in the list.\n" + - "\t-----------------------------------"; } /** * Removes a task from the list of tasks. * * @param taskID The id of the task to be removed from the list of tasks. - * @return A string representation of the task removed from the list of tasks. * @throws DudeException if the task id is invalid. */ - public String remove_task(int taskID) throws DudeException { + public void remove_task(int taskID) throws DudeException { if (taskID > list.size() || taskID < 1) { throw new DudeException("Sorry, the provided id is invalid."); } Task removed = list.remove(taskID - 1); - return "\t-----------------------------------\n" + - "\tNoted. I've removed this task:\n" + - "\t " + removed.toString() + "\n" + - "\tNow you have " + list.size() + " tasks in the list.\n" + - "\t-----------------------------------"; } /** @@ -99,26 +84,28 @@ public void mark_as_undone(int id) throws DudeException { list.get(id - 1).markAsUndone(); } - /** - * Returns a string representation of the list of tasks. + * Finds tasks whose string representation matches with the given keyword. * - * @return A string representation of the list of tasks. + * @param keyword The keyword to be used to find tasks. + * @return An ArrayList of Task objects that contain the keyword. */ - @Override - public String toString() { - String result = ""; - for (int i = 0; i < list.size(); i++) { - //if it is the last task, do not add a new line - if (i == list.size() - 1) { - result += (i + 1) + ". " + list.get(i).toString(); - break; + public ArrayList find(String keyword) { + ArrayList result = new ArrayList<>(); + String taskString; + String keywordLowerCase = keyword.toLowerCase(); + for (Task task : list) { + taskString = task.toString(); + taskString = taskString.toLowerCase(); + + if (taskString.contains(keywordLowerCase)) { + result.add(task); } - result += (i + 1) + ". " + list.get(i).toString() + "\n"; } return result; } + /** * Returns a deep copy of the list of tasks * @return An ArrayList of Task objects @@ -162,4 +149,23 @@ public Task getTask(int taskID) throws IndexOutOfBoundsException { } return list.get(taskID - 1); } + + /** + * Returns a string representation of the list of tasks. + * + * @return A string representation of the list of tasks. + */ + @Override + public String toString() { + String result = ""; + for (int i = 0; i < list.size(); i++) { + //if it is the last task, do not add a new line + if (i == list.size() - 1) { + result += (i + 1) + ". " + list.get(i).toString(); + break; + } + result += (i + 1) + ". " + list.get(i).toString() + "\n"; + } + return result; + } } From 5e6ebe0afc4fd58fa90191274f75aad1d3bf0715 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 26 Feb 2024 23:23:20 +0800 Subject: [PATCH 084/153] Implemented find command --- src/main/java/dude/Commands/CommandTypes.java | 1 + src/main/java/dude/Commands/FindCommand.java | 62 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 src/main/java/dude/Commands/FindCommand.java diff --git a/src/main/java/dude/Commands/CommandTypes.java b/src/main/java/dude/Commands/CommandTypes.java index e08aef9b14..a8d315b0fc 100644 --- a/src/main/java/dude/Commands/CommandTypes.java +++ b/src/main/java/dude/Commands/CommandTypes.java @@ -12,6 +12,7 @@ public enum CommandTypes { EVENT, MARK, UNMARK, + FIND, HELP, INVALID } diff --git a/src/main/java/dude/Commands/FindCommand.java b/src/main/java/dude/Commands/FindCommand.java new file mode 100644 index 0000000000..080e2ff1af --- /dev/null +++ b/src/main/java/dude/Commands/FindCommand.java @@ -0,0 +1,62 @@ +package dude.Commands; + + +import dude.Exceptions.InvalidFormatException; +import dude.Tasks.Task; +import dude.Tasks.TaskList; +import dude.Utils.utils; + +import java.util.ArrayList; + +/** + * The FindCommand class represents a command to find tasks in the TaskList object. + */ +public class FindCommand extends Command { + static final String COMMAND_FORMAT = "find "; + + private final String input; + private final TaskList taskList; + + /** + * Constructor for the FindCommand class. Returns a command object to find tasks with the given input + * in the TaskList object upon execution. + * + * @param input The input string that resulted in the creation of this command. + * @param taskList The TaskList object from which the tasks are to be found. + */ + public FindCommand(String input, TaskList taskList) { + super(COMMAND_FORMAT, "find .*"); + this.input = input; + this.taskList = taskList; + } + + /** + * Finds tasks in the TaskList object. + * + * @return The string message of the tasks found from the execution of the command. + */ + public String execute() throws InvalidFormatException { + String keyword = utils.discardFirstWord(input.trim()).trim(); + + if (keyword.isEmpty()) { + throw new InvalidFormatException("find", COMMAND_FORMAT); + } + ArrayList tasks = this.taskList.find(keyword); + + if (tasks.isEmpty()) { + return "No matching tasks found! :("; + } + + String msg = "Here are the matching tasks in your list:\n"; + for (int i = 0; i < tasks.size(); i++) { + msg += "\t" + (i + 1) + ". " + tasks.get(i).toString() + "\n"; + } + + return msg; + } + + @Override + public CommandTypes getCommandType() { + return CommandTypes.FIND; + } +} From b78b6cccbe49693ad780894a1c5e92c4d4144955 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 26 Feb 2024 23:23:57 +0800 Subject: [PATCH 085/153] Added find command to Parser --- src/main/java/dude/Commands/Parser.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/dude/Commands/Parser.java b/src/main/java/dude/Commands/Parser.java index 45be667d36..8b2db05411 100644 --- a/src/main/java/dude/Commands/Parser.java +++ b/src/main/java/dude/Commands/Parser.java @@ -33,6 +33,8 @@ public static Command parse(String input, TaskList tasklist) { return new MarkCommand(input, tasklist); case "unmark": return new UnmarkCommand(input, tasklist); + case "find": + return new FindCommand(input, tasklist); case "help": return new HelpCommand(input); default: From 0f866ae6e3ceb582fd769a8ae58db681e52c356e Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 26 Feb 2024 23:31:09 +0800 Subject: [PATCH 086/153] Added help support for find command --- src/main/java/dude/Commands/FindCommand.java | 3 +-- src/main/java/dude/Commands/HelpCommand.java | 6 ++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/dude/Commands/FindCommand.java b/src/main/java/dude/Commands/FindCommand.java index 080e2ff1af..a1894f5a07 100644 --- a/src/main/java/dude/Commands/FindCommand.java +++ b/src/main/java/dude/Commands/FindCommand.java @@ -51,8 +51,7 @@ public String execute() throws InvalidFormatException { for (int i = 0; i < tasks.size(); i++) { msg += "\t" + (i + 1) + ". " + tasks.get(i).toString() + "\n"; } - - return msg; + return msg.trim(); } @Override diff --git a/src/main/java/dude/Commands/HelpCommand.java b/src/main/java/dude/Commands/HelpCommand.java index ad976ba44d..1fc8d4f8cd 100644 --- a/src/main/java/dude/Commands/HelpCommand.java +++ b/src/main/java/dude/Commands/HelpCommand.java @@ -17,6 +17,7 @@ public class HelpCommand extends Command { "mark: Marks a task as done.", "unmark: Marks a task as undone.", "delete: Deletes a task from the task list.", + "find: Finds tasks with mathing keyword", "bye: Exits the program.", "help: Provides help on the commands I support." }; @@ -103,6 +104,11 @@ private String generateCommandHelpMessage() { + "\n\tFormat: delete " + "\n\tExample: delete 1" + "\n\t*Note: The id must be a valid integer task id."; + case "find": + return "find: Finds tasks whose string representation matches with the given keyword." + + "\n\tFormat: find " + + "\n\tExample: find book" + + "\n\t*Note: The keyword cannot be empty."; case "bye": return "bye: Exits the program." + "\n\tFormat: bye" From df5576edab2bc098d7763b0b20a9bf9a605dbf31 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 26 Feb 2024 23:36:16 +0800 Subject: [PATCH 087/153] Bug fixes for UI --- src/main/java/dude/Utils/Ui.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/dude/Utils/Ui.java b/src/main/java/dude/Utils/Ui.java index ada4a13168..21e269417b 100644 --- a/src/main/java/dude/Utils/Ui.java +++ b/src/main/java/dude/Utils/Ui.java @@ -25,9 +25,9 @@ public void showWelcome() { public void showMessage(String msg) { String temp = msg; - temp = temp.replaceAll("\n", "\n\t\t"); - temp = "\t\t" + "\t-----------------------------------\n" + temp + temp = "\t-----------------------------------\n" + + "\t\t" + temp + "\n\t-----------------------------------"; System.out.println(temp); } From 360681ab9a45a1427c8cb178696521966ae26b56 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 26 Feb 2024 23:46:38 +0800 Subject: [PATCH 088/153] Coding Style fixes for Deadline Class --- src/main/java/dude/Tasks/Deadline.java | 46 +++++++++++++++----------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/src/main/java/dude/Tasks/Deadline.java b/src/main/java/dude/Tasks/Deadline.java index ebaf1cb5c9..03a1b232e7 100644 --- a/src/main/java/dude/Tasks/Deadline.java +++ b/src/main/java/dude/Tasks/Deadline.java @@ -1,19 +1,20 @@ package dude.Tasks; +import java.time.LocalDateTime; +import java.time.format.DateTimeParseException; + import dude.Exceptions.InvalidArgumentException; import dude.Exceptions.InvalidDescriptionException; import dude.Exceptions.InvalidFormatException; import dude.Utils.utils; -import java.time.LocalDateTime; -import java.time.format.DateTimeParseException; /** * The Deadline class represents a task with a description and a deadline. */ public class Deadline extends Task { - private final LocalDateTime deadline_date; + private final LocalDateTime deadlineDate; /** * Constructor for the Deadline class. @@ -23,11 +24,12 @@ public class Deadline extends Task { */ public Deadline(String description, LocalDateTime by) { super(description); - this.deadline_date = by; + this.deadlineDate = by; } /** * Static method to create a Deadline object from parsing a string. + * Expects a string in the format "deadline /by ". * * @param s The string to be parsed into a Deadline object. * @return The Deadline object created from the string. @@ -35,7 +37,8 @@ public Deadline(String description, LocalDateTime by) { * @throws InvalidDescriptionException If the description of the deadline is empty. * @throws InvalidArgumentException If the 'by' of the deadline is empty. */ - public static Deadline from(String s) throws InvalidFormatException, InvalidDescriptionException, InvalidArgumentException { + public static Deadline from(String s) throws InvalidFormatException, + InvalidDescriptionException, InvalidArgumentException { //Expects a string in the format "deadline /by " //get rid of the command @@ -43,39 +46,42 @@ public static Deadline from(String s) throws InvalidFormatException, InvalidDesc String[] arr = rest.split(" "); - int by_occurences = utils.countOccurrences(arr, "/by"); + int byOccurences = utils.countOccurrences(arr, "/by"); - if (by_occurences == 0 || by_occurences > 1){ - throw new InvalidFormatException("deadline", "format: deadline /by . Provide one and only one '/by'."); + if (byOccurences == 0 || byOccurences > 1) { + throw new InvalidFormatException("deadline", "format: deadline /by . " + + "Provide one and only one '/by'."); } //they will not be -1 as I have already checked for their occurences - int by_index = utils.findIndex(arr, "/by"); + int byIndex = utils.findIndex(arr, "/by"); - //description is from 0 to by_index + //description is from 0 to byIndex String description = ""; - for (int i = 0; i < by_index; i++){ + for (int i = 0; i < byIndex; i++) { description += arr[i] + " "; } description = description.trim(); - if (description.isEmpty()){ + if (description.isEmpty()) { throw new InvalidDescriptionException("The description of a deadline cannot be empty."); } String by = ""; - for (int i = by_index+1; i < arr.length; i++){ + for (int i = byIndex + 1; i < arr.length; i++) { by += arr[i] + " "; } by = by.trim(); - if (by.isEmpty()){ - throw new InvalidArgumentException("The 'by' of a deadline cannot be empty. Follow this format: deadline /by "); + if (by.isEmpty()) { + throw new InvalidArgumentException("The 'by' of a deadline cannot be empty. " + + "Follow this format: deadline /by "); } - try{ + try { LocalDateTime dt = parseDate(by); return new Deadline(description, dt); - }catch (DateTimeParseException e){ - throw new InvalidFormatException("Invalid date format after '/by'. Use d/M/yyyy or d/M/yyy H:m in 24-hour format"); + } catch (DateTimeParseException e) { + throw new InvalidFormatException("Invalid date format after '/by'. " + + "Use d/M/yyyy or d/M/yyy H:m in 24-hour format"); } } @@ -85,7 +91,7 @@ public static Deadline from(String s) throws InvalidFormatException, InvalidDesc * @return The deadline date-time of the Deadline object. */ public LocalDateTime getBy() { - return deadline_date; + return deadlineDate; } /** @@ -95,7 +101,7 @@ public LocalDateTime getBy() { */ @Override public String toString() { - return "[D]" + super.toString() + " (by: " + formatDate(deadline_date) + ")"; + return "[D]" + super.toString() + " (by: " + formatDate(deadlineDate) + ")"; } /** From 5246c2c7f84dd8754c639c198d7613ebda1df0ae Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 26 Feb 2024 23:52:12 +0800 Subject: [PATCH 089/153] Coding Style fixes for Event Class --- src/main/java/dude/Tasks/Event.java | 87 +++++++++++++++-------------- 1 file changed, 46 insertions(+), 41 deletions(-) diff --git a/src/main/java/dude/Tasks/Event.java b/src/main/java/dude/Tasks/Event.java index f7a97cc500..f02161bf2e 100644 --- a/src/main/java/dude/Tasks/Event.java +++ b/src/main/java/dude/Tasks/Event.java @@ -1,33 +1,34 @@ package dude.Tasks; +import java.time.LocalDateTime; +import java.time.format.DateTimeParseException; + import dude.Commands.EventCommand; import dude.Exceptions.InvalidArgumentException; import dude.Exceptions.InvalidDescriptionException; import dude.Exceptions.InvalidFormatException; import dude.Utils.utils; -import java.time.LocalDateTime; -import java.time.format.DateTimeParseException; /** * The Event class represents a task with a description, start and end time. */ public class Event extends Task { - private final LocalDateTime from_time; - private final LocalDateTime to_time; + private final LocalDateTime fromTime; + private final LocalDateTime toTime; /** * Constructor for the Event class. * * @param description The description of the event. - * @param from_time The start time of the event. - * @param to_time The end time of the event. + * @param fromTime The start time of the event. + * @param toTime The end time of the event. */ - public Event(String description, LocalDateTime from_time, LocalDateTime to_time) { + public Event(String description, LocalDateTime fromTime, LocalDateTime toTime) { super(description); - this.from_time = from_time; - this.to_time = to_time; + this.fromTime = fromTime; + this.toTime = toTime; } /** @@ -39,8 +40,9 @@ public Event(String description, LocalDateTime from_time, LocalDateTime to_time) * @throws InvalidFormatException If the format of the string is invalid. * @throws InvalidDescriptionException If the description of the event is empty. */ - public static Event from(String s) throws InvalidArgumentException, InvalidFormatException, InvalidDescriptionException { - //Expects a string in the format "event /at to " + public static Event from(String s) throws InvalidArgumentException, + InvalidFormatException, InvalidDescriptionException { + //Expects a string in the format "event /at to " //get rid of the command // time time @@ -48,60 +50,63 @@ public static Event from(String s) throws InvalidArgumentException, InvalidForma String[] arr = rest.split(" "); - int from_occurences = utils.countOccurrences(arr, "/from"); + int fromOccurences = utils.countOccurrences(arr, "/from"); - if (from_occurences == 0 || from_occurences > 1){ - throw new InvalidFormatException("Invalid format. Follow this format :" + EventCommand.COMMAND_FORMAT + ". Provide one and only one '/from'."); + if (fromOccurences == 0 || fromOccurences > 1) { + throw new InvalidFormatException("Invalid format. Follow this format :" + EventCommand.COMMAND_FORMAT + + ". Provide one and only one '/from'."); } - int to_occurences = utils.countOccurrences(arr, "/to"); + int toOccurences = utils.countOccurrences(arr, "/to"); - if (to_occurences == 0 || to_occurences > 1){ - throw new InvalidFormatException("Invalid format. Follow this format: " + EventCommand.COMMAND_FORMAT + ". Provide one and only one '/to'."); + if (toOccurences == 0 || toOccurences > 1) { + throw new InvalidFormatException("Invalid format. Follow this format: " + EventCommand.COMMAND_FORMAT + + ". Provide one and only one '/to'."); } //they will not be -1 as I have already checked for their occurences - int from_index = utils.findIndex(arr, "/from"); - int to_index = utils.findIndex(arr, "/to"); + int fromIndex = utils.findIndex(arr, "/from"); + int toIndex = utils.findIndex(arr, "/to"); - if (from_index > to_index){ + if (fromIndex > toIndex) { throw new InvalidFormatException("The 'from time' of an event cannot be after the 'to time'."); } - //description is from 0 to from_index + //description is from 0 to fromIndex String description = ""; - for (int i = 0; i < from_index; i++){ + for (int i = 0; i < fromIndex; i++) { description += arr[i] + " "; } description = description.trim(); - if (description.isEmpty()){ + if (description.isEmpty()) { throw new InvalidDescriptionException("The description of an event cannot be empty."); } - String from_time = ""; - for (int i = from_index+1; i < to_index; i++){ - from_time += arr[i] + " "; + String fromTime = ""; + for (int i = fromIndex + 1; i < toIndex; i++) { + fromTime += arr[i] + " "; } - from_time = from_time.trim(); - if (from_time.isEmpty()){ - throw new InvalidArgumentException("The 'from_time' of an event cannot be empty."); + fromTime = fromTime.trim(); + if (fromTime.isEmpty()) { + throw new InvalidArgumentException("The 'fromTime' of an event cannot be empty."); } - String to_time = ""; - for (int i = to_index+1; i < arr.length; i++){ - to_time += arr[i] + " "; + String toTime = ""; + for (int i = toIndex + 1; i < arr.length; i++) { + toTime += arr[i] + " "; } - to_time = to_time.trim(); - if (to_time.isEmpty()){ - throw new InvalidArgumentException("The 'to_time' of an event cannot be empty."); + toTime = toTime.trim(); + if (toTime.isEmpty()) { + throw new InvalidArgumentException("The 'toTime' of an event cannot be empty."); } try { - LocalDateTime from = parseDate(from_time); - LocalDateTime to = parseDate(to_time); + LocalDateTime from = parseDate(fromTime); + LocalDateTime to = parseDate(toTime); return new Event(description, from, to); } catch (DateTimeParseException e) { - throw new InvalidFormatException("Invalid date format after '/from' or '/to'. Use d/M/yyyy or d/M/yyy H:m in 24-hour format"); + throw new InvalidFormatException("Invalid date format after '/from' or '/to'." + + "Use d/M/yyyy or d/M/yyy H:m in 24-hour format"); } } @@ -113,7 +118,7 @@ public static Event from(String s) throws InvalidArgumentException, InvalidForma */ @Override public String toString() { - return "[E]" + super.toString() + " (from: " + formatDate(from_time) + " to: " + formatDate(to_time) + ")"; + return "[E]" + super.toString() + " (from: " + formatDate(fromTime) + " to: " + formatDate(toTime) + ")"; } /** @@ -122,7 +127,7 @@ public String toString() { * @return The start date-time of the event. */ public LocalDateTime getFromTime() { - return from_time; + return fromTime; } /** @@ -131,7 +136,7 @@ public LocalDateTime getFromTime() { * @return The end date-time of the event. */ public LocalDateTime getToTime() { - return to_time; + return toTime; } /** From 2d22e8c189aa889e8a7659cc7efa13e34549e2c1 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 27 Feb 2024 00:06:27 +0800 Subject: [PATCH 090/153] Added Javadoc for Task class --- src/main/java/dude/Tasks/Event.java | 15 ++++++--------- src/main/java/dude/Tasks/Task.java | 3 +++ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/dude/Tasks/Event.java b/src/main/java/dude/Tasks/Event.java index f02161bf2e..37ae5e161e 100644 --- a/src/main/java/dude/Tasks/Event.java +++ b/src/main/java/dude/Tasks/Event.java @@ -33,21 +33,18 @@ public Event(String description, LocalDateTime fromTime, LocalDateTime toTime) { /** * Static method to create an Event object from parsing a string. + * Expects a string in the format "event /at to " * - * @param s The string to be parsed into an Event object. + * @param input The string to be parsed into an Event object. * @return The Event object created from the string. * @throws InvalidArgumentException If the 'from_time' or 'to_time' of the event is empty. * @throws InvalidFormatException If the format of the string is invalid. * @throws InvalidDescriptionException If the description of the event is empty. */ - public static Event from(String s) throws InvalidArgumentException, + public static Event from(String input) throws InvalidArgumentException, InvalidFormatException, InvalidDescriptionException { - //Expects a string in the format "event /at to " - - //get rid of the command - // time time - String rest = utils.discardFirstWord(s.trim()).trim(); + String rest = utils.discardFirstWord(input.trim()).trim(); String[] arr = rest.split(" "); int fromOccurences = utils.countOccurrences(arr, "/from"); @@ -57,9 +54,9 @@ public static Event from(String s) throws InvalidArgumentException, + ". Provide one and only one '/from'."); } - int toOccurences = utils.countOccurrences(arr, "/to"); + int toOccurrences = utils.countOccurrences(arr, "/to"); - if (toOccurences == 0 || toOccurences > 1) { + if (toOccurrences == 0 || toOccurrences > 1) { throw new InvalidFormatException("Invalid format. Follow this format: " + EventCommand.COMMAND_FORMAT + ". Provide one and only one '/to'."); } diff --git a/src/main/java/dude/Tasks/Task.java b/src/main/java/dude/Tasks/Task.java index 2f5058b4f2..473248cc2c 100644 --- a/src/main/java/dude/Tasks/Task.java +++ b/src/main/java/dude/Tasks/Task.java @@ -6,6 +6,9 @@ import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; +/** + * The Task class represents a task with a description and a status. + */ public class Task implements Serializable { private final String description; private boolean isDone; From 63484c27611cc3f668ba83f2bc24429801227949 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 27 Feb 2024 00:10:04 +0800 Subject: [PATCH 091/153] Updated Event, TaskList, Todo classes to coding standards --- src/main/java/dude/Tasks/Event.java | 2 +- src/main/java/dude/Tasks/TaskList.java | 28 +++++++++++++------------- src/main/java/dude/Tasks/Todo.java | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/main/java/dude/Tasks/Event.java b/src/main/java/dude/Tasks/Event.java index 37ae5e161e..a48a0dba33 100644 --- a/src/main/java/dude/Tasks/Event.java +++ b/src/main/java/dude/Tasks/Event.java @@ -33,7 +33,7 @@ public Event(String description, LocalDateTime fromTime, LocalDateTime toTime) { /** * Static method to create an Event object from parsing a string. - * Expects a string in the format "event /at to " + * Expects a string in the format "event *description* /at *fromTime* to *toTime*" * * @param input The string to be parsed into an Event object. * @return The Event object created from the string. diff --git a/src/main/java/dude/Tasks/TaskList.java b/src/main/java/dude/Tasks/TaskList.java index 0bd50cc2df..c0f42c725b 100644 --- a/src/main/java/dude/Tasks/TaskList.java +++ b/src/main/java/dude/Tasks/TaskList.java @@ -1,8 +1,8 @@ package dude.Tasks; -import dude.Exceptions.DudeException; import java.util.ArrayList; +import dude.Exceptions.DudeException; import dude.Exceptions.TaskListFullException; /** @@ -41,17 +41,17 @@ public static TaskList from(ArrayList tasks) { */ public String add_task(Task task) throws TaskListFullException { - if ( list.size() >= 100) { + if (list.size() >= 100) { throw new TaskListFullException("Sorry, the task list is full."); } list.add(task); - return "\t-----------------------------------\n" + - "\tGot it. I've added this task:\n" + - "\t\t" + task.toString() + "\n" + - "\tNow you have " + list.size() + " tasks in the list.\n" + - "\t-----------------------------------"; + return "\t-----------------------------------\n" + + "\tGot it. I've added this task:\n" + + "\t\t" + task.toString() + "\n" + + "\tNow you have " + list.size() + " tasks in the list.\n" + + "\t-----------------------------------"; } /** @@ -66,11 +66,11 @@ public String remove_task(int taskID) throws DudeException { throw new DudeException("Sorry, the provided id is invalid."); } Task removed = list.remove(taskID - 1); - return "\t-----------------------------------\n" + - "\tNoted. I've removed this task:\n" + - "\t " + removed.toString() + "\n" + - "\tNow you have " + list.size() + " tasks in the list.\n" + - "\t-----------------------------------"; + return "\t-----------------------------------\n" + + "\tNoted. I've removed this task:\n" + + "\t " + removed.toString() + "\n" + + "\tNow you have " + list.size() + " tasks in the list.\n" + + "\t-----------------------------------"; } /** @@ -157,8 +157,8 @@ public int getSize() { */ public Task getTask(int taskID) throws IndexOutOfBoundsException { if (taskID <= 0 || taskID > list.size()) { - throw new IndexOutOfBoundsException("Sorry, the provided id is invalid. " + - "Use the list command to see the list of tasks."); + throw new IndexOutOfBoundsException("Sorry, the provided id is invalid. " + + "Use the list command to see the list of tasks."); } return list.get(taskID - 1); } diff --git a/src/main/java/dude/Tasks/Todo.java b/src/main/java/dude/Tasks/Todo.java index e251c0624f..f5bda1aafe 100644 --- a/src/main/java/dude/Tasks/Todo.java +++ b/src/main/java/dude/Tasks/Todo.java @@ -30,7 +30,7 @@ public static Todo from(String s) throws InvalidDescriptionException { //get rid of the command String description = utils.discardFirstWord(s.trim()).trim(); - if (!description.isEmpty()){ + if (!description.isEmpty()) { return new Todo(description); } else { throw new InvalidDescriptionException("The description of a todo cannot be empty."); From 5015a4321cca07a2407a27091550b69a254e8c2b Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 27 Feb 2024 00:11:03 +0800 Subject: [PATCH 092/153] Updated code to coding standards --- src/main/java/dude/Dude.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/dude/Dude.java b/src/main/java/dude/Dude.java index 89948b0d84..1d1caebd5b 100644 --- a/src/main/java/dude/Dude.java +++ b/src/main/java/dude/Dude.java @@ -42,7 +42,8 @@ public Dude(String filePath) { try { temp = this.storage.loadTasks(); } catch (Exception e) { //Thrown when file gets corrupted - ui.showMessage("An error occurred while loading the tasks. Deleting the storage and starting with an empty task list."); + ui.showMessage("An error occurred while loading the tasks. Deleting the storage and starting with " + + "an empty task list."); this.storage.deleteStorage(); temp = new TaskList(); } From 5350264fc247215081c08dab78b4c2020f45823f Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 27 Feb 2024 00:12:25 +0800 Subject: [PATCH 093/153] Renamed Tasks package to tasks --- src/main/java/dude/Commands/DeadlineCommand.java | 4 ++-- src/main/java/dude/Commands/DeleteCommand.java | 4 ++-- src/main/java/dude/Commands/EventCommand.java | 4 ++-- src/main/java/dude/Commands/ListCommand.java | 2 +- src/main/java/dude/Commands/MarkCommand.java | 4 ++-- src/main/java/dude/Commands/Parser.java | 2 +- src/main/java/dude/Commands/TodoCommand.java | 4 ++-- src/main/java/dude/Commands/UnmarkCommand.java | 4 ++-- src/main/java/dude/Dude.java | 2 +- src/main/java/dude/Utils/Storage.java | 4 ++-- src/main/java/dude/{Tasks => tasks}/Deadline.java | 2 +- src/main/java/dude/{Tasks => tasks}/Event.java | 2 +- src/main/java/dude/{Tasks => tasks}/Task.java | 2 +- src/main/java/dude/{Tasks => tasks}/TaskList.java | 2 +- src/main/java/dude/{Tasks => tasks}/Todo.java | 2 +- src/test/java/dude/Commands/ParserTest.java | 4 ++-- src/test/java/dude/Utils/StorageTest.java | 6 +++--- src/test/java/dude/{Tasks => tasks}/DeadlineTest.java | 2 +- src/test/java/dude/{Tasks => tasks}/EventTest.java | 2 +- src/test/java/dude/{Tasks => tasks}/TodoTest.java | 2 +- 20 files changed, 30 insertions(+), 30 deletions(-) rename src/main/java/dude/{Tasks => tasks}/Deadline.java (99%) rename src/main/java/dude/{Tasks => tasks}/Event.java (99%) rename src/main/java/dude/{Tasks => tasks}/Task.java (99%) rename src/main/java/dude/{Tasks => tasks}/TaskList.java (99%) rename src/main/java/dude/{Tasks => tasks}/Todo.java (98%) rename src/test/java/dude/{Tasks => tasks}/DeadlineTest.java (97%) rename src/test/java/dude/{Tasks => tasks}/EventTest.java (98%) rename src/test/java/dude/{Tasks => tasks}/TodoTest.java (97%) diff --git a/src/main/java/dude/Commands/DeadlineCommand.java b/src/main/java/dude/Commands/DeadlineCommand.java index 5af6938f56..6ee29fd82d 100644 --- a/src/main/java/dude/Commands/DeadlineCommand.java +++ b/src/main/java/dude/Commands/DeadlineCommand.java @@ -2,8 +2,8 @@ import dude.Exceptions.DudeException; import dude.Exceptions.InvalidFormatException; -import dude.Tasks.Deadline; -import dude.Tasks.TaskList; +import dude.tasks.Deadline; +import dude.tasks.TaskList; /** * The DeadlineCommand class represents a command to add a deadline task to the TaskList object. diff --git a/src/main/java/dude/Commands/DeleteCommand.java b/src/main/java/dude/Commands/DeleteCommand.java index a61f7c90bb..87dd73ea32 100644 --- a/src/main/java/dude/Commands/DeleteCommand.java +++ b/src/main/java/dude/Commands/DeleteCommand.java @@ -2,8 +2,8 @@ import dude.Exceptions.DudeException; import dude.Exceptions.InvalidFormatException; -import dude.Tasks.Task; -import dude.Tasks.TaskList; +import dude.tasks.Task; +import dude.tasks.TaskList; /** * The DeleteCommand class represents a command to delete a task from the TaskList object. diff --git a/src/main/java/dude/Commands/EventCommand.java b/src/main/java/dude/Commands/EventCommand.java index 5cb8641160..ff0e2f2cef 100644 --- a/src/main/java/dude/Commands/EventCommand.java +++ b/src/main/java/dude/Commands/EventCommand.java @@ -2,8 +2,8 @@ import dude.Exceptions.DudeException; import dude.Exceptions.InvalidFormatException; -import dude.Tasks.Event; -import dude.Tasks.TaskList; +import dude.tasks.Event; +import dude.tasks.TaskList; /** * The EventCommand class represents a command that adds an event to the TaskList object. diff --git a/src/main/java/dude/Commands/ListCommand.java b/src/main/java/dude/Commands/ListCommand.java index 5c1babff20..8d41d057e6 100644 --- a/src/main/java/dude/Commands/ListCommand.java +++ b/src/main/java/dude/Commands/ListCommand.java @@ -1,6 +1,6 @@ package dude.Commands; -import dude.Tasks.TaskList; +import dude.tasks.TaskList; /** * The ListCommand class represents a command to list all the tasks in the TaskList object. diff --git a/src/main/java/dude/Commands/MarkCommand.java b/src/main/java/dude/Commands/MarkCommand.java index f18c8dfded..66b3263f2e 100644 --- a/src/main/java/dude/Commands/MarkCommand.java +++ b/src/main/java/dude/Commands/MarkCommand.java @@ -2,8 +2,8 @@ import dude.Exceptions.DudeException; import dude.Exceptions.InvalidFormatException; -import dude.Tasks.Task; -import dude.Tasks.TaskList; +import dude.tasks.Task; +import dude.tasks.TaskList; /** * The MarkCommand class represents a command to mark a task as done in the TaskList object. diff --git a/src/main/java/dude/Commands/Parser.java b/src/main/java/dude/Commands/Parser.java index 45be667d36..b278876529 100644 --- a/src/main/java/dude/Commands/Parser.java +++ b/src/main/java/dude/Commands/Parser.java @@ -1,6 +1,6 @@ package dude.Commands; -import dude.Tasks.TaskList; +import dude.tasks.TaskList; /** * The Parser class is responsible for parsing the user input and returning the appropriate command. diff --git a/src/main/java/dude/Commands/TodoCommand.java b/src/main/java/dude/Commands/TodoCommand.java index 34259d538b..ae24b081f4 100644 --- a/src/main/java/dude/Commands/TodoCommand.java +++ b/src/main/java/dude/Commands/TodoCommand.java @@ -2,8 +2,8 @@ import dude.Exceptions.DudeException; import dude.Exceptions.InvalidFormatException; -import dude.Tasks.TaskList; -import dude.Tasks.Todo; +import dude.tasks.TaskList; +import dude.tasks.Todo; /** * The TodoCommand class represents a command to add a todo task to the TaskList object. diff --git a/src/main/java/dude/Commands/UnmarkCommand.java b/src/main/java/dude/Commands/UnmarkCommand.java index e7ee4a352a..71a33655d6 100644 --- a/src/main/java/dude/Commands/UnmarkCommand.java +++ b/src/main/java/dude/Commands/UnmarkCommand.java @@ -2,8 +2,8 @@ import dude.Exceptions.DudeException; import dude.Exceptions.InvalidFormatException; -import dude.Tasks.Task; -import dude.Tasks.TaskList; +import dude.tasks.Task; +import dude.tasks.TaskList; /** * The UnmarkCommand class represents a command to mark a task as not done in the task list. diff --git a/src/main/java/dude/Dude.java b/src/main/java/dude/Dude.java index 1d1caebd5b..7ba2c35106 100644 --- a/src/main/java/dude/Dude.java +++ b/src/main/java/dude/Dude.java @@ -7,7 +7,7 @@ import dude.Commands.CommandTypes; import dude.Commands.Parser; import dude.Exceptions.DudeException; -import dude.Tasks.TaskList; +import dude.tasks.TaskList; import dude.Utils.Storage; import dude.Utils.Ui; diff --git a/src/main/java/dude/Utils/Storage.java b/src/main/java/dude/Utils/Storage.java index 120a2deed4..7654b068b8 100644 --- a/src/main/java/dude/Utils/Storage.java +++ b/src/main/java/dude/Utils/Storage.java @@ -8,8 +8,8 @@ import java.io.ObjectOutputStream; import java.util.ArrayList; -import dude.Tasks.Task; -import dude.Tasks.TaskList; +import dude.tasks.Task; +import dude.tasks.TaskList; /** diff --git a/src/main/java/dude/Tasks/Deadline.java b/src/main/java/dude/tasks/Deadline.java similarity index 99% rename from src/main/java/dude/Tasks/Deadline.java rename to src/main/java/dude/tasks/Deadline.java index 03a1b232e7..e6a839fbbf 100644 --- a/src/main/java/dude/Tasks/Deadline.java +++ b/src/main/java/dude/tasks/Deadline.java @@ -1,4 +1,4 @@ -package dude.Tasks; +package dude.tasks; import java.time.LocalDateTime; import java.time.format.DateTimeParseException; diff --git a/src/main/java/dude/Tasks/Event.java b/src/main/java/dude/tasks/Event.java similarity index 99% rename from src/main/java/dude/Tasks/Event.java rename to src/main/java/dude/tasks/Event.java index a48a0dba33..9b9d4e5a6f 100644 --- a/src/main/java/dude/Tasks/Event.java +++ b/src/main/java/dude/tasks/Event.java @@ -1,4 +1,4 @@ -package dude.Tasks; +package dude.tasks; import java.time.LocalDateTime; import java.time.format.DateTimeParseException; diff --git a/src/main/java/dude/Tasks/Task.java b/src/main/java/dude/tasks/Task.java similarity index 99% rename from src/main/java/dude/Tasks/Task.java rename to src/main/java/dude/tasks/Task.java index 473248cc2c..7a300b6aa7 100644 --- a/src/main/java/dude/Tasks/Task.java +++ b/src/main/java/dude/tasks/Task.java @@ -1,4 +1,4 @@ -package dude.Tasks; +package dude.tasks; import java.io.Serializable; import java.time.LocalDate; diff --git a/src/main/java/dude/Tasks/TaskList.java b/src/main/java/dude/tasks/TaskList.java similarity index 99% rename from src/main/java/dude/Tasks/TaskList.java rename to src/main/java/dude/tasks/TaskList.java index c0f42c725b..f0553c09c7 100644 --- a/src/main/java/dude/Tasks/TaskList.java +++ b/src/main/java/dude/tasks/TaskList.java @@ -1,4 +1,4 @@ -package dude.Tasks; +package dude.tasks; import java.util.ArrayList; diff --git a/src/main/java/dude/Tasks/Todo.java b/src/main/java/dude/tasks/Todo.java similarity index 98% rename from src/main/java/dude/Tasks/Todo.java rename to src/main/java/dude/tasks/Todo.java index f5bda1aafe..7a69d5683e 100644 --- a/src/main/java/dude/Tasks/Todo.java +++ b/src/main/java/dude/tasks/Todo.java @@ -1,4 +1,4 @@ -package dude.Tasks; +package dude.tasks; import dude.Exceptions.InvalidDescriptionException; import dude.Utils.utils; diff --git a/src/test/java/dude/Commands/ParserTest.java b/src/test/java/dude/Commands/ParserTest.java index 9c42a8480e..27b886bde2 100644 --- a/src/test/java/dude/Commands/ParserTest.java +++ b/src/test/java/dude/Commands/ParserTest.java @@ -3,8 +3,8 @@ import dude.Exceptions.DudeException; import dude.Exceptions.InvalidDescriptionException; import dude.Exceptions.TaskListFullException; -import dude.Tasks.TaskList; -import dude.Tasks.Todo; +import dude.tasks.TaskList; +import dude.tasks.Todo; import org.junit.jupiter.api.Test; public class ParserTest { diff --git a/src/test/java/dude/Utils/StorageTest.java b/src/test/java/dude/Utils/StorageTest.java index 59698200ed..26f195fecd 100644 --- a/src/test/java/dude/Utils/StorageTest.java +++ b/src/test/java/dude/Utils/StorageTest.java @@ -1,9 +1,9 @@ package dude.Utils; import dude.Exceptions.TaskListFullException; -import dude.Tasks.Task; -import dude.Tasks.TaskList; -import dude.Tasks.Todo; +import dude.tasks.Task; +import dude.tasks.TaskList; +import dude.tasks.Todo; import org.junit.jupiter.api.Test; import java.util.ArrayList; diff --git a/src/test/java/dude/Tasks/DeadlineTest.java b/src/test/java/dude/tasks/DeadlineTest.java similarity index 97% rename from src/test/java/dude/Tasks/DeadlineTest.java rename to src/test/java/dude/tasks/DeadlineTest.java index 065b271d7d..f6401bb52e 100644 --- a/src/test/java/dude/Tasks/DeadlineTest.java +++ b/src/test/java/dude/tasks/DeadlineTest.java @@ -1,4 +1,4 @@ -package dude.Tasks; +package dude.tasks; import org.junit.jupiter.api.Test; diff --git a/src/test/java/dude/Tasks/EventTest.java b/src/test/java/dude/tasks/EventTest.java similarity index 98% rename from src/test/java/dude/Tasks/EventTest.java rename to src/test/java/dude/tasks/EventTest.java index 1f4ffc3bb6..50ae8b056d 100644 --- a/src/test/java/dude/Tasks/EventTest.java +++ b/src/test/java/dude/tasks/EventTest.java @@ -1,4 +1,4 @@ -package dude.Tasks; +package dude.tasks; import org.junit.jupiter.api.Test; diff --git a/src/test/java/dude/Tasks/TodoTest.java b/src/test/java/dude/tasks/TodoTest.java similarity index 97% rename from src/test/java/dude/Tasks/TodoTest.java rename to src/test/java/dude/tasks/TodoTest.java index cc51e51de8..072b553625 100644 --- a/src/test/java/dude/Tasks/TodoTest.java +++ b/src/test/java/dude/tasks/TodoTest.java @@ -1,4 +1,4 @@ -package dude.Tasks; +package dude.tasks; import org.junit.jupiter.api.Test; From 96f3f5e4cdb3734409a336a92b4d8b5df571cd57 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 27 Feb 2024 00:19:11 +0800 Subject: [PATCH 094/153] Renamed all packages to lower-case --- src/main/java/dude/Dude.java | 13 +++++++------ .../dude/{Commands => commands}/ByeCommand.java | 2 +- .../java/dude/{Commands => commands}/Command.java | 4 ++-- .../dude/{Commands => commands}/CommandTypes.java | 2 +- .../{Commands => commands}/DeadlineCommand.java | 6 +++--- .../dude/{Commands => commands}/DeleteCommand.java | 6 +++--- .../dude/{Commands => commands}/EventCommand.java | 6 +++--- .../dude/{Commands => commands}/HelpCommand.java | 4 ++-- .../dude/{Commands => commands}/InvalidCommand.java | 2 +- .../dude/{Commands => commands}/ListCommand.java | 2 +- .../dude/{Commands => commands}/MarkCommand.java | 6 +++--- .../java/dude/{Commands => commands}/Parser.java | 2 +- .../dude/{Commands => commands}/TodoCommand.java | 6 +++--- .../dude/{Commands => commands}/UnmarkCommand.java | 6 +++--- .../{Exceptions => exceptions}/DudeException.java | 2 +- .../InvalidArgumentException.java | 2 +- .../InvalidCommandException.java | 2 +- .../InvalidDescriptionException.java | 2 +- .../InvalidFormatException.java | 2 +- .../TaskListFullException.java | 2 +- src/main/java/dude/tasks/Deadline.java | 8 ++++---- src/main/java/dude/tasks/Event.java | 10 +++++----- src/main/java/dude/tasks/TaskList.java | 4 ++-- src/main/java/dude/tasks/Todo.java | 4 ++-- src/main/java/dude/{Utils => utils}/Storage.java | 2 +- src/main/java/dude/{Utils => utils}/Ui.java | 2 +- src/main/java/dude/{Utils => utils}/utils.java | 2 +- .../dude/{Commands => commands}/ParserTest.java | 8 ++++---- .../java/dude/{Utils => utils}/StorageTest.java | 4 ++-- 29 files changed, 62 insertions(+), 61 deletions(-) rename src/main/java/dude/{Commands => commands}/ByeCommand.java (95%) rename src/main/java/dude/{Commands => commands}/Command.java (95%) rename src/main/java/dude/{Commands => commands}/CommandTypes.java (91%) rename src/main/java/dude/{Commands => commands}/DeadlineCommand.java (94%) rename src/main/java/dude/{Commands => commands}/DeleteCommand.java (94%) rename src/main/java/dude/{Commands => commands}/EventCommand.java (94%) rename src/main/java/dude/{Commands => commands}/HelpCommand.java (98%) rename src/main/java/dude/{Commands => commands}/InvalidCommand.java (96%) rename src/main/java/dude/{Commands => commands}/ListCommand.java (97%) rename src/main/java/dude/{Commands => commands}/MarkCommand.java (94%) rename src/main/java/dude/{Commands => commands}/Parser.java (98%) rename src/main/java/dude/{Commands => commands}/TodoCommand.java (94%) rename src/main/java/dude/{Commands => commands}/UnmarkCommand.java (94%) rename src/main/java/dude/{Exceptions => exceptions}/DudeException.java (93%) rename src/main/java/dude/{Exceptions => exceptions}/InvalidArgumentException.java (94%) rename src/main/java/dude/{Exceptions => exceptions}/InvalidCommandException.java (94%) rename src/main/java/dude/{Exceptions => exceptions}/InvalidDescriptionException.java (94%) rename src/main/java/dude/{Exceptions => exceptions}/InvalidFormatException.java (98%) rename src/main/java/dude/{Exceptions => exceptions}/TaskListFullException.java (93%) rename src/main/java/dude/{Utils => utils}/Storage.java (99%) rename src/main/java/dude/{Utils => utils}/Ui.java (97%) rename src/main/java/dude/{Utils => utils}/utils.java (98%) rename src/test/java/dude/{Commands => commands}/ParserTest.java (93%) rename src/test/java/dude/{Utils => utils}/StorageTest.java (94%) diff --git a/src/main/java/dude/Dude.java b/src/main/java/dude/Dude.java index 7ba2c35106..e9217bc43d 100644 --- a/src/main/java/dude/Dude.java +++ b/src/main/java/dude/Dude.java @@ -3,13 +3,14 @@ import java.util.NoSuchElementException; import java.util.Scanner; -import dude.Commands.Command; -import dude.Commands.CommandTypes; -import dude.Commands.Parser; -import dude.Exceptions.DudeException; +import dude.commands.Command; +import dude.commands.CommandTypes; +import dude.commands.Parser; +import dude.exceptions.DudeException; +import dude.utils.Storage; +import dude.utils.Ui; import dude.tasks.TaskList; -import dude.Utils.Storage; -import dude.Utils.Ui; + /** * The main class of the Duke application. diff --git a/src/main/java/dude/Commands/ByeCommand.java b/src/main/java/dude/commands/ByeCommand.java similarity index 95% rename from src/main/java/dude/Commands/ByeCommand.java rename to src/main/java/dude/commands/ByeCommand.java index 105eb788cf..1e526e1c34 100644 --- a/src/main/java/dude/Commands/ByeCommand.java +++ b/src/main/java/dude/commands/ByeCommand.java @@ -1,4 +1,4 @@ -package dude.Commands; +package dude.commands; /** * The ByeCommand class represents a command to exit the program. diff --git a/src/main/java/dude/Commands/Command.java b/src/main/java/dude/commands/Command.java similarity index 95% rename from src/main/java/dude/Commands/Command.java rename to src/main/java/dude/commands/Command.java index 6461c24d30..46c351fb74 100644 --- a/src/main/java/dude/Commands/Command.java +++ b/src/main/java/dude/commands/Command.java @@ -1,6 +1,6 @@ -package dude.Commands; +package dude.commands; -import dude.Exceptions.DudeException; +import dude.exceptions.DudeException; /** * The Command class represents a command that can be executed by the user. diff --git a/src/main/java/dude/Commands/CommandTypes.java b/src/main/java/dude/commands/CommandTypes.java similarity index 91% rename from src/main/java/dude/Commands/CommandTypes.java rename to src/main/java/dude/commands/CommandTypes.java index e08aef9b14..7bfbac1f95 100644 --- a/src/main/java/dude/Commands/CommandTypes.java +++ b/src/main/java/dude/commands/CommandTypes.java @@ -1,4 +1,4 @@ -package dude.Commands; +package dude.commands; /** * The CommandTypes enum represents the types of commands that can be used in the application. diff --git a/src/main/java/dude/Commands/DeadlineCommand.java b/src/main/java/dude/commands/DeadlineCommand.java similarity index 94% rename from src/main/java/dude/Commands/DeadlineCommand.java rename to src/main/java/dude/commands/DeadlineCommand.java index 6ee29fd82d..164e48a45f 100644 --- a/src/main/java/dude/Commands/DeadlineCommand.java +++ b/src/main/java/dude/commands/DeadlineCommand.java @@ -1,7 +1,7 @@ -package dude.Commands; +package dude.commands; -import dude.Exceptions.DudeException; -import dude.Exceptions.InvalidFormatException; +import dude.exceptions.DudeException; +import dude.exceptions.InvalidFormatException; import dude.tasks.Deadline; import dude.tasks.TaskList; diff --git a/src/main/java/dude/Commands/DeleteCommand.java b/src/main/java/dude/commands/DeleteCommand.java similarity index 94% rename from src/main/java/dude/Commands/DeleteCommand.java rename to src/main/java/dude/commands/DeleteCommand.java index 87dd73ea32..8b168e90e9 100644 --- a/src/main/java/dude/Commands/DeleteCommand.java +++ b/src/main/java/dude/commands/DeleteCommand.java @@ -1,7 +1,7 @@ -package dude.Commands; +package dude.commands; -import dude.Exceptions.DudeException; -import dude.Exceptions.InvalidFormatException; +import dude.exceptions.DudeException; +import dude.exceptions.InvalidFormatException; import dude.tasks.Task; import dude.tasks.TaskList; diff --git a/src/main/java/dude/Commands/EventCommand.java b/src/main/java/dude/commands/EventCommand.java similarity index 94% rename from src/main/java/dude/Commands/EventCommand.java rename to src/main/java/dude/commands/EventCommand.java index ff0e2f2cef..932c8e5d8e 100644 --- a/src/main/java/dude/Commands/EventCommand.java +++ b/src/main/java/dude/commands/EventCommand.java @@ -1,7 +1,7 @@ -package dude.Commands; +package dude.commands; -import dude.Exceptions.DudeException; -import dude.Exceptions.InvalidFormatException; +import dude.exceptions.DudeException; +import dude.exceptions.InvalidFormatException; import dude.tasks.Event; import dude.tasks.TaskList; diff --git a/src/main/java/dude/Commands/HelpCommand.java b/src/main/java/dude/commands/HelpCommand.java similarity index 98% rename from src/main/java/dude/Commands/HelpCommand.java rename to src/main/java/dude/commands/HelpCommand.java index ad976ba44d..404fed4a12 100644 --- a/src/main/java/dude/Commands/HelpCommand.java +++ b/src/main/java/dude/commands/HelpCommand.java @@ -1,6 +1,6 @@ -package dude.Commands; +package dude.commands; -import dude.Exceptions.DudeException; +import dude.exceptions.DudeException; /** * The HelpCommand class represents a command that provides help on the commands the application supports. diff --git a/src/main/java/dude/Commands/InvalidCommand.java b/src/main/java/dude/commands/InvalidCommand.java similarity index 96% rename from src/main/java/dude/Commands/InvalidCommand.java rename to src/main/java/dude/commands/InvalidCommand.java index cc77e6f027..e4cbdeeda7 100644 --- a/src/main/java/dude/Commands/InvalidCommand.java +++ b/src/main/java/dude/commands/InvalidCommand.java @@ -1,4 +1,4 @@ -package dude.Commands; +package dude.commands; /** * The InvalidCommand class represents a command that is invalid. diff --git a/src/main/java/dude/Commands/ListCommand.java b/src/main/java/dude/commands/ListCommand.java similarity index 97% rename from src/main/java/dude/Commands/ListCommand.java rename to src/main/java/dude/commands/ListCommand.java index 8d41d057e6..1245b776cc 100644 --- a/src/main/java/dude/Commands/ListCommand.java +++ b/src/main/java/dude/commands/ListCommand.java @@ -1,4 +1,4 @@ -package dude.Commands; +package dude.commands; import dude.tasks.TaskList; diff --git a/src/main/java/dude/Commands/MarkCommand.java b/src/main/java/dude/commands/MarkCommand.java similarity index 94% rename from src/main/java/dude/Commands/MarkCommand.java rename to src/main/java/dude/commands/MarkCommand.java index 66b3263f2e..2b2ced532e 100644 --- a/src/main/java/dude/Commands/MarkCommand.java +++ b/src/main/java/dude/commands/MarkCommand.java @@ -1,7 +1,7 @@ -package dude.Commands; +package dude.commands; -import dude.Exceptions.DudeException; -import dude.Exceptions.InvalidFormatException; +import dude.exceptions.DudeException; +import dude.exceptions.InvalidFormatException; import dude.tasks.Task; import dude.tasks.TaskList; diff --git a/src/main/java/dude/Commands/Parser.java b/src/main/java/dude/commands/Parser.java similarity index 98% rename from src/main/java/dude/Commands/Parser.java rename to src/main/java/dude/commands/Parser.java index b278876529..82058fcdf5 100644 --- a/src/main/java/dude/Commands/Parser.java +++ b/src/main/java/dude/commands/Parser.java @@ -1,4 +1,4 @@ -package dude.Commands; +package dude.commands; import dude.tasks.TaskList; diff --git a/src/main/java/dude/Commands/TodoCommand.java b/src/main/java/dude/commands/TodoCommand.java similarity index 94% rename from src/main/java/dude/Commands/TodoCommand.java rename to src/main/java/dude/commands/TodoCommand.java index ae24b081f4..6cb7e6b829 100644 --- a/src/main/java/dude/Commands/TodoCommand.java +++ b/src/main/java/dude/commands/TodoCommand.java @@ -1,7 +1,7 @@ -package dude.Commands; +package dude.commands; -import dude.Exceptions.DudeException; -import dude.Exceptions.InvalidFormatException; +import dude.exceptions.DudeException; +import dude.exceptions.InvalidFormatException; import dude.tasks.TaskList; import dude.tasks.Todo; diff --git a/src/main/java/dude/Commands/UnmarkCommand.java b/src/main/java/dude/commands/UnmarkCommand.java similarity index 94% rename from src/main/java/dude/Commands/UnmarkCommand.java rename to src/main/java/dude/commands/UnmarkCommand.java index 71a33655d6..57082945fb 100644 --- a/src/main/java/dude/Commands/UnmarkCommand.java +++ b/src/main/java/dude/commands/UnmarkCommand.java @@ -1,7 +1,7 @@ -package dude.Commands; +package dude.commands; -import dude.Exceptions.DudeException; -import dude.Exceptions.InvalidFormatException; +import dude.exceptions.DudeException; +import dude.exceptions.InvalidFormatException; import dude.tasks.Task; import dude.tasks.TaskList; diff --git a/src/main/java/dude/Exceptions/DudeException.java b/src/main/java/dude/exceptions/DudeException.java similarity index 93% rename from src/main/java/dude/Exceptions/DudeException.java rename to src/main/java/dude/exceptions/DudeException.java index 614b2f4a90..7adeaf7708 100644 --- a/src/main/java/dude/Exceptions/DudeException.java +++ b/src/main/java/dude/exceptions/DudeException.java @@ -1,4 +1,4 @@ -package dude.Exceptions; +package dude.exceptions; /** * The DudeException class represents an exception that is specific to the Dude application. diff --git a/src/main/java/dude/Exceptions/InvalidArgumentException.java b/src/main/java/dude/exceptions/InvalidArgumentException.java similarity index 94% rename from src/main/java/dude/Exceptions/InvalidArgumentException.java rename to src/main/java/dude/exceptions/InvalidArgumentException.java index b8905f8bb5..fa84936cb2 100644 --- a/src/main/java/dude/Exceptions/InvalidArgumentException.java +++ b/src/main/java/dude/exceptions/InvalidArgumentException.java @@ -1,4 +1,4 @@ -package dude.Exceptions; +package dude.exceptions; /** * The InvalidArgumentException class represents an exception that is thrown when an argument for a command is invalid. diff --git a/src/main/java/dude/Exceptions/InvalidCommandException.java b/src/main/java/dude/exceptions/InvalidCommandException.java similarity index 94% rename from src/main/java/dude/Exceptions/InvalidCommandException.java rename to src/main/java/dude/exceptions/InvalidCommandException.java index 09aefc86de..8c1c6cb8c8 100644 --- a/src/main/java/dude/Exceptions/InvalidCommandException.java +++ b/src/main/java/dude/exceptions/InvalidCommandException.java @@ -1,4 +1,4 @@ -package dude.Exceptions; +package dude.exceptions; /** * The InvalidCommandException class represents an exception that is thrown when the command is invalid. diff --git a/src/main/java/dude/Exceptions/InvalidDescriptionException.java b/src/main/java/dude/exceptions/InvalidDescriptionException.java similarity index 94% rename from src/main/java/dude/Exceptions/InvalidDescriptionException.java rename to src/main/java/dude/exceptions/InvalidDescriptionException.java index 0ce6a8106b..5dbab919c2 100644 --- a/src/main/java/dude/Exceptions/InvalidDescriptionException.java +++ b/src/main/java/dude/exceptions/InvalidDescriptionException.java @@ -1,4 +1,4 @@ -package dude.Exceptions; +package dude.exceptions; /** * The InvalidDescriptionException class represents an exception that is thrown when the description for a task is invalid. diff --git a/src/main/java/dude/Exceptions/InvalidFormatException.java b/src/main/java/dude/exceptions/InvalidFormatException.java similarity index 98% rename from src/main/java/dude/Exceptions/InvalidFormatException.java rename to src/main/java/dude/exceptions/InvalidFormatException.java index 2f526bffe7..136711944a 100644 --- a/src/main/java/dude/Exceptions/InvalidFormatException.java +++ b/src/main/java/dude/exceptions/InvalidFormatException.java @@ -1,4 +1,4 @@ -package dude.Exceptions; +package dude.exceptions; /** * The InvalidFormatException class represents an exception that is thrown when the format is invalid. diff --git a/src/main/java/dude/Exceptions/TaskListFullException.java b/src/main/java/dude/exceptions/TaskListFullException.java similarity index 93% rename from src/main/java/dude/Exceptions/TaskListFullException.java rename to src/main/java/dude/exceptions/TaskListFullException.java index 41e12a79c5..b2b1426a04 100644 --- a/src/main/java/dude/Exceptions/TaskListFullException.java +++ b/src/main/java/dude/exceptions/TaskListFullException.java @@ -1,4 +1,4 @@ -package dude.Exceptions; +package dude.exceptions; /** * The TaskListFullException class represents an exception that is thrown when the task list is full. diff --git a/src/main/java/dude/tasks/Deadline.java b/src/main/java/dude/tasks/Deadline.java index e6a839fbbf..e05dbef3f4 100644 --- a/src/main/java/dude/tasks/Deadline.java +++ b/src/main/java/dude/tasks/Deadline.java @@ -3,10 +3,10 @@ import java.time.LocalDateTime; import java.time.format.DateTimeParseException; -import dude.Exceptions.InvalidArgumentException; -import dude.Exceptions.InvalidDescriptionException; -import dude.Exceptions.InvalidFormatException; -import dude.Utils.utils; +import dude.exceptions.InvalidArgumentException; +import dude.exceptions.InvalidDescriptionException; +import dude.exceptions.InvalidFormatException; +import dude.utils.utils; /** diff --git a/src/main/java/dude/tasks/Event.java b/src/main/java/dude/tasks/Event.java index 9b9d4e5a6f..7ce41d0cd3 100644 --- a/src/main/java/dude/tasks/Event.java +++ b/src/main/java/dude/tasks/Event.java @@ -3,11 +3,11 @@ import java.time.LocalDateTime; import java.time.format.DateTimeParseException; -import dude.Commands.EventCommand; -import dude.Exceptions.InvalidArgumentException; -import dude.Exceptions.InvalidDescriptionException; -import dude.Exceptions.InvalidFormatException; -import dude.Utils.utils; +import dude.commands.EventCommand; +import dude.exceptions.InvalidArgumentException; +import dude.exceptions.InvalidDescriptionException; +import dude.exceptions.InvalidFormatException; +import dude.utils.utils; /** diff --git a/src/main/java/dude/tasks/TaskList.java b/src/main/java/dude/tasks/TaskList.java index f0553c09c7..7d0b267eaa 100644 --- a/src/main/java/dude/tasks/TaskList.java +++ b/src/main/java/dude/tasks/TaskList.java @@ -2,8 +2,8 @@ import java.util.ArrayList; -import dude.Exceptions.DudeException; -import dude.Exceptions.TaskListFullException; +import dude.exceptions.DudeException; +import dude.exceptions.TaskListFullException; /** * The TaskList class handles keeping track of the list of tasks. diff --git a/src/main/java/dude/tasks/Todo.java b/src/main/java/dude/tasks/Todo.java index 7a69d5683e..9a39831573 100644 --- a/src/main/java/dude/tasks/Todo.java +++ b/src/main/java/dude/tasks/Todo.java @@ -1,7 +1,7 @@ package dude.tasks; -import dude.Exceptions.InvalidDescriptionException; -import dude.Utils.utils; +import dude.exceptions.InvalidDescriptionException; +import dude.utils.utils; /** * The Todo class represents a task with a description. diff --git a/src/main/java/dude/Utils/Storage.java b/src/main/java/dude/utils/Storage.java similarity index 99% rename from src/main/java/dude/Utils/Storage.java rename to src/main/java/dude/utils/Storage.java index 7654b068b8..1ec0c6017e 100644 --- a/src/main/java/dude/Utils/Storage.java +++ b/src/main/java/dude/utils/Storage.java @@ -1,4 +1,4 @@ -package dude.Utils; +package dude.utils; import java.io.File; import java.io.FileInputStream; diff --git a/src/main/java/dude/Utils/Ui.java b/src/main/java/dude/utils/Ui.java similarity index 97% rename from src/main/java/dude/Utils/Ui.java rename to src/main/java/dude/utils/Ui.java index ada4a13168..7a2d7c0d94 100644 --- a/src/main/java/dude/Utils/Ui.java +++ b/src/main/java/dude/utils/Ui.java @@ -1,4 +1,4 @@ -package dude.Utils; +package dude.utils; /** * The Ui class handles the user interface of the application. diff --git a/src/main/java/dude/Utils/utils.java b/src/main/java/dude/utils/utils.java similarity index 98% rename from src/main/java/dude/Utils/utils.java rename to src/main/java/dude/utils/utils.java index acb9f4a242..5a1cfc44df 100644 --- a/src/main/java/dude/Utils/utils.java +++ b/src/main/java/dude/utils/utils.java @@ -1,4 +1,4 @@ -package dude.Utils; +package dude.utils; public class utils { diff --git a/src/test/java/dude/Commands/ParserTest.java b/src/test/java/dude/commands/ParserTest.java similarity index 93% rename from src/test/java/dude/Commands/ParserTest.java rename to src/test/java/dude/commands/ParserTest.java index 27b886bde2..6b80b33e8b 100644 --- a/src/test/java/dude/Commands/ParserTest.java +++ b/src/test/java/dude/commands/ParserTest.java @@ -1,8 +1,8 @@ -package dude.Commands; +package dude.commands; -import dude.Exceptions.DudeException; -import dude.Exceptions.InvalidDescriptionException; -import dude.Exceptions.TaskListFullException; +import dude.exceptions.DudeException; +import dude.exceptions.InvalidDescriptionException; +import dude.exceptions.TaskListFullException; import dude.tasks.TaskList; import dude.tasks.Todo; import org.junit.jupiter.api.Test; diff --git a/src/test/java/dude/Utils/StorageTest.java b/src/test/java/dude/utils/StorageTest.java similarity index 94% rename from src/test/java/dude/Utils/StorageTest.java rename to src/test/java/dude/utils/StorageTest.java index 26f195fecd..6323466f11 100644 --- a/src/test/java/dude/Utils/StorageTest.java +++ b/src/test/java/dude/utils/StorageTest.java @@ -1,6 +1,6 @@ -package dude.Utils; +package dude.utils; -import dude.Exceptions.TaskListFullException; +import dude.exceptions.TaskListFullException; import dude.tasks.Task; import dude.tasks.TaskList; import dude.tasks.Todo; From 629cbc2a838835a6425ba8eed211f321badc0efa Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 27 Feb 2024 00:24:32 +0800 Subject: [PATCH 095/153] Updated to coding Standards --- src/main/java/dude/Dude.java | 2 +- src/main/java/dude/commands/DeadlineCommand.java | 4 ++-- src/main/java/dude/commands/DeleteCommand.java | 3 ++- src/main/java/dude/commands/EventCommand.java | 5 +++-- src/main/java/dude/commands/HelpCommand.java | 5 +++-- .../dude/exceptions/InvalidDescriptionException.java | 3 ++- .../java/dude/exceptions/InvalidFormatException.java | 11 ++++++----- src/main/java/dude/tasks/Deadline.java | 2 +- 8 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/main/java/dude/Dude.java b/src/main/java/dude/Dude.java index e9217bc43d..6dcb7d1777 100644 --- a/src/main/java/dude/Dude.java +++ b/src/main/java/dude/Dude.java @@ -7,9 +7,9 @@ import dude.commands.CommandTypes; import dude.commands.Parser; import dude.exceptions.DudeException; +import dude.tasks.TaskList; import dude.utils.Storage; import dude.utils.Ui; -import dude.tasks.TaskList; /** diff --git a/src/main/java/dude/commands/DeadlineCommand.java b/src/main/java/dude/commands/DeadlineCommand.java index 164e48a45f..c3a14f6e5d 100644 --- a/src/main/java/dude/commands/DeadlineCommand.java +++ b/src/main/java/dude/commands/DeadlineCommand.java @@ -15,8 +15,8 @@ public class DeadlineCommand extends Command { private final TaskList taskList; /** - * Constructor for the DeadlineCommand class. Returns a command object to add a deadline task to the TaskList object upon - * execution. + * Constructor for the DeadlineCommand class. Returns a command object to add a deadline task to + * the TaskList object upon execution. * * @param input The input string that resulted in the creation of this command. * @param tasklist The TaskList object to which the deadline task is to be added. diff --git a/src/main/java/dude/commands/DeleteCommand.java b/src/main/java/dude/commands/DeleteCommand.java index 8b168e90e9..d8c1b95404 100644 --- a/src/main/java/dude/commands/DeleteCommand.java +++ b/src/main/java/dude/commands/DeleteCommand.java @@ -9,10 +9,11 @@ * The DeleteCommand class represents a command to delete a task from the TaskList object. */ public class DeleteCommand extends Command { + + private static final String COMMAND_FORMAT = "delete "; private final String input; private final TaskList taskList; - private static final String COMMAND_FORMAT = "delete "; /** * Constructor for the DeleteCommand class. Returns a command object to delete a task from the TaskList object upon diff --git a/src/main/java/dude/commands/EventCommand.java b/src/main/java/dude/commands/EventCommand.java index 932c8e5d8e..19b83e06e7 100644 --- a/src/main/java/dude/commands/EventCommand.java +++ b/src/main/java/dude/commands/EventCommand.java @@ -9,11 +9,12 @@ * The EventCommand class represents a command that adds an event to the TaskList object. */ public class EventCommand extends Command { - private final String input; - private final TaskList taskList; public static final String COMMAND_FORMAT = "event /from /to "; + private final String input; + private final TaskList taskList; + /** * Constructor for the EventCommand class. Returns a command object to add an event to the TaskList object upon * execution. diff --git a/src/main/java/dude/commands/HelpCommand.java b/src/main/java/dude/commands/HelpCommand.java index 404fed4a12..5b4861f927 100644 --- a/src/main/java/dude/commands/HelpCommand.java +++ b/src/main/java/dude/commands/HelpCommand.java @@ -107,9 +107,10 @@ private String generateCommandHelpMessage() { return "bye: Exits the program." + "\n\tFormat: bye" + "\n\tExample: bye"; + default: + return "I'm sorry, I don't know what that command is. Please type 'help' to see the " + + "list of commands I support."; } - - return "I'm sorry, I don't know what that command is. Please type 'help' to see the list of commands I support."; } @Override diff --git a/src/main/java/dude/exceptions/InvalidDescriptionException.java b/src/main/java/dude/exceptions/InvalidDescriptionException.java index 5dbab919c2..aa26f5d9b7 100644 --- a/src/main/java/dude/exceptions/InvalidDescriptionException.java +++ b/src/main/java/dude/exceptions/InvalidDescriptionException.java @@ -1,7 +1,8 @@ package dude.exceptions; /** - * The InvalidDescriptionException class represents an exception that is thrown when the description for a task is invalid. + * The InvalidDescriptionException class represents an exception that is thrown when the description for + * a task is invalid. */ public class InvalidDescriptionException extends DudeException { diff --git a/src/main/java/dude/exceptions/InvalidFormatException.java b/src/main/java/dude/exceptions/InvalidFormatException.java index 136711944a..6f35a75e38 100644 --- a/src/main/java/dude/exceptions/InvalidFormatException.java +++ b/src/main/java/dude/exceptions/InvalidFormatException.java @@ -21,7 +21,8 @@ public InvalidFormatException(String message) { * @param format The format that should be used. */ public InvalidFormatException(String command, String format) { - super("Invalid format for " + command + " command. \nPlease use this format: " + format + ",\n or type help for more information."); + super("Invalid format for " + command + " command. \nPlease use this format: " + format + + ",\n or type help for more information."); } /** @@ -32,9 +33,9 @@ public InvalidFormatException(String command, String format) { * @param note The note to be added to the exception message. */ public InvalidFormatException(String command, String format, String note) { - super("Invalid format for " + command + " command. " + - "\nPlease use this format: " + format + "," + - "\n or type help for more information." + super("Invalid format for " + command + " command. " + + "\nPlease use this format: " + format + "," + + "\n or type help for more information." + "\nNote: " + note); } -} \ No newline at end of file +} diff --git a/src/main/java/dude/tasks/Deadline.java b/src/main/java/dude/tasks/Deadline.java index e05dbef3f4..1e46c68133 100644 --- a/src/main/java/dude/tasks/Deadline.java +++ b/src/main/java/dude/tasks/Deadline.java @@ -29,7 +29,7 @@ public Deadline(String description, LocalDateTime by) { /** * Static method to create a Deadline object from parsing a string. - * Expects a string in the format "deadline /by ". + * Expects a string in the format "deadline *description* /by *deadline_date*". * * @param s The string to be parsed into a Deadline object. * @return The Deadline object created from the string. From b2b86be7cdcfc1af44f757ca1faa902aec9b0f44 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 27 Feb 2024 00:25:13 +0800 Subject: [PATCH 096/153] Updated to coding Standards --- src/main/java/dude/commands/ListCommand.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/dude/commands/ListCommand.java b/src/main/java/dude/commands/ListCommand.java index 1245b776cc..7c0adc63c8 100644 --- a/src/main/java/dude/commands/ListCommand.java +++ b/src/main/java/dude/commands/ListCommand.java @@ -11,7 +11,8 @@ public class ListCommand extends Command { private final TaskList tasklist; /** - * Constructor for the ListCommand class. Returns a command object to list all the tasks in the given TaskList object upon + * Constructor for the ListCommand class. Returns a command object to list all the tasks in the given + * TaskList object upon * execution. * * @param tasklist The TaskList object to be listed. From 2552cc13bb7c663bdae8e05e2e9d49ffc8d523bf Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 27 Feb 2024 00:26:28 +0800 Subject: [PATCH 097/153] Changed array indenting for HelpCommand --- src/main/java/dude/commands/HelpCommand.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/dude/commands/HelpCommand.java b/src/main/java/dude/commands/HelpCommand.java index 5b4861f927..804c54c560 100644 --- a/src/main/java/dude/commands/HelpCommand.java +++ b/src/main/java/dude/commands/HelpCommand.java @@ -10,15 +10,15 @@ public class HelpCommand extends Command { private static final String COMMAND_FORMAT = "help "; private final String[] supportedCommands = new String[]{ - "list: Lists all the tasks in the task list.", - "todo: Adds a todo task to the task list.", + "bye: Exits the program.", "deadline: Adds a deadline task to the task list.", + "delete: Deletes a task from the task list.", "event: Adds an event task to the task list.", + "help: Provides help on the commands I support.", + "list: Lists all the tasks in the task list.", "mark: Marks a task as done.", - "unmark: Marks a task as undone.", - "delete: Deletes a task from the task list.", - "bye: Exits the program.", - "help: Provides help on the commands I support." + "todo: Adds a todo task to the task list.", + "unmark: Marks a task as undone." }; private final String input; From fd7330c05a1dcd59e01c85d76172ffa5edfd945a Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 27 Feb 2024 00:27:33 +0800 Subject: [PATCH 098/153] Changed array indenting for HelpCommand --- src/main/java/dude/commands/HelpCommand.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/dude/commands/HelpCommand.java b/src/main/java/dude/commands/HelpCommand.java index 804c54c560..0523475d2f 100644 --- a/src/main/java/dude/commands/HelpCommand.java +++ b/src/main/java/dude/commands/HelpCommand.java @@ -10,14 +10,10 @@ public class HelpCommand extends Command { private static final String COMMAND_FORMAT = "help "; private final String[] supportedCommands = new String[]{ - "bye: Exits the program.", - "deadline: Adds a deadline task to the task list.", - "delete: Deletes a task from the task list.", - "event: Adds an event task to the task list.", - "help: Provides help on the commands I support.", - "list: Lists all the tasks in the task list.", - "mark: Marks a task as done.", - "todo: Adds a todo task to the task list.", + "bye: Exits the program.", "deadline: Adds a deadline task to the task list.", + "delete: Deletes a task from the task list.", "event: Adds an event task to the task list.", + "help: Provides help on the commands I support.", "list: Lists all the tasks in the task list.", + "mark: Marks a task as done.", "todo: Adds a todo task to the task list.", "unmark: Marks a task as undone." }; From 70c00dd6faa0f31c256eba0f09dee18d93b9782e Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 27 Feb 2024 00:28:39 +0800 Subject: [PATCH 099/153] changed indent for Help copmmand --- src/main/java/dude/commands/HelpCommand.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/dude/commands/HelpCommand.java b/src/main/java/dude/commands/HelpCommand.java index 0523475d2f..dfa881822a 100644 --- a/src/main/java/dude/commands/HelpCommand.java +++ b/src/main/java/dude/commands/HelpCommand.java @@ -10,11 +10,11 @@ public class HelpCommand extends Command { private static final String COMMAND_FORMAT = "help "; private final String[] supportedCommands = new String[]{ - "bye: Exits the program.", "deadline: Adds a deadline task to the task list.", - "delete: Deletes a task from the task list.", "event: Adds an event task to the task list.", - "help: Provides help on the commands I support.", "list: Lists all the tasks in the task list.", - "mark: Marks a task as done.", "todo: Adds a todo task to the task list.", - "unmark: Marks a task as undone." + "bye: Exits the program.", "deadline: Adds a deadline task to the task list.", + "delete: Deletes a task from the task list.", "event: Adds an event task to the task list.", + "help: Provides help on the commands I support.", "list: Lists all the tasks in the task list.", + "mark: Marks a task as done.", "todo: Adds a todo task to the task list.", + "unmark: Marks a task as undone." }; private final String input; From 893948cf492d05866c0c8cdfde010e21611b86ea Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 27 Feb 2024 00:31:11 +0800 Subject: [PATCH 100/153] Added Javadoc to utils class --- src/main/java/dude/commands/UnmarkCommand.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/dude/commands/UnmarkCommand.java b/src/main/java/dude/commands/UnmarkCommand.java index 57082945fb..51253274e3 100644 --- a/src/main/java/dude/commands/UnmarkCommand.java +++ b/src/main/java/dude/commands/UnmarkCommand.java @@ -15,8 +15,8 @@ public class UnmarkCommand extends Command { private final TaskList taskList; /** - * Constructor for the UnmarkCommand class. Returns a command object to mark a task as not done in the task list upon - * execution. + * Constructor for the UnmarkCommand class. Returns a command object to mark a task as not done in the task + * list upon execution. * * @param input The input string that resulted in the creation of this command. * @param tasklist The TaskList object in which the task is to be marked as not done. From e80de01344c7b9cbfb2fdef25a3d769ea3beabe3 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 27 Feb 2024 00:31:30 +0800 Subject: [PATCH 101/153] Added Javadoc to utils class --- src/main/java/dude/utils/utils.java | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/main/java/dude/utils/utils.java b/src/main/java/dude/utils/utils.java index 5a1cfc44df..f77e1a38e2 100644 --- a/src/main/java/dude/utils/utils.java +++ b/src/main/java/dude/utils/utils.java @@ -1,9 +1,19 @@ package dude.utils; +/** + * The utils class contains utility methods that are used throughout the application. + */ public class utils { // From chat GPT https://chat.openai.com/share/1848f5d2-1197-418e-86a9-bccdf69fc790 + + /** + * Discards the first word from the input string. + * + * @param input The input string. + * @return The input string with the first word discarded. + */ public static String discardFirstWord(String input) { // Split the string by whitespace String[] words = input.split(" ", 2); @@ -17,6 +27,13 @@ public static String discardFirstWord(String input) { } } + /** + * Counts the occurrences of a target string in an array of strings. + * + * @param array The array of strings. + * @param target The target string. + * @return The number of occurrences of the target string in the array. + */ public static int countOccurrences(String[] array, String target) { int count = 0; for (String str : array) { @@ -27,6 +44,13 @@ public static int countOccurrences(String[] array, String target) { return count; } + /** + * Finds the index of the first occurrence of a target string in an array of strings. + * + * @param array The array of strings. + * @param target The target string. + * @return The index of the first occurrence of the target string in the array. + */ public static int findIndex(String[] array, String target) { for (int i = 0; i < array.length; i++) { if (array[i].equals(target)) { From 191dc8d181c018011c09d7c4124e9ac460851915 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 27 Feb 2024 00:32:04 +0800 Subject: [PATCH 102/153] Renamed utils class to Utils --- src/main/java/dude/tasks/Deadline.java | 8 ++++---- src/main/java/dude/tasks/Event.java | 12 ++++++------ src/main/java/dude/tasks/Todo.java | 4 ++-- src/main/java/dude/utils/{utils.java => Utils.java} | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) rename src/main/java/dude/utils/{utils.java => Utils.java} (98%) diff --git a/src/main/java/dude/tasks/Deadline.java b/src/main/java/dude/tasks/Deadline.java index 1e46c68133..d7fd61be79 100644 --- a/src/main/java/dude/tasks/Deadline.java +++ b/src/main/java/dude/tasks/Deadline.java @@ -6,7 +6,7 @@ import dude.exceptions.InvalidArgumentException; import dude.exceptions.InvalidDescriptionException; import dude.exceptions.InvalidFormatException; -import dude.utils.utils; +import dude.utils.Utils; /** @@ -42,11 +42,11 @@ public static Deadline from(String s) throws InvalidFormatException, //Expects a string in the format "deadline /by " //get rid of the command - String rest = utils.discardFirstWord(s.trim()).trim(); + String rest = Utils.discardFirstWord(s.trim()).trim(); String[] arr = rest.split(" "); - int byOccurences = utils.countOccurrences(arr, "/by"); + int byOccurences = Utils.countOccurrences(arr, "/by"); if (byOccurences == 0 || byOccurences > 1) { throw new InvalidFormatException("deadline", "format: deadline /by . " @@ -54,7 +54,7 @@ public static Deadline from(String s) throws InvalidFormatException, } //they will not be -1 as I have already checked for their occurences - int byIndex = utils.findIndex(arr, "/by"); + int byIndex = Utils.findIndex(arr, "/by"); //description is from 0 to byIndex String description = ""; diff --git a/src/main/java/dude/tasks/Event.java b/src/main/java/dude/tasks/Event.java index 7ce41d0cd3..4b60d55242 100644 --- a/src/main/java/dude/tasks/Event.java +++ b/src/main/java/dude/tasks/Event.java @@ -7,7 +7,7 @@ import dude.exceptions.InvalidArgumentException; import dude.exceptions.InvalidDescriptionException; import dude.exceptions.InvalidFormatException; -import dude.utils.utils; +import dude.utils.Utils; /** @@ -44,17 +44,17 @@ public Event(String description, LocalDateTime fromTime, LocalDateTime toTime) { public static Event from(String input) throws InvalidArgumentException, InvalidFormatException, InvalidDescriptionException { - String rest = utils.discardFirstWord(input.trim()).trim(); + String rest = Utils.discardFirstWord(input.trim()).trim(); String[] arr = rest.split(" "); - int fromOccurences = utils.countOccurrences(arr, "/from"); + int fromOccurences = Utils.countOccurrences(arr, "/from"); if (fromOccurences == 0 || fromOccurences > 1) { throw new InvalidFormatException("Invalid format. Follow this format :" + EventCommand.COMMAND_FORMAT + ". Provide one and only one '/from'."); } - int toOccurrences = utils.countOccurrences(arr, "/to"); + int toOccurrences = Utils.countOccurrences(arr, "/to"); if (toOccurrences == 0 || toOccurrences > 1) { throw new InvalidFormatException("Invalid format. Follow this format: " + EventCommand.COMMAND_FORMAT @@ -62,8 +62,8 @@ public static Event from(String input) throws InvalidArgumentException, } //they will not be -1 as I have already checked for their occurences - int fromIndex = utils.findIndex(arr, "/from"); - int toIndex = utils.findIndex(arr, "/to"); + int fromIndex = Utils.findIndex(arr, "/from"); + int toIndex = Utils.findIndex(arr, "/to"); if (fromIndex > toIndex) { throw new InvalidFormatException("The 'from time' of an event cannot be after the 'to time'."); diff --git a/src/main/java/dude/tasks/Todo.java b/src/main/java/dude/tasks/Todo.java index 9a39831573..95bf026603 100644 --- a/src/main/java/dude/tasks/Todo.java +++ b/src/main/java/dude/tasks/Todo.java @@ -1,7 +1,7 @@ package dude.tasks; import dude.exceptions.InvalidDescriptionException; -import dude.utils.utils; +import dude.utils.Utils; /** * The Todo class represents a task with a description. @@ -28,7 +28,7 @@ public Todo(String description) { public static Todo from(String s) throws InvalidDescriptionException { //get rid of the command - String description = utils.discardFirstWord(s.trim()).trim(); + String description = Utils.discardFirstWord(s.trim()).trim(); if (!description.isEmpty()) { return new Todo(description); diff --git a/src/main/java/dude/utils/utils.java b/src/main/java/dude/utils/Utils.java similarity index 98% rename from src/main/java/dude/utils/utils.java rename to src/main/java/dude/utils/Utils.java index f77e1a38e2..a45d297260 100644 --- a/src/main/java/dude/utils/utils.java +++ b/src/main/java/dude/utils/Utils.java @@ -3,7 +3,7 @@ /** * The utils class contains utility methods that are used throughout the application. */ -public class utils { +public class Utils { // From chat GPT https://chat.openai.com/share/1848f5d2-1197-418e-86a9-bccdf69fc790 From 3f506a4d962f3b8e48fc3829e4f6e90201d09edd Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 27 Feb 2024 00:33:55 +0800 Subject: [PATCH 103/153] Updated TaskListFullException to coding standards --- src/main/java/dude/exceptions/TaskListFullException.java | 2 +- src/main/java/dude/utils/Storage.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/dude/exceptions/TaskListFullException.java b/src/main/java/dude/exceptions/TaskListFullException.java index b2b1426a04..c30f7e8cc1 100644 --- a/src/main/java/dude/exceptions/TaskListFullException.java +++ b/src/main/java/dude/exceptions/TaskListFullException.java @@ -13,4 +13,4 @@ public class TaskListFullException extends DudeException { public TaskListFullException(String message) { super(message); } -} \ No newline at end of file +} diff --git a/src/main/java/dude/utils/Storage.java b/src/main/java/dude/utils/Storage.java index 1ec0c6017e..6cee24c723 100644 --- a/src/main/java/dude/utils/Storage.java +++ b/src/main/java/dude/utils/Storage.java @@ -91,7 +91,9 @@ public void saveTasks(TaskList taskList) throws IOException, SecurityException { * Loads the task list from the storage file. Returns empty task list if no task data is found. * * @return TaskList - * @throws IOException, ClassNotFoundException, SecurityException + * @throws IOException If an I/O error occurs. + * @throws ClassNotFoundException If the class of the object to be loaded was not found. + * @throws SecurityException If a security manager exists and its checkRead method denies read access to the file. */ public TaskList loadTasks() throws IOException, ClassNotFoundException, SecurityException { createStorageIfNotExists(); From 22c928271a55f482b094079edf4ae1181fceed00 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 27 Feb 2024 00:35:06 +0800 Subject: [PATCH 104/153] Updated MarkCommand to coding standards --- src/main/java/dude/commands/MarkCommand.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/dude/commands/MarkCommand.java b/src/main/java/dude/commands/MarkCommand.java index 2b2ced532e..4c39c9fda3 100644 --- a/src/main/java/dude/commands/MarkCommand.java +++ b/src/main/java/dude/commands/MarkCommand.java @@ -15,8 +15,8 @@ public class MarkCommand extends Command { private final TaskList taskList; /** - * Constructor for the MarkCommand class. Returns a command object to mark a task as done in the TaskList object upon - * execution. + * Constructor for the MarkCommand class. Returns a command object to mark a task as done in the TaskList + * object upon execution. * * @param input The input string that resulted in the creation of this command. * @param tasklist The TaskList object in which the task is to be marked as done. @@ -43,16 +43,12 @@ public String execute() throws DudeException { } int id = Integer.parseInt(this.input.split(" ")[1]); - - //re-thow exception if task does not exist try { Task task = this.taskList.getTask(id); this.taskList.mark_as_done(id); - String msg = "Nice! I've marked this task as done:\n" + return "Nice! I've marked this task as done:\n" + "\t " + id + ". " + task.toString(); - - return msg; } catch (DudeException e) { throw new DudeException(e.getMessage()); } From 935a8327b6174ebb0c5a1b64f0ef4939399b6966 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Tue, 27 Feb 2024 00:37:50 +0800 Subject: [PATCH 105/153] Code quality updates from intelliJ suggestions --- src/main/java/dude/commands/UnmarkCommand.java | 4 +--- src/main/java/dude/utils/Storage.java | 6 +++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/dude/commands/UnmarkCommand.java b/src/main/java/dude/commands/UnmarkCommand.java index 51253274e3..c92e8e16fb 100644 --- a/src/main/java/dude/commands/UnmarkCommand.java +++ b/src/main/java/dude/commands/UnmarkCommand.java @@ -49,10 +49,8 @@ public String execute() throws DudeException { Task task = taskList.getTask(id); this.taskList.mark_as_undone(id); - String msg = "Nice! I've unmarked this task as done:\n" + return "Nice! I've unmarked this task as done:\n" + "\t " + id + ". " + task.toString(); - - return msg; } catch (DudeException e) { throw new DudeException(e.getMessage()); } diff --git a/src/main/java/dude/utils/Storage.java b/src/main/java/dude/utils/Storage.java index 6cee24c723..d5bb065947 100644 --- a/src/main/java/dude/utils/Storage.java +++ b/src/main/java/dude/utils/Storage.java @@ -41,7 +41,7 @@ private void createStorageIfNotExists() throws IOException, SecurityException { //create the directory if it does not exist if (!path.exists()) { - boolean created = path.mkdirs(); + path.mkdirs(); } File file = new File(this.filepath + this.filename); @@ -64,7 +64,7 @@ public void deleteStorage() throws SecurityException { boolean fileExists = file.exists(); if (fileExists) { - boolean deleted = file.delete(); + file.delete(); } } @@ -98,7 +98,7 @@ public void saveTasks(TaskList taskList) throws IOException, SecurityException { public TaskList loadTasks() throws IOException, ClassNotFoundException, SecurityException { createStorageIfNotExists(); - ArrayList list = new ArrayList<>(); + ArrayList list; try { FileInputStream fis = new FileInputStream(this.filepath + this.filename); ObjectInputStream ois = new ObjectInputStream(fis); From 7184d0ab7d23ebdb48f4a68a55a447a9deaa5dab Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Wed, 28 Feb 2024 00:07:55 +0800 Subject: [PATCH 106/153] Minor style change --- src/main/java/dude/tasks/Event.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/dude/tasks/Event.java b/src/main/java/dude/tasks/Event.java index 4b60d55242..5462eee6ae 100644 --- a/src/main/java/dude/tasks/Event.java +++ b/src/main/java/dude/tasks/Event.java @@ -47,15 +47,13 @@ public static Event from(String input) throws InvalidArgumentException, String rest = Utils.discardFirstWord(input.trim()).trim(); String[] arr = rest.split(" "); - int fromOccurences = Utils.countOccurrences(arr, "/from"); - - if (fromOccurences == 0 || fromOccurences > 1) { + int fromOccurrences = Utils.countOccurrences(arr, "/from"); + if (fromOccurrences == 0 || fromOccurrences > 1) { throw new InvalidFormatException("Invalid format. Follow this format :" + EventCommand.COMMAND_FORMAT + ". Provide one and only one '/from'."); } int toOccurrences = Utils.countOccurrences(arr, "/to"); - if (toOccurrences == 0 || toOccurrences > 1) { throw new InvalidFormatException("Invalid format. Follow this format: " + EventCommand.COMMAND_FORMAT + ". Provide one and only one '/to'."); From cf3aa559d1f827e1e28c4d06ef9c75ce57927ff0 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Thu, 29 Feb 2024 18:30:21 +0800 Subject: [PATCH 107/153] Fixed some Checkstyle errors --- src/main/java/dude/commands/FindCommand.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/dude/commands/FindCommand.java b/src/main/java/dude/commands/FindCommand.java index 2dd2fbd501..688448f0b6 100644 --- a/src/main/java/dude/commands/FindCommand.java +++ b/src/main/java/dude/commands/FindCommand.java @@ -1,13 +1,12 @@ package dude.commands; +import java.util.ArrayList; import dude.exceptions.InvalidFormatException; import dude.tasks.Task; import dude.tasks.TaskList; import dude.utils.Utils; -import java.util.ArrayList; - /** * The FindCommand class represents a command to find tasks in the TaskList object. */ From ec3137ff88df2e107c5387afb204ae332cc81068 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Thu, 29 Feb 2024 23:50:17 +0800 Subject: [PATCH 108/153] Implemented sending message to UI --- build.gradle | 17 ++++++ src/main/java/dude/Dude.java | 97 +++++++++++++++++++++++++++++++- src/main/java/dude/Launcher.java | 10 ++++ 3 files changed, 121 insertions(+), 3 deletions(-) create mode 100644 src/main/java/dude/Launcher.java diff --git a/build.gradle b/build.gradle index 9316b94279..fbdd30592c 100644 --- a/build.gradle +++ b/build.gradle @@ -12,8 +12,25 @@ 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 { useJUnitPlatform() diff --git a/src/main/java/dude/Dude.java b/src/main/java/dude/Dude.java index 6dcb7d1777..29b8b7103c 100644 --- a/src/main/java/dude/Dude.java +++ b/src/main/java/dude/Dude.java @@ -3,6 +3,8 @@ import java.util.NoSuchElementException; import java.util.Scanner; +import javafx.application.Application; + import dude.commands.Command; import dude.commands.CommandTypes; import dude.commands.Parser; @@ -11,6 +13,16 @@ import dude.utils.Storage; import dude.utils.Ui; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.TextField; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.Region; +import javafx.scene.layout.VBox; +import javafx.stage.Stage; + /** * The main class of the Duke application. @@ -20,7 +32,7 @@ * The main loop of the application is responsible for reading user input, * parsing it into a command, executing the command and saving the task list to disk. **/ -public class Dude { +public class Dude extends Application { private final TaskList taskList; private final Storage storage; private final Ui ui; @@ -104,7 +116,86 @@ private void saveToDisk() { } } - public static void main(String[] args) { - new Dude("data/tasklist.ser").run(); + public Dude() { + this("data/tasks.txt"); + } + + @Override + public void start(Stage stage) { + + + Label label = new Label("Hello Boii"); + + ScrollPane scrollPane = new ScrollPane(); + VBox container = new VBox(); + + scrollPane.setContent(container); + + Button sendButton = new Button("Send"); + TextField textField = new TextField(); + + AnchorPane mainLayout = new AnchorPane(); + mainLayout.getChildren().addAll(label, scrollPane, textField, sendButton); + + + Scene scene = new Scene(mainLayout); + + stage.setTitle("Duke"); + stage.setResizable(false); + stage.setMinHeight(600.0); + stage.setMinWidth(440); + + scrollPane.setPrefSize(420, 535); + scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); + scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.ALWAYS); + + scrollPane.setVvalue(1.0); + scrollPane.setFitToWidth(true); + + textField.setPrefWidth(300); + sendButton.setPrefWidth(100); + + AnchorPane.setTopAnchor(scrollPane, 1.0); + AnchorPane.setLeftAnchor(scrollPane, 1.0); + + AnchorPane.setBottomAnchor(sendButton, 10.0); + AnchorPane.setRightAnchor(sendButton, 5.0); + + AnchorPane.setBottomAnchor(textField, 10.0); + AnchorPane.setLeftAnchor(textField, 5.0); + + container.setPrefHeight(Region.USE_COMPUTED_SIZE); + + sendButton.setOnMouseClicked(e -> { + String input = textField.getText(); + container.getChildren().add(getUserMessageView(input)); + textField.clear(); + }); + + textField.setOnAction(e -> { + String input = textField.getText(); + container.getChildren().add(getUserMessageView(input)); + textField.clear(); + }); + + mainLayout.setPrefSize(420, 600.0); + mainLayout.heightProperty().addListener((observable) -> { + scrollPane.setVvalue(1.0); + System.out.println("Height: " + mainLayout.getHeight()); + }); + + stage.setScene(scene); // Setting the stage to show our screen + stage.show(); // Render the stage. + } + + + private static Label getUserMessageView(String message) { + System.out.println("User: " + message); + Label label = new Label(message); + label.setWrapText(true); + label.setMinHeight(Region.USE_PREF_SIZE); + label.setPrefWidth(Region.USE_COMPUTED_SIZE); + label.getStyleClass().add("dialog-label"); + return label; } } diff --git a/src/main/java/dude/Launcher.java b/src/main/java/dude/Launcher.java new file mode 100644 index 0000000000..3092610a7b --- /dev/null +++ b/src/main/java/dude/Launcher.java @@ -0,0 +1,10 @@ +package dude; + +import javafx.application.Application; + +public class Launcher { + + public static void main(String[] args) { + Application.launch(Dude.class, args); + } +} From 933e721c1961f6f4216f35e0783e12ad86d02d05 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 16:48:51 +0800 Subject: [PATCH 109/153] Implemented exchange of dialog --- src/main/java/dude/DialogBox.java | 63 +++++++++++++++++++++++++ src/main/java/dude/Dude.java | 4 +- src/main/java/dude/Launcher.java | 2 +- src/main/java/dude/Main.java | 29 ++++++++++++ src/main/java/dude/MainView.java | 51 ++++++++++++++++++++ src/main/resources/images/user.jpg | Bin 0 -> 6686 bytes src/main/resources/view/DialogBox.fxml | 17 +++++++ src/main/resources/view/MainView.fxml | 34 +++++++++++++ 8 files changed, 197 insertions(+), 3 deletions(-) create mode 100644 src/main/java/dude/DialogBox.java create mode 100644 src/main/java/dude/Main.java create mode 100644 src/main/java/dude/MainView.java create mode 100644 src/main/resources/images/user.jpg create mode 100644 src/main/resources/view/DialogBox.fxml create mode 100644 src/main/resources/view/MainView.fxml diff --git a/src/main/java/dude/DialogBox.java b/src/main/java/dude/DialogBox.java new file mode 100644 index 0000000000..c120231ffd --- /dev/null +++ b/src/main/java/dude/DialogBox.java @@ -0,0 +1,63 @@ +package dude; + +import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import javafx.fxml.FXML; + +import java.io.IOException; +import java.util.Collections; + +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; + +import javafx.fxml.FXMLLoader; +import javafx.geometry.Pos; +import javafx.scene.Node; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; + +/** + * An example of a custom control using FXML. + * This control represents a dialog box consisting of an ImageView to represent the speaker's face and a label + * containing text from the speaker. + */ +public class DialogBox extends HBox { + @FXML + private Label dialog; + @FXML + private ImageView displayPicture; + + private DialogBox(String text, Image img) { + try { + FXMLLoader fxmlLoader = new FXMLLoader(MainView.class.getResource("/view/DialogBox.fxml")); + fxmlLoader.setController(this); + fxmlLoader.setRoot(this); + fxmlLoader.load(); + } catch (IOException e) { + e.printStackTrace(); + } + + dialog.setText(text); + displayPicture.setImage(img); + } + + /** + * Flips the dialog box such that the ImageView is on the left and text on the right. + */ + private void flip() { + ObservableList tmp = FXCollections.observableArrayList(this.getChildren()); + Collections.reverse(tmp); + getChildren().setAll(tmp); + setAlignment(Pos.TOP_LEFT); + } + + public static DialogBox getUserDialog(String text, Image img) { + return new DialogBox(text, img); + } + + public static DialogBox getDukeDialog(String text, Image img) { + var db = new DialogBox(text, img); + db.flip(); + return db; + } +} diff --git a/src/main/java/dude/Dude.java b/src/main/java/dude/Dude.java index 29b8b7103c..ad4378b567 100644 --- a/src/main/java/dude/Dude.java +++ b/src/main/java/dude/Dude.java @@ -179,9 +179,9 @@ public void start(Stage stage) { }); mainLayout.setPrefSize(420, 600.0); - mainLayout.heightProperty().addListener((observable) -> { + + container.heightProperty().addListener((observable) -> { scrollPane.setVvalue(1.0); - System.out.println("Height: " + mainLayout.getHeight()); }); stage.setScene(scene); // Setting the stage to show our screen diff --git a/src/main/java/dude/Launcher.java b/src/main/java/dude/Launcher.java index 3092610a7b..97dd1dafc9 100644 --- a/src/main/java/dude/Launcher.java +++ b/src/main/java/dude/Launcher.java @@ -5,6 +5,6 @@ public class Launcher { public static void main(String[] args) { - Application.launch(Dude.class, args); + Application.launch(Main.class, args); } } diff --git a/src/main/java/dude/Main.java b/src/main/java/dude/Main.java new file mode 100644 index 0000000000..2c960d5e5d --- /dev/null +++ b/src/main/java/dude/Main.java @@ -0,0 +1,29 @@ +package dude; + +import javafx.application.Application; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.scene.layout.AnchorPane; +import javafx.stage.Stage; + +import java.io.IOException; + +public class Main extends Application { + + @Override + public void start(Stage stage) { + stage.setTitle("Dude"); + + FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("/view/MainView.fxml")); + AnchorPane anchorPane = null; + try { + anchorPane = fxmlLoader.load(); + } catch (IOException e) { + throw new RuntimeException(e); + } + + Scene scene = new Scene(anchorPane); + stage.setScene(scene); + stage.show(); + } +} diff --git a/src/main/java/dude/MainView.java b/src/main/java/dude/MainView.java new file mode 100644 index 0000000000..45ce1f9bf6 --- /dev/null +++ b/src/main/java/dude/MainView.java @@ -0,0 +1,51 @@ +package dude; + +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.TextField; +import javafx.scene.image.Image; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.VBox; + +/** + * Controller for MainView. Provides the layout for the other controls. + */ +public class MainView extends AnchorPane { + @FXML + private ScrollPane scrollPane; + + @FXML + private Button sendButton; + + @FXML + private TextField userInputField; + + @FXML + private VBox dialogContainer; + + private Image userImage = new Image(this.getClass().getResourceAsStream("/images/user.jpg")); + + @FXML + public void initialize() { + System.out.println("Initializing MainView"); + + } + + + @FXML + public void handleUserInput() { + String input = userInputField.getText(); + String response = "Duke heard: " + input; + + System.out.println("User input: " + input); + userInputField.clear(); + + dialogContainer.getChildren().addAll( + DialogBox.getUserDialog(input, userImage), + DialogBox.getDukeDialog(response, userImage) + ); + + } + +} diff --git a/src/main/resources/images/user.jpg b/src/main/resources/images/user.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3993a1f4f80d6c20f75a4ff0e5962494cee9be9d GIT binary patch literal 6686 zcmeHLc~p~Uvrk09T7^agl(hv#1<}TkfIz_e739_u@?jDp``1K4f)Lqdr<<&S@*$G2 zgbFo40--Ds5%=brn=os*MiCeM?Z-^{%4J2UT2 z$4)okE5Lp!sol?hsr?7`?>``YNJd&hM?N`p@Q~b*&pwkoA}0%yKYk2!ROzU!oPw%? z(uor)Dk`5HQ`1mW);O-LqP(jFxc|Tb=>yV-Wn>O3gXBQU|6|&D3IH7h_5(|#fSQ1P zAfOZoxKjsE1pop2q<}ym;63e=kvbp^+<#EA`}Jo)08nZl;FC`d?3a<2**yZ>C-DL# zee~ED;Qz4s)>~flBKo_e`w#hlyXI5;OhF6xPnnaDuf8vtJEf1p`#y)l%q?#CWlK~k zNo@SlibT~upw#XL=r0>U5O}8xa9BzL4I~8um;tt4zDM_Om{V$ieV_lEGke?nF8}Wx zy>EkYCP9%u?$Zpv`h=sCc)W8gnHhYRGPmEHCiGU}DVPVgo{8K;_I~{-OSj?b z0t4u$y-3oy1IvXJ+767UtylT$=Q08 zLR8Nm&vqj@uA)?DJRnia`IKD5Gv@5grr6b_&El%ff!gUY40;xdF&3bk7fc~-y7GlH zmWTZdNULnvy!%wK>)Ewtv7qm5X-Pz{uXtwrTx^YA-?8IbJ*{y;yNPRgbjy4F@!d_`w&KUJ{)c8!8m?Q%dJ;2;3+_(?j%S!v%7gOy z9oTCALsm51H->P3r%a7hZF_GKJ>zOI@lK+PYg<$ww!yI=26EjUj zvwOihn;XgGeE$j{>3yVknf;ObFYm6u6L8ABsm`2uQBG6a?G|a|)!Yw1EibM!>fcmQ zP9*W1Iu{B%sV#$y%50+z4Y@;xSSW&LW?9JsR~v|LQK?;LsLfr~NnJyln&fC2EP6Z| z9mD$Pl89}&vkK;mR!GOQ_hx^nI$8O!M~tm#FPog~t@Lhz zjfM*}3j9}T^;b*H^_RyBAMudQb;%AO>LOn>Wn3F~@`OAFeZ;pB42WAj}`f*VZ& z2*w}bFZsq`jCm+H1U{JrtBRHoDck6a@w1=*!H(Vz!&BZ5JS0Jm2LZ zPVi7yi7PDS+)Rahp*YU0q=eo(o#t9VpoQsrw<1Y!r`}JBuW|a1{_;W9NBGt2h{i-v z9~`MHdwde|U3NP`;OMYcI(&va5gX9UUh$2HRz)6!61(jm^~7oiL2HC~?wtAJ4j?vY zOGx^b|JvwMw98LFE}-@Cx#vA)6P)q9RNL>@cBm} zm1vjCkuoZTm?^;$GD3gf z>Puak^KRZ2JqCXI{%;@U)prxN19(*)v7s1o$yNlpr|-QAO$RUQuv|D5>kMeKW+XK7 z{XgF^QbpT|HN8uwEnj$Siig#57eg$!b$z!<8lw+vn=3DW_S@d^j~tb$FT^)H$K_v- z?xoK&23PBd8ir^;!3&yBLJX%STDIAfadq8$MnLS8=ZQOQpg$fs zxu^5@^}2~v@$jO@3eBv%kwHA<9vcA{Ok*tcc_==psxVVV_KrTnOgXQMbGshHoyUwJ zN7Fhw04b4sYEA+)_gDbn&_>jC)30n8ObGlC(4X3fZPVG*b> zi>yAo1U8*KmfNkuWfwot85p+0fWUl{xushlRK4TEx?nQX2nV^N_$Ib*NOjx97-K{w z#8!y$rc=gy9RmT2o!QOSj{;!neeB{IVax)3xtYIxBH$n+^6-0IAD5|RZFe$xlspy{ zscWiuYX?xm`kKizakOHmKX^P&D`HvJP>plhIS#>3Qa$WiX9oJHCk0~;?DA!Qu7%65 zD^~RQ_>c~YlD9ZdjGYqHvynHpj0QuLbk5;{1%E`ZaYg!o5M}g2-2nPZ;Q3>8adgePe*KL6q$9}N5qi2fh|q_PH(G7-1!;^U2Q&`pYc*f&iBZqk0o0KtdXUT zy<}hLV5Q(HPuS+w;A*Z48v|o@08UIZbpL5MR{tBmT4yP0tYK1F=Iq9Aa# zeY`u{fF9BA@u<~MEy{eh=CY5Odrsy*!<> z(;w3(vN<@qTc-(6)@|QneBmgML58+C!^4S^rYPhw@#!6kDxfhp=y^+Vuu=9Br?BOT z!9C8b6sywdxSw-Ex7{)17+Cj9uTlksqiWl&#j=8$n;^6MRk=TO)uYPXFHyT4^t?Gu zwu-B#n386wd$L@u+>38H*@2goD|Wd~W8I5{3L2r(>`e4p<$M~RQrCYz9q-;$nUsmW z(elq6A<~TZ8i&L8+l#MDZXVATEBlw|jV{_7T*!f!FH;Gk){X7ldIG42w-ZG^YVQl1HPI;0U9#j)z+?{o3y}J0w z3yC`O{1WY&dazqRg2Gw^#Nz;EAb?n94I`crdbn$SVm6a7y zzV%b3@7DXKRnJ={JFk)N*O@mh^sx8}ce&;prwg4*21lHqHL#LnT#{=DOsIn2YTa@j zSHJe0*Wi%ymdf?w!hsi8%qTvj{2Ix%$ij-`1!jzY{1o}SlZS&&DBhW$8NS&Q2h&5n zV6rC@+d{MoG|m^(yZC+^l)!9Vx=FXBBn~=KV?&L`IHyp;N}sLn)DqqFRHgvh!weUo zTJ`R+3!U11Ls{OiDTkO`^|vh#k&Z3%NSDg|LPv6(AF$xIUtyq`MdoirB0fAcgzC>; z4x`MHGDk_z3)FD#rPw8thEcJB&L}hDduGhsXvz&SPKQJ%4UmQPtzfXRm8WJk-|%Kq zZaoZYZR&N>*CJ##py%#Z-V8N-J2!-sj5kn^k2iknQtXoBB+r8jTZLzvY(;0@*N+bc z?(n6cfG@#}23{p1{a7#tNkp6bH!Xt+_77mmF}BwJz6cNxp}&sR*(l=@N7@QlBsX2h zhPY1OV-7hHS~$vrCszb7U56oVR;({=%ir+u#iZNV!m?_hnVX`_r52Zg@r31{72gFo z%<#mTk+ai@>joy7lR>$6d($RFv^>#IDGx=foaubA8M`stfSrh*MF+O7s!;rF?Y45vVsm+eH$`-xgHUV$v! z>9E{c4BS852^nQzeEQnUjQ9s;7r*{Xs@+L_$6H1|a&Mu33t08+m>@9Y$R*nw@AvSzH96Fe!JiB4csqknQJ5GgG+ zHQOY~dkMk%9i>m^y|UWem=RYR3d)Z!AyB97US(u7ke0iIoG=yivZV-4jQ>}XC1#J7 z28=?-t4Tg1aeTfLXEd#PE?PED?%p~R#!nuGNLr|LOU0VeTw;a+%5ZR*NG#{^%c3YbzG3C z`pt>SA#YFa*hRt3J1eF$^FNVDF&e>zGlGRKQ|s#&Ra~xkg*)duV)KTDjpXsTl%V1P zq3_yWf2Uj2}U}JHORo* z{>Wku>h7A-Z(_Y0ILCB@Y0Qi4ipi`tV|?MQaeHB5pxi4PkcVdP+rCoyaZI;HEgUs9 zX%U-J3XI)N$X?GoIz}PWGz}<{2deQ6?+jSGVXI!9pNjUkv~pNpY$-9e&Tzkr zC~7WGIffU2b35pv@qR&9IWx$KPIbM{|2!}4YTu*vMd8)$q;%p1S$rZAindyC%no+X zTH=|^{(Rus59#=8b*$7Vw7_+WsIu4!_iG77LdI=FmD(e4qll{5$4?vRnk$3wgVQqGhnYf^dQuWjYq`|$JG}km7fsMAY07Eh8MRQA&7Pie~SBm|MM@i|<^N5Bn z0c6>e3kA=N%~Nj2v*shq{($(uVU4K!2|cMs)kaGWcCV<=!ZCg&h`)V?RE1MpPmQ5d zVhaWOSgU%pKuy2Nw{D}YHz~ihz`bIvtPX{F*)SUcqsXb(g&0(sKKy{L4Rq`im$N_S9-tk2d@* z)-?Q7GhAa)G`5D3pY^}W{obxB&ZU0Hx=kF&E!uRB-vQ`bR=a63?*K`=)2^nrtEQ3L zL(HATi;$(MjknEn9ZRD>Vj5I{+xG#84rn z(a_ARr+En{WHzl5U*wKp8=y9?0V%unT3=QFrC3$H+T3qgSWYl87(zCt+@6m3Rb|8G z(NNu@AYhUEqXl^FRjlLSnRn&p&mcaQjpfF709v<6-zd7ZmRn5XpJ=;hrTl%UyI00p zY@$_9T8?|`SZdl8n3(xxV@Ju;zrB%kf(o;;GxJNYVCw~gHtJn;dU(Q3&VYYt_|dT) zfJ}0Z(8A0%<;|a7X?D=xZU-=eQJ>CP^l&)h8Y^mtTI(qY zu)38z1Ozf+di{ALHQp+JuGodoZ~iTQGwQ-y@e}o$hcA7$kh%k+btyp09;^EM-Y;Js z{{LgUvH8CjkbO!)(~g^vHB;tSsgpr2axVOPON + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/view/MainView.fxml b/src/main/resources/view/MainView.fxml new file mode 100644 index 0000000000..9dd0eac360 --- /dev/null +++ b/src/main/resources/view/MainView.fxml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + From 14703f12caae606e05838146716c977e073b261d Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 16:53:29 +0800 Subject: [PATCH 110/153] minor changes --- src/main/java/dude/MainView.java | 6 ++++-- src/main/resources/view/MainView.fxml | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/main/java/dude/MainView.java b/src/main/java/dude/MainView.java index 45ce1f9bf6..006514f988 100644 --- a/src/main/java/dude/MainView.java +++ b/src/main/java/dude/MainView.java @@ -28,11 +28,9 @@ public class MainView extends AnchorPane { @FXML public void initialize() { - System.out.println("Initializing MainView"); } - @FXML public void handleUserInput() { String input = userInputField.getText(); @@ -46,6 +44,10 @@ public void handleUserInput() { DialogBox.getDukeDialog(response, userImage) ); + dialogContainer.heightProperty().addListener((observable) -> { + scrollPane.setVvalue(1.0); + }); + } } diff --git a/src/main/resources/view/MainView.fxml b/src/main/resources/view/MainView.fxml index 9dd0eac360..fe4e058548 100644 --- a/src/main/resources/view/MainView.fxml +++ b/src/main/resources/view/MainView.fxml @@ -8,26 +8,26 @@ - - + - + - - From dbdd4e7f2ffd4b384198ee29f346552bfd30b516 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 17:04:09 +0800 Subject: [PATCH 111/153] Added proper images --- src/main/java/dude/MainView.java | 5 +++-- src/main/resources/images/dude.png | Bin 0 -> 11000 bytes src/main/resources/images/user.jpg | Bin 6686 -> 0 bytes src/main/resources/images/user.png | Bin 0 -> 20057 bytes 4 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 src/main/resources/images/dude.png delete mode 100644 src/main/resources/images/user.jpg create mode 100644 src/main/resources/images/user.png diff --git a/src/main/java/dude/MainView.java b/src/main/java/dude/MainView.java index 006514f988..db1cbc86b7 100644 --- a/src/main/java/dude/MainView.java +++ b/src/main/java/dude/MainView.java @@ -24,7 +24,8 @@ public class MainView extends AnchorPane { @FXML private VBox dialogContainer; - private Image userImage = new Image(this.getClass().getResourceAsStream("/images/user.jpg")); + private Image userImage = new Image(this.getClass().getResourceAsStream("/images/user.png")); + private Image dudeImage = new Image(this.getClass().getResourceAsStream("/images/dude.png")); @FXML public void initialize() { @@ -41,7 +42,7 @@ public void handleUserInput() { dialogContainer.getChildren().addAll( DialogBox.getUserDialog(input, userImage), - DialogBox.getDukeDialog(response, userImage) + DialogBox.getDukeDialog(response, dudeImage) ); dialogContainer.heightProperty().addListener((observable) -> { diff --git a/src/main/resources/images/dude.png b/src/main/resources/images/dude.png new file mode 100644 index 0000000000000000000000000000000000000000..ca3d4646a25afedf935186ec14609bf44e0e1862 GIT binary patch literal 11000 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/images/user.jpg b/src/main/resources/images/user.jpg deleted file mode 100644 index 3993a1f4f80d6c20f75a4ff0e5962494cee9be9d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6686 zcmeHLc~p~Uvrk09T7^agl(hv#1<}TkfIz_e739_u@?jDp``1K4f)Lqdr<<&S@*$G2 zgbFo40--Ds5%=brn=os*MiCeM?Z-^{%4J2UT2 z$4)okE5Lp!sol?hsr?7`?>``YNJd&hM?N`p@Q~b*&pwkoA}0%yKYk2!ROzU!oPw%? z(uor)Dk`5HQ`1mW);O-LqP(jFxc|Tb=>yV-Wn>O3gXBQU|6|&D3IH7h_5(|#fSQ1P zAfOZoxKjsE1pop2q<}ym;63e=kvbp^+<#EA`}Jo)08nZl;FC`d?3a<2**yZ>C-DL# zee~ED;Qz4s)>~flBKo_e`w#hlyXI5;OhF6xPnnaDuf8vtJEf1p`#y)l%q?#CWlK~k zNo@SlibT~upw#XL=r0>U5O}8xa9BzL4I~8um;tt4zDM_Om{V$ieV_lEGke?nF8}Wx zy>EkYCP9%u?$Zpv`h=sCc)W8gnHhYRGPmEHCiGU}DVPVgo{8K;_I~{-OSj?b z0t4u$y-3oy1IvXJ+767UtylT$=Q08 zLR8Nm&vqj@uA)?DJRnia`IKD5Gv@5grr6b_&El%ff!gUY40;xdF&3bk7fc~-y7GlH zmWTZdNULnvy!%wK>)Ewtv7qm5X-Pz{uXtwrTx^YA-?8IbJ*{y;yNPRgbjy4F@!d_`w&KUJ{)c8!8m?Q%dJ;2;3+_(?j%S!v%7gOy z9oTCALsm51H->P3r%a7hZF_GKJ>zOI@lK+PYg<$ww!yI=26EjUj zvwOihn;XgGeE$j{>3yVknf;ObFYm6u6L8ABsm`2uQBG6a?G|a|)!Yw1EibM!>fcmQ zP9*W1Iu{B%sV#$y%50+z4Y@;xSSW&LW?9JsR~v|LQK?;LsLfr~NnJyln&fC2EP6Z| z9mD$Pl89}&vkK;mR!GOQ_hx^nI$8O!M~tm#FPog~t@Lhz zjfM*}3j9}T^;b*H^_RyBAMudQb;%AO>LOn>Wn3F~@`OAFeZ;pB42WAj}`f*VZ& z2*w}bFZsq`jCm+H1U{JrtBRHoDck6a@w1=*!H(Vz!&BZ5JS0Jm2LZ zPVi7yi7PDS+)Rahp*YU0q=eo(o#t9VpoQsrw<1Y!r`}JBuW|a1{_;W9NBGt2h{i-v z9~`MHdwde|U3NP`;OMYcI(&va5gX9UUh$2HRz)6!61(jm^~7oiL2HC~?wtAJ4j?vY zOGx^b|JvwMw98LFE}-@Cx#vA)6P)q9RNL>@cBm} zm1vjCkuoZTm?^;$GD3gf z>Puak^KRZ2JqCXI{%;@U)prxN19(*)v7s1o$yNlpr|-QAO$RUQuv|D5>kMeKW+XK7 z{XgF^QbpT|HN8uwEnj$Siig#57eg$!b$z!<8lw+vn=3DW_S@d^j~tb$FT^)H$K_v- z?xoK&23PBd8ir^;!3&yBLJX%STDIAfadq8$MnLS8=ZQOQpg$fs zxu^5@^}2~v@$jO@3eBv%kwHA<9vcA{Ok*tcc_==psxVVV_KrTnOgXQMbGshHoyUwJ zN7Fhw04b4sYEA+)_gDbn&_>jC)30n8ObGlC(4X3fZPVG*b> zi>yAo1U8*KmfNkuWfwot85p+0fWUl{xushlRK4TEx?nQX2nV^N_$Ib*NOjx97-K{w z#8!y$rc=gy9RmT2o!QOSj{;!neeB{IVax)3xtYIxBH$n+^6-0IAD5|RZFe$xlspy{ zscWiuYX?xm`kKizakOHmKX^P&D`HvJP>plhIS#>3Qa$WiX9oJHCk0~;?DA!Qu7%65 zD^~RQ_>c~YlD9ZdjGYqHvynHpj0QuLbk5;{1%E`ZaYg!o5M}g2-2nPZ;Q3>8adgePe*KL6q$9}N5qi2fh|q_PH(G7-1!;^U2Q&`pYc*f&iBZqk0o0KtdXUT zy<}hLV5Q(HPuS+w;A*Z48v|o@08UIZbpL5MR{tBmT4yP0tYK1F=Iq9Aa# zeY`u{fF9BA@u<~MEy{eh=CY5Odrsy*!<> z(;w3(vN<@qTc-(6)@|QneBmgML58+C!^4S^rYPhw@#!6kDxfhp=y^+Vuu=9Br?BOT z!9C8b6sywdxSw-Ex7{)17+Cj9uTlksqiWl&#j=8$n;^6MRk=TO)uYPXFHyT4^t?Gu zwu-B#n386wd$L@u+>38H*@2goD|Wd~W8I5{3L2r(>`e4p<$M~RQrCYz9q-;$nUsmW z(elq6A<~TZ8i&L8+l#MDZXVATEBlw|jV{_7T*!f!FH;Gk){X7ldIG42w-ZG^YVQl1HPI;0U9#j)z+?{o3y}J0w z3yC`O{1WY&dazqRg2Gw^#Nz;EAb?n94I`crdbn$SVm6a7y zzV%b3@7DXKRnJ={JFk)N*O@mh^sx8}ce&;prwg4*21lHqHL#LnT#{=DOsIn2YTa@j zSHJe0*Wi%ymdf?w!hsi8%qTvj{2Ix%$ij-`1!jzY{1o}SlZS&&DBhW$8NS&Q2h&5n zV6rC@+d{MoG|m^(yZC+^l)!9Vx=FXBBn~=KV?&L`IHyp;N}sLn)DqqFRHgvh!weUo zTJ`R+3!U11Ls{OiDTkO`^|vh#k&Z3%NSDg|LPv6(AF$xIUtyq`MdoirB0fAcgzC>; z4x`MHGDk_z3)FD#rPw8thEcJB&L}hDduGhsXvz&SPKQJ%4UmQPtzfXRm8WJk-|%Kq zZaoZYZR&N>*CJ##py%#Z-V8N-J2!-sj5kn^k2iknQtXoBB+r8jTZLzvY(;0@*N+bc z?(n6cfG@#}23{p1{a7#tNkp6bH!Xt+_77mmF}BwJz6cNxp}&sR*(l=@N7@QlBsX2h zhPY1OV-7hHS~$vrCszb7U56oVR;({=%ir+u#iZNV!m?_hnVX`_r52Zg@r31{72gFo z%<#mTk+ai@>joy7lR>$6d($RFv^>#IDGx=foaubA8M`stfSrh*MF+O7s!;rF?Y45vVsm+eH$`-xgHUV$v! z>9E{c4BS852^nQzeEQnUjQ9s;7r*{Xs@+L_$6H1|a&Mu33t08+m>@9Y$R*nw@AvSzH96Fe!JiB4csqknQJ5GgG+ zHQOY~dkMk%9i>m^y|UWem=RYR3d)Z!AyB97US(u7ke0iIoG=yivZV-4jQ>}XC1#J7 z28=?-t4Tg1aeTfLXEd#PE?PED?%p~R#!nuGNLr|LOU0VeTw;a+%5ZR*NG#{^%c3YbzG3C z`pt>SA#YFa*hRt3J1eF$^FNVDF&e>zGlGRKQ|s#&Ra~xkg*)duV)KTDjpXsTl%V1P zq3_yWf2Uj2}U}JHORo* z{>Wku>h7A-Z(_Y0ILCB@Y0Qi4ipi`tV|?MQaeHB5pxi4PkcVdP+rCoyaZI;HEgUs9 zX%U-J3XI)N$X?GoIz}PWGz}<{2deQ6?+jSGVXI!9pNjUkv~pNpY$-9e&Tzkr zC~7WGIffU2b35pv@qR&9IWx$KPIbM{|2!}4YTu*vMd8)$q;%p1S$rZAindyC%no+X zTH=|^{(Rus59#=8b*$7Vw7_+WsIu4!_iG77LdI=FmD(e4qll{5$4?vRnk$3wgVQqGhnYf^dQuWjYq`|$JG}km7fsMAY07Eh8MRQA&7Pie~SBm|MM@i|<^N5Bn z0c6>e3kA=N%~Nj2v*shq{($(uVU4K!2|cMs)kaGWcCV<=!ZCg&h`)V?RE1MpPmQ5d zVhaWOSgU%pKuy2Nw{D}YHz~ihz`bIvtPX{F*)SUcqsXb(g&0(sKKy{L4Rq`im$N_S9-tk2d@* z)-?Q7GhAa)G`5D3pY^}W{obxB&ZU0Hx=kF&E!uRB-vQ`bR=a63?*K`=)2^nrtEQ3L zL(HATi;$(MjknEn9ZRD>Vj5I{+xG#84rn z(a_ARr+En{WHzl5U*wKp8=y9?0V%unT3=QFrC3$H+T3qgSWYl87(zCt+@6m3Rb|8G z(NNu@AYhUEqXl^FRjlLSnRn&p&mcaQjpfF709v<6-zd7ZmRn5XpJ=;hrTl%UyI00p zY@$_9T8?|`SZdl8n3(xxV@Ju;zrB%kf(o;;GxJNYVCw~gHtJn;dU(Q3&VYYt_|dT) zfJ}0Z(8A0%<;|a7X?D=xZU-=eQJ>CP^l&)h8Y^mtTI(qY zu)38z1Ozf+di{ALHQp+JuGodoZ~iTQGwQ-y@e}o$hcA7$kh%k+btyp09;^EM-Y;Js z{{LgUvH8CjkbO!)(~g^vHB;tSsgpr2axVOPONB_$q)RVRDM~L2 zp+^vrngBvVOWykXzxQ%ZPIm9k&Ye3m_wL-8&nDU0(ujeMhYkb+F_;+Z+k!w4;1B}3 zL=F7>jrx8H{7{D7Fu8pR_{3iFLIUTs!N!hZAP{5Uzb`oFDkCq@$o}m0UKtdoB{p+`*3U`(w3tjAfkoU(&%Cq#06DBAi zw03L_2!t)06rJQ-j6e+h_D=8MQx7mz%$KJwx1V34qq}4b&0tKJxS7Rad?Q-%)yYM} zUdA^spU{o5yD=pP@Ltz5Wnpx2_t?_?68QMs{aqFP@;`>)TfE*p@=#3aewasHd@<;S z?>XNj@hokicRPThw0l;!4#Yt?-FVzh>T27^fq$zGJu!T>vT=XBq=Zs{BDa;J7Fj-# z+X;p#&rthA{K5Xz{>#L}%G8ou38@JTVamaI#UKGHfj)6cCU824iEw%%Ig#@|0Ty0K zi!iQ%qG!-1sA^0(v+OWpSJ3O|3d|`4b$5zV zZ_9@c4|A8pg4_vRqo|QRD%l;o-wdRZl-tk5LAK%i7%H+mR>=R8>scxJ*>^jMU4GT)x{B|eOf8kA0dLjiX~tSjbKR?v2*NO2K7>S z6)ZnyHxBhK8bsvAvtm&r0Z{0-GXCK{f{{B_OXFRG3fT(Qm!N&JhW!-`5%h1dh)8Tdkkpfg`Mj`%P87q!b6H1Ku)h@r_fJT4v>@2tjo z)JtKGhr5ScQcJe)``e>N2E-w~pH4H7ycVFoX+uow1p$(EtyS!$9i|k{nk&55GB6%9 zx$Snd0a`E8660w#$IX?~WW#;INmRj$U^hnsP|qhQ^|Z`sbZF0+j-q>3l3o7PQ3O87 zc0!1$^V;15W{HEgFy@2JmeQOvs1OpHa=NU}f`VWeiRwp>Q-gGJzpgi-%^HmOGgpq$ zP6$EINT-gkEB0l>ir6ZQ2rCrj718JFc-MrKAm4b-IeZH*>>eo{nZUL}xpQ&4Rv)>$ zk<}|_kYnc{2+ti%V1;sjJ;sPjy#K0;H^^4UT$_1QpR;AlAkx4#JqWhEcG710zV}D%Fn(%n=zrCI_L`uNWs~MiL>dpPfO}FH zuC&vr)P)M-DX=+zxO?(;5d_cl%ek4o>CxFqXnTZ7+MtR4Lw889R<439K~H6|k*3ql_qUKAY9vmMABST6eQBij~xmn8y~#@EhlxmX2)Q80^2#9x~lG%O}(3} ziMwrm9JVUFvp93(4%BfN>HsNNq_BHmak-7|tg^TLumQS>cD*>4#dDpU#k^m?f;AW$ zG}JeJD2|UjU^4%Z>xkLf+bv8_`KqT;uSwBc)|LKk?7DA&ELgLecGhy_Z3h~>j=Ss$P3i0G9CS&-O&$d#+vp?zPfPs2blslX z3Jgp|Z7VyV=wgI(>vRZ+YuTZ4c;DtctD!dx7$zd?x@i_%s%7>G^7dDKf3YyfK!V(0 zv5i1d&#qa!#TOQfB`eb5yH|}6-mBRnH_Ly`BUB;jnepzvm5WTVkOjIs<)((9I%?T6 zK0m6xJ`RoN#Zoc($R`@sj+eS3K+j6-Q)E-#EK z5>6J~UZtmAhhtP6RW>H-U@hScT=Ec%1jfl@w^>Q7@vq1gxbe| z!@kCc5@fF?;OG5)v!@Cg z@;=c0eF)a{Af30nS8a!br@@%28B9)J^^M7Rvc{!+XJ#-$Kziuqb6s~o4*l|Hg9bGFH+n83U3R%lDCS9ZHud0HAsKy-z8C@+6S%M=Bf6Nr%!C-jrW zciKyl-)B$JR^L<^yTx_%Q65nWc(uoJ=U3~OPL&QhPy#eyCRCi(Y2b6LerSxu$*ogY zh7ly=ZGBT;#Z6VdGyBZ1`ih(A;--x*d?dt;+K_ti3T&OAfi;I!t}oq+Y{{NsY?_sD^=r&NSzBH~!x~y$6UkCg_3Qhi*U0h)W%+_w zP7)Qm;PV?cz@eaRNqG%h0kmt(w5?Yk-_eFkf;A~w}|uB`4x z9XJzTLV_%qOORhX%ppA#Bc51=ZANUjgNKsTrQN~Bjyka5I6ekP79`jMm`VUuzlY{-zB{pZ6^}4S+6zQ(|IW#$4dU_C&#&W{*&tV!h3E~UToCC9W&tzn2{&YT^Zh{UF>uAJ}-q((0mkM(ry{x;6cu7|ix^?_kgi zlErF^nPHF!z(>}7TIpUg^7}v$F?G6$6(F9Yaj?u!At$2$irN4dQa1b+F8^!CP{)vU z`uoWW?mqeT`uYzC!yxrSAq!#+3<;XXVf*nAjFg1~4EFJtdhtqe+isH0GjrozbWp-B z>v?Tef<35-gX72sP*ID&U|vhZf^xZr1PBc-w!>yaINcTgJBaw;C?>M3B;zILTr4+EjpV z)P3;{v_QN3X^HpVy<8(oS|tm*cmI!5M{1wS@d?9mAo;Uld-r~1o$tA-?R8!XCf4}< z-q!t2ec5YgC*giZi)6E-spqa&Zeci@K^vlPyDQ35aitesbDtZJ=4g~1*b4@a402d%(~bmW z4Cn{Q`$z^o zni{H&k1AV{gDDdtR!h#tKlP|5|5Boeq6xmT+43>4VsY}p+5&F?2Q;Krx#cMEmwO9a zlRKh98&SGLS|=a!vu`O7>(e$9YCA%5C=_N@%1u?=#iEd)yolMOWN93h2iyJgjn=3!IW{0&Zr zsKjYI^q<>c6PW<&SQaPG%rlR|&U4O~?+v5DjBf#-za&i)|I7U^SN-F6i1LWzfxyH% z7&)o+fw$cnW@qVOk{vbleC)WDCCcQTd%21R;!VQ)Z}BJ@vvxWswYP&5u+NNraxYGu z8y}Q2&ez{xR7H`W+?@&K#rr5hnX5lUVCg()@`opdMB*5YIOE1cMdrV_l;`Rg?qD04 zF)EHqw%+4lSurwI(>ox@qOyqRfhoQ%tAZ?ZoQW&T;v>7biQ(=Sw(zV5BV(LVWM*0T zy|d6*KBwlZnZq;a9`rG$hsO#W3E^~)dGJ*pcr=P0^Y-I14Mgm|Q+M$$=t&S-*E(_@ zqcx>SFS)9VFSxb1mrSv8=&@Jx_OwB;2+*r9TSb%lPq!S=NxyoTXS$uA2K*<=5PuXyy@ILVx1OoU8jRY4Agn*I_~h#SM7{w7xjg{pUFV9b5(vjSHhRj18@ ztTM^4D#fT*m-*Du_a&#Ezmz|ZYo`xDbzAadG<$6lzu5j2{yOmj9r|OVr@os0L*Wzg z)73RM;@@wFwyItJI(j>$`1s8mD7rk;?eUA-2QP;a7Bi=}4f0#5j<>4qOSF^%4r%Pm zeah@$#KtLPJ*kQGXe z1nsFLm>A*V&T8Hn?@q@MOxk{6-{JIU0J7+N>%BT%fk|Q!Cq>G&KJD*~ZIeEz*BSz3 z67gF(G#hP+Q9XPM#+C!R`v%Wm4V+z|b*7D_j?y_!)oz7imNLh|OsKnOaW?>>m=Z@q@5v1l^CxT)c5cvnV(3F&N3m3}TBB}Dw!kq3Ff(fFUMUFa_ z)x8;`VjPwxx;Ov#^M4_1Q^xKpArhz6fX*{{XbTNVDYmLD@_#sQhYfaeLV7=YjKB*! z8^)dMXoot?#rGO!ylK}Y%L%NJPjnOD6u{=m7%P3?_To3#twLa&N|nO0oQqeoC`laL z7}zUO%haQIk1t6v0TWBEv*3K5ZB5g{>os=f1k;q__5<@==Jgt}XM8)vSSAc-u(Bzk<}vmUqeFOpJ_8JCf; z|C8=7d?E6h2}}QMl^ynx?1*mJ7tS3!MyvlibM9dmEX&5+#!7jdE+?Wfk6!;GXs=rS z5)^xJb7VWdAyN@N>ilh(H59(j*9ANg0AVS!D2J?R(WdsujH zs|mWq_-sy_(!UUA_AZ;`#au?)EF|5E%ZOzG`qE@G zhITFE07IW=mY>qMl5hls2N+)Vjm+Ooa5@ak!ogONYy>bySjb;lyY0dFo#pQbvzZx2 zXZ`%kebwKUa_;+x)Q=|F#tv|Lz)j0r8~VB{LY+J0JpxP?SBqHx8GK)1%9*Pt-S+G6 z?~LaeN+lm%6>>>k1$iWulIM$5NR8_ym1QYnUJflZxh(P5iPRlL&g;B*i&b5m80L*R zYT1yvwc?_RbpYxivP!)+B$J(S&rf9Z1G%IuB_7ob))gX!^-{w38e87>52QmpSq6UY znf3AI4J`^l?QL4uqF>&cJjB8tN{r?sA}i^PP2Z%psoq*f$uruoA)S&gUI9u~_cuRZ zK8QDn8RVS1gpKt$Lu>7fRT>8wL8n)IZcWMY*=S0P_N!cmZpwtFCkJ9V+!MVfjo*ti zmq=i+{Voe4H&#Yq#aF3` zD^-^bo)lU-liR>cR2j|@wt@`#xP_U4p(6162= z;x3Z5EI6UcI=F&2^M||}=Bp*%=w?7k`{AHg*08bp8I(0iZu;G2@ljG( zxT6bsVahd_0e_yCwIlIQROIg-)A>oMM6Tx%SePTjbr*`6## zq>uj-G4p-Kzw_DGjivmPy*&>1{DvnZ>cZ<~THazh$u*D`(|^4S?&JKd*0LE_{EoI3 z5>S@mM-icVMYe&szGV>pm>*kjJjj0nPdV5#Vq&?bo)emaDcou-hthk*pC@ip>!1`bNhR3> z14%REN@V-;GI`UCrs|({w26c!*`1I(5xoPtZR-!l0~{B)iG+`j9~7);%riS6;^R*} zhlI-623V(O8}ASDTa9$4X(X4|(V|(-&*trIsfCjcl+VwmJ+h5%%y6KP4;f!IS@*D$ zOFI%MZcz(Y;Hl5g=IH!!QPowW$T>yg$A6Z?fI9;Kg}LS{B70;vtFC{MA(So7H?|-n z$?+&fkW@L+DDS>_s@~A5?G>e`77{*&hnxQ?7^}aK_`S5t33wHquhse450>We_L|)z zK-?s+=wE-oaqx83HnL!pyqRt3pzp~+mOKe;b03HVxo!p_cedvszYUB7X=CNZkoEjl(y8It1IJlsJ8}m z8xeq>obLJ>zfT9jT*FSdTV6jk4mzX!{`l@cgF{<=2#jxU4dG_N;o>p$^;bzvoTItk zLRG5^;~FNho#v+Zt{hYKHPso^$YdNWK*&8Ue0h0g`-AGLUA#oA=TFU~mXdE%%4SNb&*agI}$%B96uOP)r5O$R@XrokeG zNrcfho`vsv<#qQpXIr`2KDAp`r};HV#}!9}*IK>1r*q7Oo|b%?cg_1PD+0MdhQ1G~ z;OU|nf8St$fL%ByTR^mSSDj048}+@x-K5x}^w05^=xLR{^Lh#6<*vH6u##rA5G(b% z4!f{X`|k*qOvHs8h~E5KbuC*HRL5o7Z_&XL^%dy#DWg9$r)s-!J8NryPeikH$)X}2 znhqAf$Lp*NbPfvYxR9fmm{mUGEWfpL=n zV2?BK*N(z9=M~C)q3ll&mZm&ifT*@tc22R@Ks z#Lb)0PGIL9=c?Q3gyk74^;wA@N9AE~UJc+NjEZy-h+##1z^|koxnW{jV2Rwj&L!fY zDQR4f;y}Ajb+H}sKGh;CmnJ5@zLplPai3XcB5r4j9!HA~1Z*alS{rz;4^Dje^|!`h?VM2tML5OEAD;HZYMn`qZ?X5Xjcpv)BDJDfxex_exf zKr$GjMZ?kYMcdh1Q$P^f-&ywn{7z|G;d~mx^cW&fjrq|IJw2AY`BNK=Uv|=aH{4k# z9R?VAG$sZsYy~PdW96l#pIje1GWj?Pw4Y!q9GB0mC24c$`%AA9oa7lWmA&x_6O`^n z1(%xjB0*k~UDF;{1Ur=gMo|Rs>Xxe%TZ>J-z2?eb2hiegz$OKRr_%FTF8S+A_JGg4 zZlj4>Y#)mgq@Y&>?S~D6@k0%^3Ja#44(ea%p360#iY2#*T<@048wyk()wMH}u{H5UF5B6KrchIAql zv3p#{?_W(7E-wG5Sy`t00yO7{=s2YI!CnznulpWjC> zfBR4#9T8C*#7)|EEEfoTREtxGlgn_F?rimM4&}N(0p9k^4$VIn&e$gP)HpFxu${jf zEcU@f2b`Bou9O0beeVN9YlGzeH~R^C`+Hw(1(#V7-_XCi|HnpR!>x_3tshuRm~cIZ zkmjqU^!`dDlL_GaKJat=eYEln@ugFPP(q{&sAl{yM(3WIxYZm8rLe>tpAozPkW z=Gyl`2-bB&V>arGSTqEyjWFwWPAAh7|Jgh|ijW#u!<5oIbf$nVWd-2~ZryI48PSjV z+J@W5694HkDk%)!WW(dmEdWdqo^Oa~E07^*L7l8<0rG0=ibTcg%yV1Mv_M-JIwUIe zUj95-)(=9{qE#?3E~|O4_0!=P$OM>g&$%jl1x397{5IVqZdsiDYgLH&5kZczzu56{ zPQ~A*6U0~MQFN(-RWKZ z5f=o38hCmi6eBdoZ*p7rrxW-QA5KaAmBc#4QeXR|ZO|Zg#mFAy^e=Gm4y$2`BD{YC z#3nhd>OB`tm(5a0FE};GPm=Tsa0(guPE4JwSZ#-rJRoAq4#KXKaCpM)`pjrZtUq?$ zk3pecodkA+?WV!=()1$&5q9qD{{KNNQu3^ajFlB z|KphP47X>6_!X zrCI(+dQcw*VmpBip;DZ&bG$n29-plhKSqOfJWdmeZ6C|oV%IZyP0^N`2Zpobr+`FA zJq2D+D`rThroB4fI9me0+qpo|wb(wjT~@}qx%R+=`Y3S6Zsr@1iV))Uxcs*4^cxB| z&Oao5ZnD>u|JII5*PNA5%$QCnc(S!jPqeXK$~5G~hpno_c7WBcz70h6bk%*}{peY3 zt*yQ3T=G?~12IlBL*~IICLEd7csAsaZFJJ%Su7@>Vj%L$9uWDJb{*8G!c?)w=b?)A zR_+%po^sg#(5G_LW3)AH<#NCb{x5>(Dwtn;9pKi%XXZ>d14a81gYv{eS}4ba#D6k5 zxM`{Y9VbW!*UEW8uuI0M@OE&_46iq<|5XoMr}t_Qe5as2GGcl;&U|s66(D?68}vi~ zY-|_%6w}kn8X@7XkHuyDf>>0mpZ3Q z2|X!Q{0o4;VOI_ncHsV~@5R7k3P+^i;jQ@fu~atSJG{ZdA-GsVcFAl1mj+W$yBoPL z+TC90M1I@26nl2q4zkyhmP^0Kq{T$u}%;Clo~NNmb1sj-ff&U zZ*nME%1dOw%a!-V7~5KY@`9Wo9-X zXz7Gq=oJLTM9w$a;`(mDzU(thSwIA6j?Gx_$m}v`-RKxU^z;49;yWZxJjRiqh;ia; zzH8PYz6QSl$qFwSc#7e_u_gQ%=|r%XpYf5CXCjOn%s;iJ>w-yj=BfV%Z2+X}QG2VC zsR4F7-9IAuEk3m@TAa*jU-Hj}siB1PkU_d7H1&YzPTEYS(0@5h=r8Zh_=D2hW&{a{ z@7{0W!iWGhqnphFJ#aWwuPUsfBS73BT#|GFcd57>V-LTe+_&pLMYlG%5NzY_ys!87 zgBd9CtdM%>{SgN>x929yzov=p8dOwiAuRN~f}drPLM*IK+@BEj@BT<5|7Xt%sxD%y z_N2M80lBt%Q@V)1Ugl*OTvlT6nWUn$Fe@Sln0!zKn+tEtYpdFnQ96IQgzCwJT%cSK zY25j_H|T`+bQRXGN=FVsdXMEigqCJs*TiccxIF4;Fi?}Q9&e=*2M^v`c(!p)Z%L!! zag#knfn%kom-5`+u#S_x8`*>^kMFPPZ3GcDj=qYvQAKoK_#Oxnn(B3gY^hoCyX4EC z$ok(O-j~Wkp>f~h6}AQfzg_TPt|_f*9Yf-7E<0Ux5922L-G;J$6u9$5Pj+6BJxPx1d7TksgHCeIF_2=uwIk}I~nWqm$a0_6H97}({ zwMg4EgG631j#?H5A4~EX`u5;cN%pi-?0AyVr)8_-nn%&rc$gHQ*(s&cXs#Xl2b!~f zkkX(nNt>>-n{0s9Wg}q1%LwNci^WMe^$KGDwigY$E3Rrcy9FIQvY&fgaeNTY4$dW3=6sBAEE zFf8J;@#Ax@1q=M-A_FvJ6&~O+l_mg2(pRz)*^Xaad;`!o;RPuHl79nt6rLH|y$G)j za@2fZLJ>WO29`pY+GPx_nq1^fFFj6hC;0wGAkr9w^V|L$;ocKgVM-}#cf{3Ffg9Y9 zeC;_>h9}i>zz=wbh)DBcFSAjrM|sY&n>I z#>DMX)+dKmL~EOReT?uwER4?ria)ubV!6F;oN>@;>KZgbtAI`(LYC3`$f)NPAUD85 z#~wbsSopu<(hs1xR9!1YEDkFAo9{jzUK{I!1~XSbA4OPsqz{L>MTNb5mcUxSL~T$W zulX}(S$nGUz;P_6w@*C^b!7|02qqx{)(U`n);noxOA5w7J|MZiNFo*|`bk$_RE4eA z9j3XKug-iKE4bDWuGB6!wd`#o(lV>!!H)XPpNKn&0%H#2|Ac9xKjn@cCEs=#Z(W_P zcj-O;+|r~?k5TaKe7fc;?Q)O=)Db>+jY6elaDH1N_0bS~Y1q1x+N^}Fgqb7!=Q&%h zZ*Y)5^k*@e-rp`5^@t)8WDk0&I<)i;KgjQ-K1%@gS%82iQ{VVfYUsnYk}A+RxH#2Y zaFMFhOkTq#CKucaZUwb^jI#!zIapJWy1-L3ky#at53E7fsBp$Sjl5ph>qnu|e`lJI zom#(h?^c7!7fN@y|Ia03_t-VE3uR58Ykv$+r=2cm6vQm-oJ*c2#_y-=&hfoSYk!~& zpP>oTE>6Tj5~~V%ufkxq_Eu{#smtw=>$i%o;s$zrk-%PYTYN1Zz6`o^ACjLEPqz|K zv<(0Os(EpKn@gAwHFSXi^AYQxix$ZF4JAL!L)mEQNd~f0?M;bCB6ZHT9M2D zoeZAcJstU|bHIo`2K0(VeorNQY+lg>MXHlo{$Gk1sC%#5aq9rtF41?4ffMK{Wfb2l z8?=1uF-{Z2ge70WTK?a?{jy_6G7y2ilV`xb#SUFG);rR<|4)d9!wzzmaC@q&Z`Z=v z`LN?yuX*G@S?;nbfTIjoXwkd>KPl=F1PiBezyG{7s2v#UWH?AuZMJCM?=E3=Gq{7LtAC#rNDelftjJ0)%? zasb19$Bm{0c1#@<@?|CDKOFutdhz61yYWHY;ZozGRBDy}gXkczIanORdwfNk+~vAP z=4N`~fBx9{4I^S5ojFiq@3DCU%t3L;;~iJ0J5EvDH}y<+QSxfx8f$fvcHy>@NeLfl zf@}~cCC|G;Nf`s_4XLpzXH=o`@mQhuap#Q)SSH4dr?wb2MJs~pZ7zpv4Q+ixccb}J z6?vn)+8EfXUv(F57bIEyot2+xJ@>S$qXnc zBAOaBU(AAMJtNrx1igS!ld_T10MKfJo>t4EWo{Iv;OA~>(WELAZH;Aw;0TifkXXY1veyXKN8D_JCUMM*}O~;7---Z4|Xn~cAH50*6Xk@ z^NLdxSHGwSj4v^BqO^>c)S2b5D-x0p?7LM||qP0K~2O3&1Guw}))*+zUcTRw2p{?wz0Q_XsfX zJ|nkQh5=-XNdAOrYuUJ*88ZpIraO(kM^Spvip!-J2M-GgbesJSLpPy81z_EN-Q*lo z_^>H<(7{#`8nm`g&V&bE>usBxb?;I=;C{B7C%)=UfxU_@LN7FU>A(aG-FcaplCxQh56h?o{D<$pH5 ztXuNAhh6$pW=H~j&0&Uk$aQB0wS5w%SuZSKT>=2*Kh(Q0s}Anp@iZCf7l-Kf=}@44 z5|#0W8yfeg`gkKpEkX13V4swq&2Q5s5_~Zq?xOB=@evt+xPI)W%v+Lds@LRW0x>me zc;2%Nz&!4vI_6oT_rK_8Ow~;vo^1|}bZ-}J{?Xq2P!!Ll(taGOT3_S|M~p^vmwf2% z>qOaJb^_neB+u1HKEAYoBasn_2_JmpGF|m|9q4I1BOj3HwaiItJ1&++>XhZm&`vV^ zTG{JoluEZ9!QPSsppt$L)Ng^m&zy2WoZvx$wWrQX{l1 zZQ;vv#Z!h+-+^JNP0y+-k^(S{Wzdoe-xiUz~E&C~W=>akQmXb4F09!Due{882qDC?7G3U== zkvyBW{-0WwN6=|A9r4QXUhDUT@qL^d&Ug|(iWe;3c+(Bu^7jL9p-dALIY5v!(Yfp` z&p;II@41Q>gs^-x_I=Uc_$d0g+Hwa9XMrXjO;+>BB^{{vZ@gPf42@qG#L&fku#qZZ zl0i5C&tHjNP2??sVVWZ*Uvs|#PpD1w=LWW0NcjncU?H{;fl6r{KG8D>}~?hkh_y+3uZ?8%w0YKx)IUH`UBOx-?C zqSuV)x}XvL#M__QVh&dvqc0fdg9eY;nSBRH=+R%eRwnQ`Lz>-Gp7{v>Va=SF zk$d}jcjBq_kdSEKaKi_wFve0V54f*>aE-0D2qN-lNge#Hw{WmSa19IYO`kb)(}v^; zH7Q{fsKi9Y2tHnE-}}5=H&Z0aT`Pt0{8qSN6A8gFrrla?1~={FINeOR`}87&E2nV< zikCtT9S<0?moUkdJtE7;G<&e16;dx=QtWdak&q3&f8RZ)(9-s$RCEqNoBZPC zvv)r^&9Sp6d+{kk(Alylj>O*#wVNwUjn{3{@}=Cy16Ac6$`(`Z|C;?N@n#1M&u1Z; zPmQEJBB%mI-QvmWR8hxQE#{u)4ZaSt;_mA(7ZvaRJqx57Ww>vS(6_#tqK%~usJpVc zzT9&v?fxh#ThUo!jXWm@8mOW#;|3P!iN|d6){h4yr5U`_zyL35A9IJWTyjRRrJk%=O5Xg1GvoeGDS$p$;4yViNon$Hw!zb13v&l`e=PNE;E25O z*q6W{4f+^^B1;YA46gAIc{gb~le~svWTyUW&A6ZVI;^2H#FmdAT||tZNxFMJYu`tG zeF^;@5IK>D>OARh;-bI%27q&=A2j#B)%1O1aAl$h0aMS<8$U?}3hnPg(6@**aEl=! zFTM8S6EgME!OMd@(0Rh&jc+BBPcUW3C}mQJY5ngtzrII%7eKYx&v#Iz*jT;vgPxyW zd6&+m8qr<#!>i3j!GSa^hjVdK03u*MGtZJt$iDvdF3eVk=}xhJmX1^}1+x9BhJ)0v zEBid{m&oIfsKn+!pQrad^51=tGgxJ!i5N9pI5rI*5%Rf?abLd$U|V{Qg?=BNhYtxo z^^@~p{LC$t$c&EAH&YLG0r>+UTht?Q=;3H^=@eC$h>6#f(|5?Gwk`F~pSpdIww7$E zZNi>qMcDTWzWESS(P7AvB_B{aMcbul;swdQEa5Txbr_&s=km}vdL@IG9q zpkTr?sYysRsATNYUYm|LSqithg0M$f!X8u_vBw0;Q&VtM6 z2mkdE={ub9sBkl7S_dk=Ovy?On`IrtPZewmYV`x4`4!jak<)c`S$fF4N`mFZu0e!G`2Qh{1`a2VJD&~os?~-5g zi9d(+C$9%?qQBjjo@Nfx4_5avsSGE)te`V4|HUXix&YR-WVfbD6_xEi+^1bL_Muo+ z>5mEmxcw^XV^Vxy|EdwGgyWj}MJsva=fe$0=8by_%ZuIPGl4(NOFULn`IPZ{S3lpt zXnxGTTvvzWWzgzcl_`Irzdvq+ za~A1WXYR-9+~b?8q0urO0e?5VzTLvKKh8l;;P81K#ckr;_^P;(Zr#pzK)sKTEP*&; z9YERrYWi@&I$)!cgD{EHScz`O^6Z$oc6?-YEOeYIL4#!2k^C5wzZ*!B;=^aV4^B&`*IsjEbkDQ|^E4WsWTLD-k|Y zTxHz54)pyFp1iak#38Tas04%L-dbl|9ox18s(WQpwf4}+7vq*(M)$Ozwarfbw#KDQ zKk%>n?=553C5!?Z%5pe&_9)=1~h zhS+sj=C~75d$2b{Hv2Px#vD8<2gF;x(t0`HtnBXxkWFXqhP(N5?vvJ1#4JP%}2K}Lr ze>}4Ca)s7_2WRfvMAEBAue~^5HN0aj;7>6Q*)j8fjsx(NnM)yk{DZs+X=Ya8DWS9QChtk2S3Z9=l+@~MC7F9^Y)I3+UO+R9- zb=BK>H-js`ES6lt5?0uO0Gw7B_Jv@(YKtIC-s6)hys;SW!yXZN{Vra6RVPmto3nX? z_M>*l_(e9}sJyU@g)$s+4S?K9MHl?dnohFSW<}5-&w>SLR7^N53U#4jvBe;90C1^) zZvKg5&)@|^mDmfBp-Qy#YONdrye*beS;i6MrJmvBgR@g@Wmc&h~(FOqCVf4u!)NL0$mOWR}5 zTWYuJ7ba~4XXu7rEgw7fX`kr=1A(zfY{@>9s1Nw8*42f;IA04(NX<03#Tq0QF>nl0 znUu^bVGffX1J+{Xf12re4Xe+j5`*QFF{xP{396NJm6r3!c%QJqHA42M-+dz<_O?ar zJur_5(cghT6^F7oON-i)t*z8`9hH=o_#O0iXo%IfKhaOOB9qAg#*G=}6=yh-XOnBc zq;qrUIvir3`#@4U$u%=VBo(UeMM)&v9MU=KY8fXu=&#~yj?@yJrD7;_q$9gC>^ z2vQAx)cD}xUTa@mM!H8UCS^;cug~S<4ieT_Dad>+B39Cy`DU|N?xEO0e#pbd2mdkD zi(WfWRB!)yo#In@t0j{oeb&x--YS%FH#b! z{|(JwMf|rc`mt2vgU`>Bdv#)grJ*qwg;ws1LtjO}Z&5WfUPI3P+>ZH2yA$^xS#2sQ z!2Ay78T6&-hbrfU#tNTS{uVmrgT!Jp1w~hbuG86MZ#Fj6DJCsXTfgU(A`o#$vN68}o7<^IlwPk!6A;C;G4x$+oahOqWxYczBk8 z;eYmLzvohrs&SSfWw()iy$zv4R6#yUBD7e}U^yN&dz6g64Mnz!)ywpM zs7ZYj65uz8s-lIEZRQ0b*wG{29?$V?4PJ92g8okPYOha^MaS5Y(Nh)LC|^C^ z9*zHiS8k5NVWhQjv#0noO~eXi^S#p01Lk>g_Q~rVNn%Twuo|CP%0g!RSptiuW5XX^nWGUtZajRTU1-qB()D)$?7c z9{72NNOjUuu~pE792(D_$WqJ*mde!86X8bmYZ#>QMHe+W?QD9io;&xZ#@Z6P z>9qML-Ns5t>frwqrwds0ff13~xenj4=!!n|Z-woonrggV4!pwSz({o+PMR%*d&+-- zXE%QLX#6K2{mr^XMAqf&_+Nl~7TxUxJm_5iV5Jj#tRb>aZzNr|z;0~)!QQ|=0d*hb zd~8Id9uCHTJlY4_bZBls-2;_Xz%kCpMk?;z_^-wvtSkY}bFOnGFv0u4h)69=!2fRO z`J`QI)djr6`@l#&e2{bg03e@5HT^uLT?r5vdRF zbpR>LX9JFh)KElf-W27ih=U;_wQ)50$FWw*HzN*))KeSqee!qep_XkT4u*)-#x~?1 z$A(&dfQ{KAZrUl=Bw#K&2}ERg+DN-%f4JqlXxx)PUnGAgZ>F3VbpS-9R?a8?c-Bm5 zcE>@HVfiHaJNvrI7sH|#kvch^{NtG}{!%C(A#I+3p_aqrLKl%5IfDG-*+8WW_;6h4 zA_IFDX)^{6rEDJ16}+-5E!?}I=!B>dj~XAmIEUqgBFq67(v=i(wZrq zz*{1N7HQUDz*6#`6g_2DY`7v)GqcD)uJ!(cb7X9|B17{E(&o4xteg=XtBBOg8RQ?= zx`D;O%Y$RBjrQCPsF3rp-Ln?tZU}Hk?gofRrQDvo0obmo2LXT2-H@u#1i;rNz+S-p zncFct^Y0gtYRNsO+=q>=mt}5;$U02}{zJaoWVZslg-0nOb+99F9r?zytAUNfqZDzp z9&k4KPMQ_Kap*3Oh_t2+d)0X{`NpxcfN{}*ibUuDzD>T9ryIBeZ3-kJLo*HdD|yGR zZ)0PqNU42@ya|IAU^96Uk##u=c#?eMRTq|SU8FJ&C-1GaZs3o=~%#EkshxA9w6`7^e8q)id5Ftz%ArG(Yk@(0#k!y6_H|_ z3jBurvg%uot0>@pVZvmz<=zrZNI7f< zTuJ_uvKz~~^}N_{MI^D^fvd3zfh%{{?c1{-M(P1|>X1z5sXpy>@4qQ(Dle%|# z3R@pAHZE)t8N?{;Isaqi9}jw$YfxSh5mzIC<0#H*-k$OxHVBOfi(Eu{Ysa$q-An%S zzjs-My>XyL!y-Xm2;5Enlf7@b9UGLCR#+s?0lZuXak&SH!OES$JJIWdB0a`p7uCDSe|`>D{($xe5h=Wbf&0ln zU<_8~W3LQt5p)bhif$VAYHyM6+;wByl^+>%2t*{pIBa*pqU8V1}j~ScCH_D7(^u6p1`f-A55Al*P?X-QcXS2_lvw>w|BVA%*f*x5 zfRO>mLnJ~6_Wu4KftBPxkD4tP0Xqd84-qMl!+?9pKi~|dJc=zE+&SQQhLrJN7Lm_u$lOS%N)t zJq&F}D*ifv7h|u*Eg*k?Z?#+n?B#rHM5H2)z_Rt_9;k*><^n$gUWQgPOY24f2LeB& z_{n zfz7kr1^fV8&^6iZXi3pc#y;~OQ2Y&ehFTV57ye0ZM@vKmyFGdw)wng@J9u!zADp zSW4T=sm^Wv{>ozDB(zPhh$J=@I1yWDmwOQ{Uu_u7<0^i3L=ZdsU69Dlv8h9=6X<+-zZONq*%cC$0xDB|j@#p)nZ*J0@ zO@SS;&1rgmK9~Ate7qm{Ch!w1>6OT^X#yY-MqsO~j|HBexh+L84_k45Pp@)s4xt1tLtay78vRsnwozJ)Df6bYdTfTXe|@P6Q( z=-XW@RsoM;ncbeiUd3Dh%y0aBy3fyrz;f2ST|BSXpBH1RLmHj+8$FZphpgk!NTEAVoC-I2hZS^-#28 zT*_q`@HgN$z+YLt;8LV8Gy#w@7zZ2zycu{omJv>*Xu5!ZW8e0F3(U>i9Ff6k0w86x zF_vxcC@jZ7d*0?q&2<4+VHf>BV6SP4l!7JzQf5=I#{@^AI|GtV?{E62Q_oC}QURI( zNL5S$UWMftH~@QWAmU{Sa1r+E-k-5#Od_SG34m157~sX&MBoVOyD^ar&tt$pu#5hA zC`pf0j3xk52fJdA2oA(126f$0P6oFOxD2=e_&acO-sXtJ(gZ;2rswX!fsOKPw2-i_ zy0MG=1^>UjduM4N2%|9k5)s4@Z=i)lo7jkjf_NjXKU=U61QG1KL2Qgzq|j)PfcN6e z;0A(dH15Vd4}8o(nrV_byJWrzwFk6QU6I)zasaTrE1~X#+b9^Uq04XV|9Jt<(G7b$ zz%D+jXF28oVAiRGfOa^w-Hp=)$w9igLoX7)u6 z0A{~u7QHQ4N{q|+s^eb8js6%t&ByT!KiQl8m;-=We-(f-umDuT80Qrn4jzDuP_0000 Date: Sun, 3 Mar 2024 17:27:08 +0800 Subject: [PATCH 112/153] Added ActionTo Text Input Field, Changed color for labels --- src/main/java/dude/Dude.java | 114 +++++-------------------- src/main/java/dude/Main.java | 1 + src/main/java/dude/MainView.java | 10 ++- src/main/resources/view/DialogBox.fxml | 8 +- src/main/resources/view/MainView.fxml | 20 ++--- 5 files changed, 45 insertions(+), 108 deletions(-) diff --git a/src/main/java/dude/Dude.java b/src/main/java/dude/Dude.java index ad4378b567..9ec639d019 100644 --- a/src/main/java/dude/Dude.java +++ b/src/main/java/dude/Dude.java @@ -1,5 +1,6 @@ package dude; +import java.io.IOException; import java.util.NoSuchElementException; import java.util.Scanner; @@ -32,11 +33,11 @@ * The main loop of the application is responsible for reading user input, * parsing it into a command, executing the command and saving the task list to disk. **/ -public class Dude extends Application { +public class Dude { private final TaskList taskList; private final Storage storage; - private final Ui ui; + private final Ui ui; private boolean isRunning = true; /** @@ -55,7 +56,7 @@ public Dude(String filePath) { try { temp = this.storage.loadTasks(); } catch (Exception e) { //Thrown when file gets corrupted - ui.showMessage("An error occurred while loading the tasks. Deleting the storage and starting with " + System.out.println("An error occurred while loading the tasks. Deleting the storage and starting with " + "an empty task list."); this.storage.deleteStorage(); temp = new TaskList(); @@ -64,6 +65,17 @@ public Dude(String filePath) { this.taskList = temp; } + public String getResponse(String input) { + Command c = Parser.parse(input, taskList); + String response = executeCommand(c); + try { + saveToDisk(); + } catch (IOException e) { + return "An error occurred while saving the tasks to disk."; + } + return response; + } + /** * This method runs the main loop of the application. *

@@ -81,7 +93,11 @@ public void run() { String response = executeCommand(command); ui.showMessage(response); - saveToDisk(); + try { + saveToDisk(); + } catch (IOException e) { + System.out.println("An error occurred while saving the tasks to disk."); + } if (command.getCommandType() == CommandTypes.BYE) { this.isRunning = false; @@ -108,94 +124,8 @@ private static String executeCommand(Command command) { } } - private void saveToDisk() { - try { - this.storage.saveTasks(taskList); - } catch (Exception e) { - this.ui.showMessage("An error occurred while saving the tasks."); - } - } - - public Dude() { - this("data/tasks.txt"); - } - - @Override - public void start(Stage stage) { - - - Label label = new Label("Hello Boii"); - - ScrollPane scrollPane = new ScrollPane(); - VBox container = new VBox(); - - scrollPane.setContent(container); - - Button sendButton = new Button("Send"); - TextField textField = new TextField(); - - AnchorPane mainLayout = new AnchorPane(); - mainLayout.getChildren().addAll(label, scrollPane, textField, sendButton); - - - Scene scene = new Scene(mainLayout); - - stage.setTitle("Duke"); - stage.setResizable(false); - stage.setMinHeight(600.0); - stage.setMinWidth(440); - - scrollPane.setPrefSize(420, 535); - scrollPane.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); - scrollPane.setVbarPolicy(ScrollPane.ScrollBarPolicy.ALWAYS); - - scrollPane.setVvalue(1.0); - scrollPane.setFitToWidth(true); - - textField.setPrefWidth(300); - sendButton.setPrefWidth(100); - - AnchorPane.setTopAnchor(scrollPane, 1.0); - AnchorPane.setLeftAnchor(scrollPane, 1.0); - - AnchorPane.setBottomAnchor(sendButton, 10.0); - AnchorPane.setRightAnchor(sendButton, 5.0); - - AnchorPane.setBottomAnchor(textField, 10.0); - AnchorPane.setLeftAnchor(textField, 5.0); - - container.setPrefHeight(Region.USE_COMPUTED_SIZE); - - sendButton.setOnMouseClicked(e -> { - String input = textField.getText(); - container.getChildren().add(getUserMessageView(input)); - textField.clear(); - }); - - textField.setOnAction(e -> { - String input = textField.getText(); - container.getChildren().add(getUserMessageView(input)); - textField.clear(); - }); - - mainLayout.setPrefSize(420, 600.0); - - container.heightProperty().addListener((observable) -> { - scrollPane.setVvalue(1.0); - }); - - stage.setScene(scene); // Setting the stage to show our screen - stage.show(); // Render the stage. + private void saveToDisk() throws IOException, SecurityException { + this.storage.saveTasks(taskList); } - - private static Label getUserMessageView(String message) { - System.out.println("User: " + message); - Label label = new Label(message); - label.setWrapText(true); - label.setMinHeight(Region.USE_PREF_SIZE); - label.setPrefWidth(Region.USE_COMPUTED_SIZE); - label.getStyleClass().add("dialog-label"); - return label; - } } diff --git a/src/main/java/dude/Main.java b/src/main/java/dude/Main.java index 2c960d5e5d..7baf14ade9 100644 --- a/src/main/java/dude/Main.java +++ b/src/main/java/dude/Main.java @@ -13,6 +13,7 @@ public class Main extends Application { @Override public void start(Stage stage) { stage.setTitle("Dude"); + stage.setResizable(false); FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("/view/MainView.fxml")); AnchorPane anchorPane = null; diff --git a/src/main/java/dude/MainView.java b/src/main/java/dude/MainView.java index db1cbc86b7..ac95d82d3b 100644 --- a/src/main/java/dude/MainView.java +++ b/src/main/java/dude/MainView.java @@ -27,15 +27,17 @@ public class MainView extends AnchorPane { private Image userImage = new Image(this.getClass().getResourceAsStream("/images/user.png")); private Image dudeImage = new Image(this.getClass().getResourceAsStream("/images/dude.png")); + private Dude dude; + @FXML public void initialize() { - + dude = new Dude("data/tasks.ser"); } @FXML public void handleUserInput() { String input = userInputField.getText(); - String response = "Duke heard: " + input; + String response = dude.getResponse(input); System.out.println("User input: " + input); userInputField.clear(); @@ -49,6 +51,10 @@ public void handleUserInput() { scrollPane.setVvalue(1.0); }); + if (input.equals("bye")) { + System.exit(0); + } + } } diff --git a/src/main/resources/view/DialogBox.fxml b/src/main/resources/view/DialogBox.fxml index b52eb3fa9f..b07d5dbacc 100644 --- a/src/main/resources/view/DialogBox.fxml +++ b/src/main/resources/view/DialogBox.fxml @@ -6,12 +6,12 @@ + type="javafx.scene.layout.HBox" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1"> - - + - \ No newline at end of file + diff --git a/src/main/resources/view/MainView.fxml b/src/main/resources/view/MainView.fxml index fe4e058548..a9026fed66 100644 --- a/src/main/resources/view/MainView.fxml +++ b/src/main/resources/view/MainView.fxml @@ -12,22 +12,22 @@ style="-fx-background-color: #262626;" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1" fx:controller="dude.MainView"> - + - + - - From e68f6d561d29051981a2ac3042c6ed2704bb7476 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 17:27:35 +0800 Subject: [PATCH 113/153] Changed to string to return "No tasks in the list! :(" when empty --- src/main/java/dude/tasks/TaskList.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/dude/tasks/TaskList.java b/src/main/java/dude/tasks/TaskList.java index 4d2cb0b6e8..2adc34318d 100644 --- a/src/main/java/dude/tasks/TaskList.java +++ b/src/main/java/dude/tasks/TaskList.java @@ -157,6 +157,10 @@ public Task getTask(int taskID) throws IndexOutOfBoundsException { */ @Override public String toString() { + if (list.size() == 0) { + return "No tasks in the list! :("; + } + String result = ""; for (int i = 0; i < list.size(); i++) { //if it is the last task, do not add a new line From 5451acd067defea28a3c90f20a8b5e8ec9f5bac7 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 17:31:12 +0800 Subject: [PATCH 114/153] Fixed bug where label was not showing entire text --- src/main/resources/view/DialogBox.fxml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/view/DialogBox.fxml b/src/main/resources/view/DialogBox.fxml index b07d5dbacc..e09124ba30 100644 --- a/src/main/resources/view/DialogBox.fxml +++ b/src/main/resources/view/DialogBox.fxml @@ -8,7 +8,7 @@ - From a4688f039d366aee852f267fd3c57e2d362a7ed8 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 17:33:03 +0800 Subject: [PATCH 115/153] Changed DialogBox.fxml so that the text has some margin --- src/main/resources/view/DialogBox.fxml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/resources/view/DialogBox.fxml b/src/main/resources/view/DialogBox.fxml index e09124ba30..0f72df935e 100644 --- a/src/main/resources/view/DialogBox.fxml +++ b/src/main/resources/view/DialogBox.fxml @@ -8,7 +8,11 @@ - From 0b9c0103d32f42ecffb48af0cbc4064c13adc774 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 17:41:00 +0800 Subject: [PATCH 116/153] bug fix --- src/main/resources/view/DialogBox.fxml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/resources/view/DialogBox.fxml b/src/main/resources/view/DialogBox.fxml index 0f72df935e..5b7a5e0558 100644 --- a/src/main/resources/view/DialogBox.fxml +++ b/src/main/resources/view/DialogBox.fxml @@ -10,10 +10,14 @@ - + + + + + From 5d1649a19ad457aa7bb378d4e0e42aea0f09d0a4 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 17:42:50 +0800 Subject: [PATCH 117/153] cleaned imports --- src/main/java/dude/Dude.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/main/java/dude/Dude.java b/src/main/java/dude/Dude.java index 9ec639d019..a76bf44682 100644 --- a/src/main/java/dude/Dude.java +++ b/src/main/java/dude/Dude.java @@ -4,8 +4,6 @@ import java.util.NoSuchElementException; import java.util.Scanner; -import javafx.application.Application; - import dude.commands.Command; import dude.commands.CommandTypes; import dude.commands.Parser; @@ -14,16 +12,6 @@ import dude.utils.Storage; import dude.utils.Ui; -import javafx.scene.Scene; -import javafx.scene.control.Button; -import javafx.scene.control.Label; -import javafx.scene.control.ScrollPane; -import javafx.scene.control.TextField; -import javafx.scene.layout.AnchorPane; -import javafx.scene.layout.Region; -import javafx.scene.layout.VBox; -import javafx.stage.Stage; - /** * The main class of the Duke application. From 934b16f8957503c25fc9e0d184d64ce4ab445919 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 17:47:51 +0800 Subject: [PATCH 118/153] Implmented var-args in TaskList --- src/main/java/dude/tasks/TaskList.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/dude/tasks/TaskList.java b/src/main/java/dude/tasks/TaskList.java index 2adc34318d..09f8da7dc1 100644 --- a/src/main/java/dude/tasks/TaskList.java +++ b/src/main/java/dude/tasks/TaskList.java @@ -32,6 +32,20 @@ public static TaskList from(ArrayList tasks) { return taskList; } + /** + * Static method to create a TaskList object from an arbitrary number of tasks. + * + * @param tasks Task objects to be put into a TaskList object. + * @return The TaskList object created from the Task objects. + */ + public static TaskList from(Task... tasks) { + TaskList taskList = new TaskList(); + for (Task task : tasks) { + taskList.list.add(task); + } + return taskList; + } + /** * Adds a task to the list of tasks. * From 2a51624857c5593c076d364b1959430755073b02 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 17:52:49 +0800 Subject: [PATCH 119/153] Added padding to dialog container --- src/main/resources/view/DialogBox.fxml | 2 +- src/main/resources/view/MainView.fxml | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/resources/view/DialogBox.fxml b/src/main/resources/view/DialogBox.fxml index 5b7a5e0558..bb4ca7aae8 100644 --- a/src/main/resources/view/DialogBox.fxml +++ b/src/main/resources/view/DialogBox.fxml @@ -5,7 +5,7 @@ -

- * This method is responsible for reading user input, parsing it into a command, - * executing the command and saving the task list to disk. - */ - public void run() { - - ui.showWelcome(); - Scanner sc = new Scanner(System.in); - while (this.isRunning) { - String input = extractInput(sc); - Command command = Parser.parse(input, taskList); - - String response = executeCommand(command); - ui.showMessage(response); - - try { - saveToDisk(); - } catch (IOException e) { - System.out.println("An error occurred while saving the tasks to disk."); - } - - if (command.getCommandType() == CommandTypes.BYE) { - this.isRunning = false; - } - } - } - - private static String extractInput(Scanner sc) { - String input = ""; - try { - input = sc.nextLine(); - } catch (NoSuchElementException e) { - //this will not be handled. App will only exit at bye command. - input = ""; - } - return input; - } - private static String executeCommand(Command command) { try { return command.execute(); From a146d3bfed1fb8c147bcff3ff9d34636d43c58b5 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 22:38:28 +0800 Subject: [PATCH 129/153] Added more javadoc to dude.java --- src/main/java/dude/Dude.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/dude/Dude.java b/src/main/java/dude/Dude.java index 928acecda8..ba20e934db 100644 --- a/src/main/java/dude/Dude.java +++ b/src/main/java/dude/Dude.java @@ -25,8 +25,6 @@ public class Dude { private final TaskList taskList; private final Storage storage; - private boolean isRunning = true; - /** * Constructor for the Dude class. *

@@ -51,7 +49,13 @@ public Dude(String filePath) { this.taskList = temp; } - + /** + * The main method used to interact with dude. User input is passed to this method to execute the + * appropriate command and send back a response from dude. + *

+ * + * @param input The user input to be processed. + */ public String getResponse(String input) { Command c = Parser.parse(input, taskList); String response = executeCommand(c); From 6d134e004c2b47c03fd2d476494cfeb2977fe02a Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 22:53:25 +0800 Subject: [PATCH 130/153] Code style improvements for Dude.java --- src/main/java/dude/Dude.java | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/main/java/dude/Dude.java b/src/main/java/dude/Dude.java index ba20e934db..c4b7247251 100644 --- a/src/main/java/dude/Dude.java +++ b/src/main/java/dude/Dude.java @@ -1,16 +1,12 @@ package dude; import java.io.IOException; -import java.util.NoSuchElementException; -import java.util.Scanner; import dude.commands.Command; -import dude.commands.CommandTypes; import dude.commands.Parser; import dude.exceptions.DudeException; import dude.tasks.TaskList; import dude.utils.Storage; -import dude.utils.Ui; /** @@ -22,6 +18,9 @@ * parsing it into a command, executing the command and saving the task list to disk. **/ public class Dude { + private static final String STORAGE_LOADING_ERROR_MESSAGE = "An error occurred while loading the tasks. " + + "Deleting the storage and starting with an empty task list."; + private static final String STORAGE_SAVING_ERROR_MESSAGE = "An error occurred while saving the tasks to disk."; private final TaskList taskList; private final Storage storage; @@ -35,18 +34,7 @@ public class Dude { */ public Dude(String filePath) { this.storage = new Storage(filePath); - - TaskList temp = null; - try { - temp = this.storage.loadTasks(); - } catch (Exception e) { //Thrown when file gets corrupted - System.out.println("An error occurred while loading the tasks. Deleting the storage and starting with " - + "an empty task list."); - this.storage.deleteStorage(); - temp = new TaskList(); - } - - this.taskList = temp; + this.taskList = loadTaskList(); } /** @@ -62,7 +50,7 @@ public String getResponse(String input) { try { saveToDisk(); } catch (IOException e) { - return "An error occurred while saving the tasks to disk."; + return STORAGE_SAVING_ERROR_MESSAGE; } return response; } @@ -79,4 +67,16 @@ private void saveToDisk() throws IOException, SecurityException { this.storage.saveTasks(taskList); } + private TaskList loadTaskList() { + TaskList temp; + try { + temp = this.storage.loadTasks(); + } catch (Exception e) { //Thrown when file gets corrupted + System.out.println(STORAGE_LOADING_ERROR_MESSAGE); + this.storage.deleteStorage(); + temp = new TaskList(); + } + return temp; + } + } From 8f5c70725eb0cd4b7910e06ef62756df6e0ffbd6 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 22:55:21 +0800 Subject: [PATCH 131/153] Added javaDoc for main.start() --- src/main/java/dude/Main.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/dude/Main.java b/src/main/java/dude/Main.java index 21978be0a8..d8d67e64b1 100644 --- a/src/main/java/dude/Main.java +++ b/src/main/java/dude/Main.java @@ -13,6 +13,11 @@ */ public class Main extends Application { + /** + * Method caled to start the application. It initializes the UI and sets up the javafx stage + * + * @param stage The stage to be used for the application. + */ @Override public void start(Stage stage) { stage.setTitle("Dude"); From c33f9e7ecccf2f1fe39178cc11571de5abac4d91 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 23:22:58 +0800 Subject: [PATCH 132/153] better code quality for Task package --- src/main/java/dude/tasks/Deadline.java | 70 +++++++++++--------- src/main/java/dude/tasks/Event.java | 89 ++++++++++++++++---------- src/main/java/dude/tasks/Task.java | 7 +- src/main/java/dude/tasks/TaskList.java | 2 +- src/main/java/dude/tasks/Todo.java | 9 +-- 5 files changed, 104 insertions(+), 73 deletions(-) diff --git a/src/main/java/dude/tasks/Deadline.java b/src/main/java/dude/tasks/Deadline.java index d7fd61be79..7200372bfe 100644 --- a/src/main/java/dude/tasks/Deadline.java +++ b/src/main/java/dude/tasks/Deadline.java @@ -39,33 +39,29 @@ public Deadline(String description, LocalDateTime by) { */ public static Deadline from(String s) throws InvalidFormatException, InvalidDescriptionException, InvalidArgumentException { - //Expects a string in the format "deadline /by " - - //get rid of the command String rest = Utils.discardFirstWord(s.trim()).trim(); - String[] arr = rest.split(" "); - int byOccurences = Utils.countOccurrences(arr, "/by"); + validateBy(arr); + int byIndex = Utils.findIndex(arr, "/by"); - if (byOccurences == 0 || byOccurences > 1) { - throw new InvalidFormatException("deadline", "format: deadline /by . " - + "Provide one and only one '/by'."); - } + String description = extractDescription(byIndex, arr); + String by = extractBy(byIndex, arr); + LocalDateTime dt = extractDateFromString(by); - //they will not be -1 as I have already checked for their occurences - int byIndex = Utils.findIndex(arr, "/by"); + return new Deadline(description, dt); + } - //description is from 0 to byIndex - String description = ""; - for (int i = 0; i < byIndex; i++) { - description += arr[i] + " "; - } - description = description.trim(); - if (description.isEmpty()) { - throw new InvalidDescriptionException("The description of a deadline cannot be empty."); - } + /** + * Returns the deadline of the Deadline object. + * + * @return The deadline date-time of the Deadline object. + */ + public LocalDateTime extractBy() { + return deadlineDate; + } + private static String extractBy(int byIndex, String[] arr) throws InvalidArgumentException { String by = ""; for (int i = byIndex + 1; i < arr.length; i++) { by += arr[i] + " "; @@ -75,25 +71,41 @@ public static Deadline from(String s) throws InvalidFormatException, throw new InvalidArgumentException("The 'by' of a deadline cannot be empty. " + "Follow this format: deadline /by "); } + return by; + } + private static LocalDateTime extractDateFromString(String by) throws InvalidFormatException { try { LocalDateTime dt = parseDate(by); - return new Deadline(description, dt); + return dt; } catch (DateTimeParseException e) { throw new InvalidFormatException("Invalid date format after '/by'. " + "Use d/M/yyyy or d/M/yyy H:m in 24-hour format"); } } - /** - * Returns the deadline of the Deadline object. - * - * @return The deadline date-time of the Deadline object. - */ - public LocalDateTime getBy() { - return deadlineDate; + private static String extractDescription(int byIndex, String[] arr) throws InvalidDescriptionException { + String description = ""; + for (int i = 0; i < byIndex; i++) { + description += arr[i] + " "; + } + + description = description.trim(); + if (description.isEmpty()) { + throw new InvalidDescriptionException("The description of a deadline cannot be empty."); + } + return description; + } + + private static void validateBy(String[] arr) throws InvalidFormatException { + int byOccurences = Utils.countOccurrences(arr, "/by"); + if (byOccurences == 0 || byOccurences > 1) { + throw new InvalidFormatException("deadline", "format: deadline /by . " + + "Provide one and only one '/by'."); + } } + /** * Returns a string representation of the Deadline object. * @@ -114,7 +126,7 @@ public String toString() { public boolean equals(Object object) { if (object instanceof Deadline) { Deadline t = (Deadline) object; - return t.getDescription().equals(this.getDescription()) && t.getBy().equals(this.getBy()); + return t.getDescription().equals(this.getDescription()) && t.extractBy().equals(this.extractBy()); } return false; } diff --git a/src/main/java/dude/tasks/Event.java b/src/main/java/dude/tasks/Event.java index 5462eee6ae..4ff576e445 100644 --- a/src/main/java/dude/tasks/Event.java +++ b/src/main/java/dude/tasks/Event.java @@ -47,61 +47,82 @@ public static Event from(String input) throws InvalidArgumentException, String rest = Utils.discardFirstWord(input.trim()).trim(); String[] arr = rest.split(" "); - int fromOccurrences = Utils.countOccurrences(arr, "/from"); - if (fromOccurrences == 0 || fromOccurrences > 1) { - throw new InvalidFormatException("Invalid format. Follow this format :" + EventCommand.COMMAND_FORMAT - + ". Provide one and only one '/from'."); - } + validateKeywordOccurences(arr); - int toOccurrences = Utils.countOccurrences(arr, "/to"); - if (toOccurrences == 0 || toOccurrences > 1) { - throw new InvalidFormatException("Invalid format. Follow this format: " + EventCommand.COMMAND_FORMAT - + ". Provide one and only one '/to'."); - } - - //they will not be -1 as I have already checked for their occurences int fromIndex = Utils.findIndex(arr, "/from"); int toIndex = Utils.findIndex(arr, "/to"); - if (fromIndex > toIndex) { throw new InvalidFormatException("The 'from time' of an event cannot be after the 'to time'."); } - //description is from 0 to fromIndex - String description = ""; - for (int i = 0; i < fromIndex; i++) { - description += arr[i] + " "; + String description = extractDescription(fromIndex, arr); + String fromTime = extractFromString(fromIndex, toIndex, arr); + String toTime = extractToTimeString(toIndex, arr); + + Event event = getEvent(fromTime, toTime, description); + return event; + } + + private static Event getEvent(String fromTime, String toTime, String description) throws InvalidFormatException { + Event event = null; + try { + LocalDateTime from = parseDate(fromTime); + LocalDateTime to = parseDate(toTime); + event = new Event(description, from, to); + } catch (DateTimeParseException e) { + throw new InvalidFormatException("Invalid date format after '/from' or '/to'." + + "Use d/M/yyyy or d/M/yyy H:m in 24-hour format"); } - description = description.trim(); - if (description.isEmpty()) { - throw new InvalidDescriptionException("The description of an event cannot be empty."); + return event; + } + + private static String extractToTimeString(int toIndex, String[] arr) throws InvalidArgumentException { + String toTime = ""; + for (int i = toIndex + 1; i < arr.length; i++) { + toTime += arr[i] + " "; } + toTime = toTime.trim(); + if (toTime.isEmpty()) { + throw new InvalidArgumentException("The '/to' of an event cannot be empty."); + } + return toTime; + } + private static String extractFromString(int fromIndex, int toIndex, String[] arr) throws InvalidArgumentException { String fromTime = ""; for (int i = fromIndex + 1; i < toIndex; i++) { fromTime += arr[i] + " "; } fromTime = fromTime.trim(); if (fromTime.isEmpty()) { - throw new InvalidArgumentException("The 'fromTime' of an event cannot be empty."); + throw new InvalidArgumentException("The '/from' of an event cannot be empty."); } + return fromTime; + } - String toTime = ""; - for (int i = toIndex + 1; i < arr.length; i++) { - toTime += arr[i] + " "; + private static String extractDescription(int fromIndex, String[] arr) throws InvalidDescriptionException { + String description = ""; + for (int i = 0; i < fromIndex; i++) { + description += arr[i] + " "; } - toTime = toTime.trim(); - if (toTime.isEmpty()) { - throw new InvalidArgumentException("The 'toTime' of an event cannot be empty."); + description = description.trim(); + if (description.isEmpty()) { + throw new InvalidDescriptionException("The description of an event cannot be empty."); } + return description; + } - try { - LocalDateTime from = parseDate(fromTime); - LocalDateTime to = parseDate(toTime); - return new Event(description, from, to); - } catch (DateTimeParseException e) { - throw new InvalidFormatException("Invalid date format after '/from' or '/to'." - + "Use d/M/yyyy or d/M/yyy H:m in 24-hour format"); + private static void validateKeywordOccurences(String[] arr) throws InvalidFormatException { + int fromOccurrences = Utils.countOccurrences(arr, "/from"); + if (fromOccurrences == 0 || fromOccurrences > 1) { + throw new InvalidFormatException("Invalid format. Follow this format :" + EventCommand.COMMAND_FORMAT + + ". Provide one and only one '/from'."); + } + + int toOccurrences = Utils.countOccurrences(arr, "/to"); + if (toOccurrences == 0 || toOccurrences > 1) { + throw new InvalidFormatException("Invalid format. Follow this format: " + EventCommand.COMMAND_FORMAT + + ". Provide one and only one '/to'."); } } diff --git a/src/main/java/dude/tasks/Task.java b/src/main/java/dude/tasks/Task.java index 7a300b6aa7..fd9f175006 100644 --- a/src/main/java/dude/tasks/Task.java +++ b/src/main/java/dude/tasks/Task.java @@ -10,6 +10,8 @@ * The Task class represents a task with a description and a status. */ public class Task implements Serializable { + private static final String DATE_TIME_FORMAT = "d/M/yyyy H:m"; + private static final String DATE_FORMAT = "d/M/yyyy"; private final String description; private boolean isDone; @@ -73,12 +75,11 @@ protected static LocalDateTime parseDate(String string) throws DateTimeParseExce String dateTimePattern = "\\d{1,2}/\\d{1,2}/\\d{4} \\d{1,2}:\\d{2}"; String datePattern = "\\d{1,2}/\\d{1,2}/\\d{4}"; - if (string.matches(dateTimePattern)) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/yyyy H:m"); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_TIME_FORMAT); return LocalDateTime.parse(string, formatter); } else if (string.matches(datePattern)) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/yyyy"); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_FORMAT); LocalDate date = LocalDate.parse(string, formatter); return date.atStartOfDay(); } else { diff --git a/src/main/java/dude/tasks/TaskList.java b/src/main/java/dude/tasks/TaskList.java index 09f8da7dc1..2d45ad1465 100644 --- a/src/main/java/dude/tasks/TaskList.java +++ b/src/main/java/dude/tasks/TaskList.java @@ -128,7 +128,7 @@ public ArrayList getList() { ArrayList copy = new ArrayList<>(); for (Task task : list) { if (task instanceof Deadline) { - copy.add(new Deadline(task.getDescription(), ((Deadline) task).getBy())); + copy.add(new Deadline(task.getDescription(), ((Deadline) task).extractBy())); } else if (task instanceof Event) { copy.add(new Event(task.getDescription(), ((Event) task).getFromTime(), ((Event) task).getToTime())); } else if (task instanceof Todo) { diff --git a/src/main/java/dude/tasks/Todo.java b/src/main/java/dude/tasks/Todo.java index 95bf026603..e2e01d7aa5 100644 --- a/src/main/java/dude/tasks/Todo.java +++ b/src/main/java/dude/tasks/Todo.java @@ -26,15 +26,12 @@ public Todo(String description) { * @throws InvalidDescriptionException if the description of the todo is empty. */ public static Todo from(String s) throws InvalidDescriptionException { - - //get rid of the command String description = Utils.discardFirstWord(s.trim()).trim(); - - if (!description.isEmpty()) { - return new Todo(description); - } else { + if (description.isEmpty()) { throw new InvalidDescriptionException("The description of a todo cannot be empty."); } + + return new Todo(description); } /** From 0696e645fcc2fb4d3b1ac3ae898ee6fa1ceb13c3 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 23:27:48 +0800 Subject: [PATCH 133/153] better code quality for Task package --- src/main/java/dude/tasks/Deadline.java | 8 ++++---- src/main/java/dude/tasks/TaskList.java | 8 +++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/dude/tasks/Deadline.java b/src/main/java/dude/tasks/Deadline.java index 7200372bfe..9b0a35cf1d 100644 --- a/src/main/java/dude/tasks/Deadline.java +++ b/src/main/java/dude/tasks/Deadline.java @@ -46,7 +46,7 @@ public static Deadline from(String s) throws InvalidFormatException, int byIndex = Utils.findIndex(arr, "/by"); String description = extractDescription(byIndex, arr); - String by = extractBy(byIndex, arr); + String by = extractByString(byIndex, arr); LocalDateTime dt = extractDateFromString(by); return new Deadline(description, dt); @@ -57,11 +57,11 @@ public static Deadline from(String s) throws InvalidFormatException, * * @return The deadline date-time of the Deadline object. */ - public LocalDateTime extractBy() { + public LocalDateTime getByTime() { return deadlineDate; } - private static String extractBy(int byIndex, String[] arr) throws InvalidArgumentException { + private static String extractByString(int byIndex, String[] arr) throws InvalidArgumentException { String by = ""; for (int i = byIndex + 1; i < arr.length; i++) { by += arr[i] + " "; @@ -126,7 +126,7 @@ public String toString() { public boolean equals(Object object) { if (object instanceof Deadline) { Deadline t = (Deadline) object; - return t.getDescription().equals(this.getDescription()) && t.extractBy().equals(this.extractBy()); + return t.getDescription().equals(this.getDescription()) && t.getByTime().equals(this.getByTime()); } return false; } diff --git a/src/main/java/dude/tasks/TaskList.java b/src/main/java/dude/tasks/TaskList.java index 2d45ad1465..fa0a9fe257 100644 --- a/src/main/java/dude/tasks/TaskList.java +++ b/src/main/java/dude/tasks/TaskList.java @@ -128,9 +128,11 @@ public ArrayList getList() { ArrayList copy = new ArrayList<>(); for (Task task : list) { if (task instanceof Deadline) { - copy.add(new Deadline(task.getDescription(), ((Deadline) task).extractBy())); + Deadline deadline = (Deadline) task; + copy.add(new Deadline(deadline.getDescription(), deadline.getByTime())); } else if (task instanceof Event) { - copy.add(new Event(task.getDescription(), ((Event) task).getFromTime(), ((Event) task).getToTime())); + Event event = (Event) task; + copy.add(new Event(event.getDescription(), event.getFromTime(), event.getToTime())); } else if (task instanceof Todo) { copy.add(new Todo(task.getDescription())); } else { @@ -171,7 +173,7 @@ public Task getTask(int taskID) throws IndexOutOfBoundsException { */ @Override public String toString() { - if (list.size() == 0) { + if (list.isEmpty()) { return "No tasks in the list! :("; } From 04323f7713c23aaa70b050017cf15f02c5ef51e9 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 23:28:48 +0800 Subject: [PATCH 134/153] fixed some checkstyle errors --- src/main/java/dude/Launcher.java | 2 +- src/main/java/dude/Main.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/dude/Launcher.java b/src/main/java/dude/Launcher.java index 37715ff866..ec85912d2e 100644 --- a/src/main/java/dude/Launcher.java +++ b/src/main/java/dude/Launcher.java @@ -15,4 +15,4 @@ public class Launcher { public static void main(String[] args) { Application.launch(Main.class, args); } -} \ No newline at end of file +} diff --git a/src/main/java/dude/Main.java b/src/main/java/dude/Main.java index d8d67e64b1..1ae8e5c750 100644 --- a/src/main/java/dude/Main.java +++ b/src/main/java/dude/Main.java @@ -1,13 +1,13 @@ package dude; +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 java.io.IOException; - /** * The Main class is used to boot up the GUI for the application. */ From c6fbb9bd206aa8748c8c9e3c5d24b73cfa8c58ba Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 23:42:44 +0800 Subject: [PATCH 135/153] Better code quality --- src/main/java/dude/gui/DialogBox.java | 12 ++++---- src/main/java/dude/gui/MainView.java | 40 +++++++++++++++++---------- 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/main/java/dude/gui/DialogBox.java b/src/main/java/dude/gui/DialogBox.java index fbd4d073e3..ced2c26221 100644 --- a/src/main/java/dude/gui/DialogBox.java +++ b/src/main/java/dude/gui/DialogBox.java @@ -1,25 +1,27 @@ package dude.gui; -import javafx.scene.control.Label; -import javafx.scene.layout.HBox; -import javafx.fxml.FXML; import java.io.IOException; import java.util.Collections; import javafx.collections.FXCollections; import javafx.collections.ObservableList; - +import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.geometry.Pos; import javafx.scene.Node; import javafx.scene.image.Image; import javafx.scene.image.ImageView; +// @@author Jeffry Lum +// Solution below is reused from https://se-education.org/guides/tutorials/javaFxPart4.html + /** - * An example of a custom control using FXML. * This control represents a dialog box consisting of an ImageView to represent the speaker's face and a label * containing text from the speaker. + * */ public class DialogBox extends HBox { @FXML diff --git a/src/main/java/dude/gui/MainView.java b/src/main/java/dude/gui/MainView.java index 5dec1fac0f..867d361e77 100644 --- a/src/main/java/dude/gui/MainView.java +++ b/src/main/java/dude/gui/MainView.java @@ -13,6 +13,8 @@ * Controller for MainView. Provides the layout for the other controls. */ public class MainView extends AnchorPane { + private static final String USER_IMAGE_PATH = "/images/user.png"; + private static final String DUDE_IMAGE_PATH = "/images/dude.png"; @FXML private ScrollPane scrollPane; @@ -25,37 +27,47 @@ public class MainView extends AnchorPane { @FXML private VBox dialogContainer; - private Image userImage = new Image(this.getClass().getResourceAsStream("/images/user.png")); - private Image dudeImage = new Image(this.getClass().getResourceAsStream("/images/dude.png")); - + private Image userImage; + private Image dudeImage; private Dude dude; @FXML public void initialize() { - dude = new Dude("data/tasks.ser"); + this.dude = new Dude("data/tasks.ser"); + this.userImage = new Image(this.getClass().getResourceAsStream(USER_IMAGE_PATH)); + this.dudeImage = new Image(this.getClass().getResourceAsStream(DUDE_IMAGE_PATH)); } + /** + * Creates two dialog boxes, one echoing user input and the other containing Dude's reply and then appends them to + * the dialog container. Clears the user input after processing. + */ @FXML public void handleUserInput() { String input = userInputField.getText(); - String response = dude.getResponse(input); + if (input.equals("bye")) { + System.exit(0); + } - System.out.println("User input: " + input); + String response = dude.getResponse(input); + ; userInputField.clear(); - dialogContainer.getChildren().addAll( - DialogBox.getUserDialog(input, userImage), - DialogBox.getDukeDialog(response, dudeImage) - ); + showInputAndResponse(input, response); + scrollDown(); + } + private void scrollDown() { dialogContainer.heightProperty().addListener((observable) -> { scrollPane.setVvalue(1.0); }); + } - if (input.equals("bye")) { - System.exit(0); - } - + private void showInputAndResponse(String input, String response) { + dialogContainer.getChildren().addAll( + DialogBox.getUserDialog(input, userImage), + DialogBox.getDukeDialog(response, dudeImage) + ); } } From 1066bae306e67542f6a1305a7a507bff0c0e00ce Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 23:47:12 +0800 Subject: [PATCH 136/153] Better code quality --- src/main/java/dude/Dude.java | 4 ++-- src/main/java/dude/gui/DialogBox.java | 4 ++-- src/main/java/dude/gui/MainView.java | 3 +++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/dude/Dude.java b/src/main/java/dude/Dude.java index c4b7247251..8b28f385de 100644 --- a/src/main/java/dude/Dude.java +++ b/src/main/java/dude/Dude.java @@ -48,7 +48,7 @@ public String getResponse(String input) { Command c = Parser.parse(input, taskList); String response = executeCommand(c); try { - saveToDisk(); + saveTaskListToDisk(); } catch (IOException e) { return STORAGE_SAVING_ERROR_MESSAGE; } @@ -63,7 +63,7 @@ private static String executeCommand(Command command) { } } - private void saveToDisk() throws IOException, SecurityException { + private void saveTaskListToDisk() throws IOException, SecurityException { this.storage.saveTasks(taskList); } diff --git a/src/main/java/dude/gui/DialogBox.java b/src/main/java/dude/gui/DialogBox.java index ced2c26221..d0147e4700 100644 --- a/src/main/java/dude/gui/DialogBox.java +++ b/src/main/java/dude/gui/DialogBox.java @@ -6,14 +6,14 @@ import javafx.collections.FXCollections; import javafx.collections.ObservableList; -import javafx.scene.control.Label; -import javafx.scene.layout.HBox; 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; // @@author Jeffry Lum // Solution below is reused from https://se-education.org/guides/tutorials/javaFxPart4.html diff --git a/src/main/java/dude/gui/MainView.java b/src/main/java/dude/gui/MainView.java index 867d361e77..3508e85e0f 100644 --- a/src/main/java/dude/gui/MainView.java +++ b/src/main/java/dude/gui/MainView.java @@ -31,6 +31,9 @@ public class MainView extends AnchorPane { private Image dudeImage; private Dude dude; + /** + * Initializes the MainView, setting up the images and the Dude object. + */ @FXML public void initialize() { this.dude = new Dude("data/tasks.ser"); From 10f22e5539008a51a7728f17e84a9099c087e4d2 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 21:18:44 +0800 Subject: [PATCH 137/153] Added Assertions to Commands. There were no assertions in the Commands that were being implemented in dude. Especially the constructors, where many of the constructions were assuming certain conditions to hold true. Conditions that the command class sub-class constructors assumed to be true: * String input : Assumed to be not null, assumed to contain appropriate command * Tasklist tasklist: Assumed to be not null Now assertions have been added to the constructors to make sure such conditions are actually holding true. These assertions will help to reduce bugs making sure the conditions assumed to be true, actually hold true. I believe this will drastically reduce bugs when I decide to add on more features. --- src/main/java/dude/commands/DeadlineCommand.java | 6 ++++++ src/main/java/dude/commands/DeleteCommand.java | 5 +++++ src/main/java/dude/commands/EventCommand.java | 6 ++++++ src/main/java/dude/commands/FindCommand.java | 5 +++++ src/main/java/dude/commands/HelpCommand.java | 4 ++++ src/main/java/dude/commands/InvalidCommand.java | 4 ++-- src/main/java/dude/commands/ListCommand.java | 3 +++ src/main/java/dude/commands/MarkCommand.java | 5 +++++ src/main/java/dude/commands/Parser.java | 3 +++ src/main/java/dude/commands/TodoCommand.java | 5 +++++ src/main/java/dude/commands/UnmarkCommand.java | 5 +++++ 11 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/main/java/dude/commands/DeadlineCommand.java b/src/main/java/dude/commands/DeadlineCommand.java index c3a14f6e5d..d85d16c8f1 100644 --- a/src/main/java/dude/commands/DeadlineCommand.java +++ b/src/main/java/dude/commands/DeadlineCommand.java @@ -18,11 +18,17 @@ public class DeadlineCommand extends Command { * Constructor for the DeadlineCommand class. Returns a command object to add a deadline task to * the TaskList object upon execution. * + * * @param input The input string that resulted in the creation of this command. * @param tasklist The TaskList object to which the deadline task is to be added. */ public DeadlineCommand(String input, TaskList tasklist) { super(COMMAND_FORMAT, "deadline .* /by .*"); + + assert(input != null); + assert(tasklist != null); + assert(input.contains("deadline")); + this.input = input; this.taskList = tasklist; } diff --git a/src/main/java/dude/commands/DeleteCommand.java b/src/main/java/dude/commands/DeleteCommand.java index d8c1b95404..5d01dd8f33 100644 --- a/src/main/java/dude/commands/DeleteCommand.java +++ b/src/main/java/dude/commands/DeleteCommand.java @@ -24,6 +24,11 @@ public class DeleteCommand extends Command { */ public DeleteCommand(String input, TaskList tasklist) { super(COMMAND_FORMAT, "delete \\d+"); + + assert(input != null); + assert(tasklist != null); + assert(input.contains("delete")); + this.input = input.trim(); this.taskList = tasklist; } diff --git a/src/main/java/dude/commands/EventCommand.java b/src/main/java/dude/commands/EventCommand.java index 19b83e06e7..b452917cf0 100644 --- a/src/main/java/dude/commands/EventCommand.java +++ b/src/main/java/dude/commands/EventCommand.java @@ -24,6 +24,12 @@ public class EventCommand extends Command { */ public EventCommand(String input, TaskList tasklist) { super(COMMAND_FORMAT, "event .* /from .* /to .*"); + + assert(input != null); + assert(tasklist != null); + assert(input.contains("event")); + + this.input = input; this.taskList = tasklist; } diff --git a/src/main/java/dude/commands/FindCommand.java b/src/main/java/dude/commands/FindCommand.java index 688448f0b6..377624dca0 100644 --- a/src/main/java/dude/commands/FindCommand.java +++ b/src/main/java/dude/commands/FindCommand.java @@ -25,6 +25,11 @@ public class FindCommand extends Command { */ public FindCommand(String input, TaskList taskList) { super(COMMAND_FORMAT, "find .*"); + + assert(input != null); + assert(taskList != null); + assert(input.contains("find")); + this.input = input; this.taskList = taskList; } diff --git a/src/main/java/dude/commands/HelpCommand.java b/src/main/java/dude/commands/HelpCommand.java index 2ecac746e8..16025d55b7 100644 --- a/src/main/java/dude/commands/HelpCommand.java +++ b/src/main/java/dude/commands/HelpCommand.java @@ -32,6 +32,10 @@ public class HelpCommand extends Command { */ public HelpCommand(String input) { super("help ", "help"); + + assert(input != null); + assert(input.contains("help")); + this.input = input.trim(); } diff --git a/src/main/java/dude/commands/InvalidCommand.java b/src/main/java/dude/commands/InvalidCommand.java index e4cbdeeda7..9d52295c62 100644 --- a/src/main/java/dude/commands/InvalidCommand.java +++ b/src/main/java/dude/commands/InvalidCommand.java @@ -1,7 +1,7 @@ package dude.commands; /** - * The InvalidCommand class represents a command that is invalid. + * The InvalidCommand Class is used to wrap around any invalid commands that are input by the user. */ public class InvalidCommand extends Command { @@ -15,7 +15,7 @@ public InvalidCommand() { /** * Does nothing * - * @return The string message for an invalid command. + * @return The string message for trying to execute an invalid command. */ public String execute() { return "Sorry I don't understand that command. Please try again."; diff --git a/src/main/java/dude/commands/ListCommand.java b/src/main/java/dude/commands/ListCommand.java index 7c0adc63c8..4e1b881b49 100644 --- a/src/main/java/dude/commands/ListCommand.java +++ b/src/main/java/dude/commands/ListCommand.java @@ -19,6 +19,9 @@ public class ListCommand extends Command { */ public ListCommand(TaskList tasklist) { super("list", "list"); + + assert(tasklist != null); + this.tasklist = tasklist; } diff --git a/src/main/java/dude/commands/MarkCommand.java b/src/main/java/dude/commands/MarkCommand.java index 4c39c9fda3..f4888a5c13 100644 --- a/src/main/java/dude/commands/MarkCommand.java +++ b/src/main/java/dude/commands/MarkCommand.java @@ -23,6 +23,11 @@ public class MarkCommand extends Command { */ public MarkCommand(String input, TaskList tasklist) { super(COMMAND_FORMAT, "mark \\d+"); + + assert(input != null); + assert(tasklist != null); + assert(input.contains("mark")); + this.input = input.trim(); this.taskList = tasklist; } diff --git a/src/main/java/dude/commands/Parser.java b/src/main/java/dude/commands/Parser.java index 21a5eea025..03783487ce 100644 --- a/src/main/java/dude/commands/Parser.java +++ b/src/main/java/dude/commands/Parser.java @@ -15,6 +15,9 @@ public class Parser { * @return The parsed command from the user input. */ public static Command parse(String input, TaskList tasklist) { + assert(input != null); + assert(tasklist != null); + String[] command = input.split(" ", 2); switch (command[0]) { case "bye": diff --git a/src/main/java/dude/commands/TodoCommand.java b/src/main/java/dude/commands/TodoCommand.java index 6cb7e6b829..688acb12ff 100644 --- a/src/main/java/dude/commands/TodoCommand.java +++ b/src/main/java/dude/commands/TodoCommand.java @@ -23,6 +23,11 @@ public class TodoCommand extends Command { */ public TodoCommand(String input, TaskList tasklist) { super(COMMAND_FORMAT, "todo .*"); + + assert(input != null); + assert(tasklist != null); + assert(input.contains("todo")); + this.input = input; this.taskList = tasklist; } diff --git a/src/main/java/dude/commands/UnmarkCommand.java b/src/main/java/dude/commands/UnmarkCommand.java index c92e8e16fb..4154f2208a 100644 --- a/src/main/java/dude/commands/UnmarkCommand.java +++ b/src/main/java/dude/commands/UnmarkCommand.java @@ -23,6 +23,11 @@ public class UnmarkCommand extends Command { */ public UnmarkCommand(String input, TaskList tasklist) { super(COMMAND_FORMAT, "unmark \\d+"); + + assert(input != null); + assert(tasklist != null); + assert(input.contains("unmark")); + this.input = input.trim(); this.taskList = tasklist; } From 0efefffee2ccb8d113fd308b1e99e6e109081d8f Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 21:24:05 +0800 Subject: [PATCH 138/153] added assertions to constructors of tasks packages --- src/main/java/dude/tasks/Deadline.java | 8 +++++++- src/main/java/dude/tasks/Event.java | 6 ++++++ src/main/java/dude/tasks/Task.java | 1 + src/main/java/dude/tasks/TaskList.java | 6 ++++++ src/main/java/dude/tasks/Todo.java | 1 + 5 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/main/java/dude/tasks/Deadline.java b/src/main/java/dude/tasks/Deadline.java index d7fd61be79..e8a560035e 100644 --- a/src/main/java/dude/tasks/Deadline.java +++ b/src/main/java/dude/tasks/Deadline.java @@ -24,6 +24,11 @@ public class Deadline extends Task { */ public Deadline(String description, LocalDateTime by) { super(description); + + assert (by != null); + assert (description != null); + assert (!description.isEmpty()); + this.deadlineDate = by; } @@ -39,7 +44,8 @@ public Deadline(String description, LocalDateTime by) { */ public static Deadline from(String s) throws InvalidFormatException, InvalidDescriptionException, InvalidArgumentException { - //Expects a string in the format "deadline /by " + + assert (s != null); //get rid of the command String rest = Utils.discardFirstWord(s.trim()).trim(); diff --git a/src/main/java/dude/tasks/Event.java b/src/main/java/dude/tasks/Event.java index 5462eee6ae..5bece187aa 100644 --- a/src/main/java/dude/tasks/Event.java +++ b/src/main/java/dude/tasks/Event.java @@ -27,6 +27,12 @@ public class Event extends Task { */ public Event(String description, LocalDateTime fromTime, LocalDateTime toTime) { super(description); + + assert (fromTime != null); + assert (toTime != null); + assert (description != null); + assert (!description.isEmpty()); + this.fromTime = fromTime; this.toTime = toTime; } diff --git a/src/main/java/dude/tasks/Task.java b/src/main/java/dude/tasks/Task.java index 7a300b6aa7..77faaa47d4 100644 --- a/src/main/java/dude/tasks/Task.java +++ b/src/main/java/dude/tasks/Task.java @@ -19,6 +19,7 @@ public class Task implements Serializable { * @param description The description of the task. */ public Task(String description) { + assert (description != null); this.description = description; this.isDone = false; } diff --git a/src/main/java/dude/tasks/TaskList.java b/src/main/java/dude/tasks/TaskList.java index 09f8da7dc1..873bb276cc 100644 --- a/src/main/java/dude/tasks/TaskList.java +++ b/src/main/java/dude/tasks/TaskList.java @@ -27,6 +27,8 @@ public TaskList() { * @return The TaskList object created from the ArrayList of Task objects. */ public static TaskList from(ArrayList tasks) { + assert (tasks != null); + TaskList taskList = new TaskList(); taskList.list.addAll(tasks); return taskList; @@ -39,6 +41,8 @@ public static TaskList from(ArrayList tasks) { * @return The TaskList object created from the Task objects. */ public static TaskList from(Task... tasks) { + assert (tasks != null); + TaskList taskList = new TaskList(); for (Task task : tasks) { taskList.list.add(task); @@ -53,6 +57,7 @@ public static TaskList from(Task... tasks) { * @throws TaskListFullException if the task list is full. */ public void add_task(Task task) throws TaskListFullException { + assert (task != null); if (list.size() >= 100) { throw new TaskListFullException("Sorry, the task list is full."); } @@ -105,6 +110,7 @@ public void mark_as_undone(int id) throws DudeException { * @return An ArrayList of Task objects that contain the keyword. */ public ArrayList find(String keyword) { + assert (keyword != null); ArrayList result = new ArrayList<>(); String taskString; String keywordLowerCase = keyword.toLowerCase(); diff --git a/src/main/java/dude/tasks/Todo.java b/src/main/java/dude/tasks/Todo.java index 95bf026603..79f1d4a347 100644 --- a/src/main/java/dude/tasks/Todo.java +++ b/src/main/java/dude/tasks/Todo.java @@ -15,6 +15,7 @@ public class Todo extends Task { */ public Todo(String description) { super(description); + assert (description != null); } From d5f106fa2088b59e718431d124ff7b1dde0f5fa4 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 21:26:40 +0800 Subject: [PATCH 139/153] Added assertions to Storage.java public functions --- src/main/java/dude/utils/Storage.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/dude/utils/Storage.java b/src/main/java/dude/utils/Storage.java index d5bb065947..0d03ea398b 100644 --- a/src/main/java/dude/utils/Storage.java +++ b/src/main/java/dude/utils/Storage.java @@ -26,6 +26,8 @@ public class Storage { * @param fileLocation The file path to the storage file. */ public Storage(String fileLocation) { + assert (fileLocation != null); + this.filepath = extractFilePath(fileLocation); this.filename = extractFileName(fileLocation); } @@ -76,6 +78,7 @@ public void deleteStorage() throws SecurityException { * @throws SecurityException if a security manager exists and its checkWrite method denies write access to the file. */ public void saveTasks(TaskList taskList) throws IOException, SecurityException { + assert (taskList != null); try { FileOutputStream fos = new FileOutputStream(this.filepath + this.filename); ObjectOutputStream oos = new ObjectOutputStream(fos); From 3b13496c7772e7e562326244c69151e031a5d593 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 21:29:39 +0800 Subject: [PATCH 140/153] Added assertion to dsicardFirstWord method, modified javadoc for findIndex method. --- src/main/java/dude/utils/Utils.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/dude/utils/Utils.java b/src/main/java/dude/utils/Utils.java index a45d297260..14b0fcfa8b 100644 --- a/src/main/java/dude/utils/Utils.java +++ b/src/main/java/dude/utils/Utils.java @@ -15,6 +15,7 @@ public class Utils { * @return The input string with the first word discarded. */ public static String discardFirstWord(String input) { + assert (input != null); // Split the string by whitespace String[] words = input.split(" ", 2); // Check if there are at least two words @@ -49,7 +50,8 @@ public static int countOccurrences(String[] array, String target) { * * @param array The array of strings. * @param target The target string. - * @return The index of the first occurrence of the target string in the array. + * @return The index of the first occurrence of the target string in the array. If the target string is not found, + * -1 is returned. */ public static int findIndex(String[] array, String target) { for (int i = 0; i < array.length; i++) { From 15b7782611c41c52c9b61de2b1c1ebd86c30fa7c Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 23:22:58 +0800 Subject: [PATCH 141/153] better code quality for Task package --- src/main/java/dude/tasks/Deadline.java | 66 +++++++++++-------- src/main/java/dude/tasks/Event.java | 89 ++++++++++++++++---------- src/main/java/dude/tasks/Task.java | 7 +- src/main/java/dude/tasks/TaskList.java | 2 +- src/main/java/dude/tasks/Todo.java | 9 +-- 5 files changed, 104 insertions(+), 69 deletions(-) diff --git a/src/main/java/dude/tasks/Deadline.java b/src/main/java/dude/tasks/Deadline.java index e8a560035e..1a2c9924ab 100644 --- a/src/main/java/dude/tasks/Deadline.java +++ b/src/main/java/dude/tasks/Deadline.java @@ -52,26 +52,26 @@ public static Deadline from(String s) throws InvalidFormatException, String[] arr = rest.split(" "); - int byOccurences = Utils.countOccurrences(arr, "/by"); + validateBy(arr); + int byIndex = Utils.findIndex(arr, "/by"); - if (byOccurences == 0 || byOccurences > 1) { - throw new InvalidFormatException("deadline", "format: deadline /by . " - + "Provide one and only one '/by'."); - } + String description = extractDescription(byIndex, arr); + String by = extractBy(byIndex, arr); + LocalDateTime dt = extractDateFromString(by); - //they will not be -1 as I have already checked for their occurences - int byIndex = Utils.findIndex(arr, "/by"); + return new Deadline(description, dt); + } - //description is from 0 to byIndex - String description = ""; - for (int i = 0; i < byIndex; i++) { - description += arr[i] + " "; - } - description = description.trim(); - if (description.isEmpty()) { - throw new InvalidDescriptionException("The description of a deadline cannot be empty."); - } + /** + * Returns the deadline of the Deadline object. + * + * @return The deadline date-time of the Deadline object. + */ + public LocalDateTime extractBy() { + return deadlineDate; + } + private static String extractBy(int byIndex, String[] arr) throws InvalidArgumentException { String by = ""; for (int i = byIndex + 1; i < arr.length; i++) { by += arr[i] + " "; @@ -81,25 +81,41 @@ public static Deadline from(String s) throws InvalidFormatException, throw new InvalidArgumentException("The 'by' of a deadline cannot be empty. " + "Follow this format: deadline /by "); } + return by; + } + private static LocalDateTime extractDateFromString(String by) throws InvalidFormatException { try { LocalDateTime dt = parseDate(by); - return new Deadline(description, dt); + return dt; } catch (DateTimeParseException e) { throw new InvalidFormatException("Invalid date format after '/by'. " + "Use d/M/yyyy or d/M/yyy H:m in 24-hour format"); } } - /** - * Returns the deadline of the Deadline object. - * - * @return The deadline date-time of the Deadline object. - */ - public LocalDateTime getBy() { - return deadlineDate; + private static String extractDescription(int byIndex, String[] arr) throws InvalidDescriptionException { + String description = ""; + for (int i = 0; i < byIndex; i++) { + description += arr[i] + " "; + } + + description = description.trim(); + if (description.isEmpty()) { + throw new InvalidDescriptionException("The description of a deadline cannot be empty."); + } + return description; } + private static void validateBy(String[] arr) throws InvalidFormatException { + int byOccurences = Utils.countOccurrences(arr, "/by"); + if (byOccurences == 0 || byOccurences > 1) { + throw new InvalidFormatException("deadline", "format: deadline /by . " + + "Provide one and only one '/by'."); + } + } + + /** * Returns a string representation of the Deadline object. * @@ -120,7 +136,7 @@ public String toString() { public boolean equals(Object object) { if (object instanceof Deadline) { Deadline t = (Deadline) object; - return t.getDescription().equals(this.getDescription()) && t.getBy().equals(this.getBy()); + return t.getDescription().equals(this.getDescription()) && t.extractBy().equals(this.extractBy()); } return false; } diff --git a/src/main/java/dude/tasks/Event.java b/src/main/java/dude/tasks/Event.java index 5bece187aa..11249ccda2 100644 --- a/src/main/java/dude/tasks/Event.java +++ b/src/main/java/dude/tasks/Event.java @@ -53,61 +53,82 @@ public static Event from(String input) throws InvalidArgumentException, String rest = Utils.discardFirstWord(input.trim()).trim(); String[] arr = rest.split(" "); - int fromOccurrences = Utils.countOccurrences(arr, "/from"); - if (fromOccurrences == 0 || fromOccurrences > 1) { - throw new InvalidFormatException("Invalid format. Follow this format :" + EventCommand.COMMAND_FORMAT - + ". Provide one and only one '/from'."); - } + validateKeywordOccurences(arr); - int toOccurrences = Utils.countOccurrences(arr, "/to"); - if (toOccurrences == 0 || toOccurrences > 1) { - throw new InvalidFormatException("Invalid format. Follow this format: " + EventCommand.COMMAND_FORMAT - + ". Provide one and only one '/to'."); - } - - //they will not be -1 as I have already checked for their occurences int fromIndex = Utils.findIndex(arr, "/from"); int toIndex = Utils.findIndex(arr, "/to"); - if (fromIndex > toIndex) { throw new InvalidFormatException("The 'from time' of an event cannot be after the 'to time'."); } - //description is from 0 to fromIndex - String description = ""; - for (int i = 0; i < fromIndex; i++) { - description += arr[i] + " "; + String description = extractDescription(fromIndex, arr); + String fromTime = extractFromString(fromIndex, toIndex, arr); + String toTime = extractToTimeString(toIndex, arr); + + Event event = getEvent(fromTime, toTime, description); + return event; + } + + private static Event getEvent(String fromTime, String toTime, String description) throws InvalidFormatException { + Event event = null; + try { + LocalDateTime from = parseDate(fromTime); + LocalDateTime to = parseDate(toTime); + event = new Event(description, from, to); + } catch (DateTimeParseException e) { + throw new InvalidFormatException("Invalid date format after '/from' or '/to'." + + "Use d/M/yyyy or d/M/yyy H:m in 24-hour format"); } - description = description.trim(); - if (description.isEmpty()) { - throw new InvalidDescriptionException("The description of an event cannot be empty."); + return event; + } + + private static String extractToTimeString(int toIndex, String[] arr) throws InvalidArgumentException { + String toTime = ""; + for (int i = toIndex + 1; i < arr.length; i++) { + toTime += arr[i] + " "; } + toTime = toTime.trim(); + if (toTime.isEmpty()) { + throw new InvalidArgumentException("The '/to' of an event cannot be empty."); + } + return toTime; + } + private static String extractFromString(int fromIndex, int toIndex, String[] arr) throws InvalidArgumentException { String fromTime = ""; for (int i = fromIndex + 1; i < toIndex; i++) { fromTime += arr[i] + " "; } fromTime = fromTime.trim(); if (fromTime.isEmpty()) { - throw new InvalidArgumentException("The 'fromTime' of an event cannot be empty."); + throw new InvalidArgumentException("The '/from' of an event cannot be empty."); } + return fromTime; + } - String toTime = ""; - for (int i = toIndex + 1; i < arr.length; i++) { - toTime += arr[i] + " "; + private static String extractDescription(int fromIndex, String[] arr) throws InvalidDescriptionException { + String description = ""; + for (int i = 0; i < fromIndex; i++) { + description += arr[i] + " "; } - toTime = toTime.trim(); - if (toTime.isEmpty()) { - throw new InvalidArgumentException("The 'toTime' of an event cannot be empty."); + description = description.trim(); + if (description.isEmpty()) { + throw new InvalidDescriptionException("The description of an event cannot be empty."); } + return description; + } - try { - LocalDateTime from = parseDate(fromTime); - LocalDateTime to = parseDate(toTime); - return new Event(description, from, to); - } catch (DateTimeParseException e) { - throw new InvalidFormatException("Invalid date format after '/from' or '/to'." - + "Use d/M/yyyy or d/M/yyy H:m in 24-hour format"); + private static void validateKeywordOccurences(String[] arr) throws InvalidFormatException { + int fromOccurrences = Utils.countOccurrences(arr, "/from"); + if (fromOccurrences == 0 || fromOccurrences > 1) { + throw new InvalidFormatException("Invalid format. Follow this format :" + EventCommand.COMMAND_FORMAT + + ". Provide one and only one '/from'."); + } + + int toOccurrences = Utils.countOccurrences(arr, "/to"); + if (toOccurrences == 0 || toOccurrences > 1) { + throw new InvalidFormatException("Invalid format. Follow this format: " + EventCommand.COMMAND_FORMAT + + ". Provide one and only one '/to'."); } } diff --git a/src/main/java/dude/tasks/Task.java b/src/main/java/dude/tasks/Task.java index 77faaa47d4..00d9fc07c8 100644 --- a/src/main/java/dude/tasks/Task.java +++ b/src/main/java/dude/tasks/Task.java @@ -10,6 +10,8 @@ * The Task class represents a task with a description and a status. */ public class Task implements Serializable { + private static final String DATE_TIME_FORMAT = "d/M/yyyy H:m"; + private static final String DATE_FORMAT = "d/M/yyyy"; private final String description; private boolean isDone; @@ -74,12 +76,11 @@ protected static LocalDateTime parseDate(String string) throws DateTimeParseExce String dateTimePattern = "\\d{1,2}/\\d{1,2}/\\d{4} \\d{1,2}:\\d{2}"; String datePattern = "\\d{1,2}/\\d{1,2}/\\d{4}"; - if (string.matches(dateTimePattern)) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/yyyy H:m"); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_TIME_FORMAT); return LocalDateTime.parse(string, formatter); } else if (string.matches(datePattern)) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/yyyy"); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_FORMAT); LocalDate date = LocalDate.parse(string, formatter); return date.atStartOfDay(); } else { diff --git a/src/main/java/dude/tasks/TaskList.java b/src/main/java/dude/tasks/TaskList.java index 873bb276cc..46e3e4f86d 100644 --- a/src/main/java/dude/tasks/TaskList.java +++ b/src/main/java/dude/tasks/TaskList.java @@ -134,7 +134,7 @@ public ArrayList getList() { ArrayList copy = new ArrayList<>(); for (Task task : list) { if (task instanceof Deadline) { - copy.add(new Deadline(task.getDescription(), ((Deadline) task).getBy())); + copy.add(new Deadline(task.getDescription(), ((Deadline) task).extractBy())); } else if (task instanceof Event) { copy.add(new Event(task.getDescription(), ((Event) task).getFromTime(), ((Event) task).getToTime())); } else if (task instanceof Todo) { diff --git a/src/main/java/dude/tasks/Todo.java b/src/main/java/dude/tasks/Todo.java index 79f1d4a347..b2d4bfabe1 100644 --- a/src/main/java/dude/tasks/Todo.java +++ b/src/main/java/dude/tasks/Todo.java @@ -27,15 +27,12 @@ public Todo(String description) { * @throws InvalidDescriptionException if the description of the todo is empty. */ public static Todo from(String s) throws InvalidDescriptionException { - - //get rid of the command String description = Utils.discardFirstWord(s.trim()).trim(); - - if (!description.isEmpty()) { - return new Todo(description); - } else { + if (description.isEmpty()) { throw new InvalidDescriptionException("The description of a todo cannot be empty."); } + + return new Todo(description); } /** From 552bbca28a84a5175464850a3ca8e25d00569cc8 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 23:27:48 +0800 Subject: [PATCH 142/153] better code quality for Task package --- src/main/java/dude/tasks/Deadline.java | 8 ++++---- src/main/java/dude/tasks/TaskList.java | 8 +++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/main/java/dude/tasks/Deadline.java b/src/main/java/dude/tasks/Deadline.java index 1a2c9924ab..6720cfa391 100644 --- a/src/main/java/dude/tasks/Deadline.java +++ b/src/main/java/dude/tasks/Deadline.java @@ -56,7 +56,7 @@ public static Deadline from(String s) throws InvalidFormatException, int byIndex = Utils.findIndex(arr, "/by"); String description = extractDescription(byIndex, arr); - String by = extractBy(byIndex, arr); + String by = extractByString(byIndex, arr); LocalDateTime dt = extractDateFromString(by); return new Deadline(description, dt); @@ -67,11 +67,11 @@ public static Deadline from(String s) throws InvalidFormatException, * * @return The deadline date-time of the Deadline object. */ - public LocalDateTime extractBy() { + public LocalDateTime getByTime() { return deadlineDate; } - private static String extractBy(int byIndex, String[] arr) throws InvalidArgumentException { + private static String extractByString(int byIndex, String[] arr) throws InvalidArgumentException { String by = ""; for (int i = byIndex + 1; i < arr.length; i++) { by += arr[i] + " "; @@ -136,7 +136,7 @@ public String toString() { public boolean equals(Object object) { if (object instanceof Deadline) { Deadline t = (Deadline) object; - return t.getDescription().equals(this.getDescription()) && t.extractBy().equals(this.extractBy()); + return t.getDescription().equals(this.getDescription()) && t.getByTime().equals(this.getByTime()); } return false; } diff --git a/src/main/java/dude/tasks/TaskList.java b/src/main/java/dude/tasks/TaskList.java index 46e3e4f86d..5ad8e3d6aa 100644 --- a/src/main/java/dude/tasks/TaskList.java +++ b/src/main/java/dude/tasks/TaskList.java @@ -134,9 +134,11 @@ public ArrayList getList() { ArrayList copy = new ArrayList<>(); for (Task task : list) { if (task instanceof Deadline) { - copy.add(new Deadline(task.getDescription(), ((Deadline) task).extractBy())); + Deadline deadline = (Deadline) task; + copy.add(new Deadline(deadline.getDescription(), deadline.getByTime())); } else if (task instanceof Event) { - copy.add(new Event(task.getDescription(), ((Event) task).getFromTime(), ((Event) task).getToTime())); + Event event = (Event) task; + copy.add(new Event(event.getDescription(), event.getFromTime(), event.getToTime())); } else if (task instanceof Todo) { copy.add(new Todo(task.getDescription())); } else { @@ -177,7 +179,7 @@ public Task getTask(int taskID) throws IndexOutOfBoundsException { */ @Override public String toString() { - if (list.size() == 0) { + if (list.isEmpty()) { return "No tasks in the list! :("; } From 33b11f6f70ed03e7b80cd836e5e655000e83075c Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 23:28:48 +0800 Subject: [PATCH 143/153] fixed some checkstyle errors --- src/main/java/dude/Launcher.java | 2 +- src/main/java/dude/Main.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/dude/Launcher.java b/src/main/java/dude/Launcher.java index 37715ff866..ec85912d2e 100644 --- a/src/main/java/dude/Launcher.java +++ b/src/main/java/dude/Launcher.java @@ -15,4 +15,4 @@ public class Launcher { public static void main(String[] args) { Application.launch(Main.class, args); } -} \ No newline at end of file +} diff --git a/src/main/java/dude/Main.java b/src/main/java/dude/Main.java index d8d67e64b1..1ae8e5c750 100644 --- a/src/main/java/dude/Main.java +++ b/src/main/java/dude/Main.java @@ -1,13 +1,13 @@ package dude; +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 java.io.IOException; - /** * The Main class is used to boot up the GUI for the application. */ From aee980cafefae469ca530dbbcddbf5dbcd5a0caa Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 23:42:44 +0800 Subject: [PATCH 144/153] Better code quality --- src/main/java/dude/gui/DialogBox.java | 12 ++++---- src/main/java/dude/gui/MainView.java | 40 +++++++++++++++++---------- 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/main/java/dude/gui/DialogBox.java b/src/main/java/dude/gui/DialogBox.java index fbd4d073e3..ced2c26221 100644 --- a/src/main/java/dude/gui/DialogBox.java +++ b/src/main/java/dude/gui/DialogBox.java @@ -1,25 +1,27 @@ package dude.gui; -import javafx.scene.control.Label; -import javafx.scene.layout.HBox; -import javafx.fxml.FXML; import java.io.IOException; import java.util.Collections; import javafx.collections.FXCollections; import javafx.collections.ObservableList; - +import javafx.scene.control.Label; +import javafx.scene.layout.HBox; +import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.geometry.Pos; import javafx.scene.Node; import javafx.scene.image.Image; import javafx.scene.image.ImageView; +// @@author Jeffry Lum +// Solution below is reused from https://se-education.org/guides/tutorials/javaFxPart4.html + /** - * An example of a custom control using FXML. * This control represents a dialog box consisting of an ImageView to represent the speaker's face and a label * containing text from the speaker. + * */ public class DialogBox extends HBox { @FXML diff --git a/src/main/java/dude/gui/MainView.java b/src/main/java/dude/gui/MainView.java index 5dec1fac0f..867d361e77 100644 --- a/src/main/java/dude/gui/MainView.java +++ b/src/main/java/dude/gui/MainView.java @@ -13,6 +13,8 @@ * Controller for MainView. Provides the layout for the other controls. */ public class MainView extends AnchorPane { + private static final String USER_IMAGE_PATH = "/images/user.png"; + private static final String DUDE_IMAGE_PATH = "/images/dude.png"; @FXML private ScrollPane scrollPane; @@ -25,37 +27,47 @@ public class MainView extends AnchorPane { @FXML private VBox dialogContainer; - private Image userImage = new Image(this.getClass().getResourceAsStream("/images/user.png")); - private Image dudeImage = new Image(this.getClass().getResourceAsStream("/images/dude.png")); - + private Image userImage; + private Image dudeImage; private Dude dude; @FXML public void initialize() { - dude = new Dude("data/tasks.ser"); + this.dude = new Dude("data/tasks.ser"); + this.userImage = new Image(this.getClass().getResourceAsStream(USER_IMAGE_PATH)); + this.dudeImage = new Image(this.getClass().getResourceAsStream(DUDE_IMAGE_PATH)); } + /** + * Creates two dialog boxes, one echoing user input and the other containing Dude's reply and then appends them to + * the dialog container. Clears the user input after processing. + */ @FXML public void handleUserInput() { String input = userInputField.getText(); - String response = dude.getResponse(input); + if (input.equals("bye")) { + System.exit(0); + } - System.out.println("User input: " + input); + String response = dude.getResponse(input); + ; userInputField.clear(); - dialogContainer.getChildren().addAll( - DialogBox.getUserDialog(input, userImage), - DialogBox.getDukeDialog(response, dudeImage) - ); + showInputAndResponse(input, response); + scrollDown(); + } + private void scrollDown() { dialogContainer.heightProperty().addListener((observable) -> { scrollPane.setVvalue(1.0); }); + } - if (input.equals("bye")) { - System.exit(0); - } - + private void showInputAndResponse(String input, String response) { + dialogContainer.getChildren().addAll( + DialogBox.getUserDialog(input, userImage), + DialogBox.getDukeDialog(response, dudeImage) + ); } } From 88e5bc4aa1dbad3e0cc38b1091926359c487daae Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Sun, 3 Mar 2024 23:47:12 +0800 Subject: [PATCH 145/153] Better code quality --- src/main/java/dude/Dude.java | 4 ++-- src/main/java/dude/gui/DialogBox.java | 4 ++-- src/main/java/dude/gui/MainView.java | 3 +++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/dude/Dude.java b/src/main/java/dude/Dude.java index c4b7247251..8b28f385de 100644 --- a/src/main/java/dude/Dude.java +++ b/src/main/java/dude/Dude.java @@ -48,7 +48,7 @@ public String getResponse(String input) { Command c = Parser.parse(input, taskList); String response = executeCommand(c); try { - saveToDisk(); + saveTaskListToDisk(); } catch (IOException e) { return STORAGE_SAVING_ERROR_MESSAGE; } @@ -63,7 +63,7 @@ private static String executeCommand(Command command) { } } - private void saveToDisk() throws IOException, SecurityException { + private void saveTaskListToDisk() throws IOException, SecurityException { this.storage.saveTasks(taskList); } diff --git a/src/main/java/dude/gui/DialogBox.java b/src/main/java/dude/gui/DialogBox.java index ced2c26221..d0147e4700 100644 --- a/src/main/java/dude/gui/DialogBox.java +++ b/src/main/java/dude/gui/DialogBox.java @@ -6,14 +6,14 @@ import javafx.collections.FXCollections; import javafx.collections.ObservableList; -import javafx.scene.control.Label; -import javafx.scene.layout.HBox; 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; // @@author Jeffry Lum // Solution below is reused from https://se-education.org/guides/tutorials/javaFxPart4.html diff --git a/src/main/java/dude/gui/MainView.java b/src/main/java/dude/gui/MainView.java index 867d361e77..3508e85e0f 100644 --- a/src/main/java/dude/gui/MainView.java +++ b/src/main/java/dude/gui/MainView.java @@ -31,6 +31,9 @@ public class MainView extends AnchorPane { private Image dudeImage; private Dude dude; + /** + * Initializes the MainView, setting up the images and the Dude object. + */ @FXML public void initialize() { this.dude = new Dude("data/tasks.ser"); From 73f87d78e5474fad557fe5a9b7fc086085a9962a Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 4 Mar 2024 01:04:40 +0800 Subject: [PATCH 146/153] Changed Task::from methods to use Task:add_task method --- src/main/java/dude/tasks/TaskList.java | 10 ++++++---- src/main/java/dude/utils/Storage.java | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/java/dude/tasks/TaskList.java b/src/main/java/dude/tasks/TaskList.java index 5ad8e3d6aa..df8df61640 100644 --- a/src/main/java/dude/tasks/TaskList.java +++ b/src/main/java/dude/tasks/TaskList.java @@ -26,11 +26,13 @@ public TaskList() { * @param tasks The ArrayList of Task objects to be converted into a TaskList object. * @return The TaskList object created from the ArrayList of Task objects. */ - public static TaskList from(ArrayList tasks) { + public static TaskList from(ArrayList tasks) throws TaskListFullException { assert (tasks != null); TaskList taskList = new TaskList(); - taskList.list.addAll(tasks); + for (Task task : tasks) { + taskList.add_task(task); + } return taskList; } @@ -40,12 +42,12 @@ public static TaskList from(ArrayList tasks) { * @param tasks Task objects to be put into a TaskList object. * @return The TaskList object created from the Task objects. */ - public static TaskList from(Task... tasks) { + public static TaskList from(Task... tasks) throws TaskListFullException { assert (tasks != null); TaskList taskList = new TaskList(); for (Task task : tasks) { - taskList.list.add(task); + taskList.add_task(task); } return taskList; } diff --git a/src/main/java/dude/utils/Storage.java b/src/main/java/dude/utils/Storage.java index 0d03ea398b..8ede4070fe 100644 --- a/src/main/java/dude/utils/Storage.java +++ b/src/main/java/dude/utils/Storage.java @@ -8,6 +8,7 @@ import java.io.ObjectOutputStream; import java.util.ArrayList; +import dude.exceptions.TaskListFullException; import dude.tasks.Task; import dude.tasks.TaskList; @@ -98,7 +99,7 @@ public void saveTasks(TaskList taskList) throws IOException, SecurityException { * @throws ClassNotFoundException If the class of the object to be loaded was not found. * @throws SecurityException If a security manager exists and its checkRead method denies read access to the file. */ - public TaskList loadTasks() throws IOException, ClassNotFoundException, SecurityException { + public TaskList loadTasks() throws IOException, ClassNotFoundException, SecurityException, TaskListFullException { createStorageIfNotExists(); ArrayList list; From 2d2612babd540e4e2ffe85284ea00efbc9beb83f Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 4 Mar 2024 01:31:19 +0800 Subject: [PATCH 147/153] Added Sorting functionality to Dude. Currently, tasks are stored such that they are ordered by when tasks are added into dude by user. It has no order. The ordering of the tasks are necessary as it is a relevant information to the user. I have modified Dude in such a way that it sorts the tasks added by time, every time a new task is added to added it dude. The Tasks are sorted by By-Dates (if Deadline Task) or From-Date (for event tasks). Todo tasks are sorted by which one was last added. Now the user will get a sorted task list everywhere in the program, allowing the user to see tasks chronologically. --- src/main/java/dude/tasks/TaskList.java | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/main/java/dude/tasks/TaskList.java b/src/main/java/dude/tasks/TaskList.java index df8df61640..5e701e6a75 100644 --- a/src/main/java/dude/tasks/TaskList.java +++ b/src/main/java/dude/tasks/TaskList.java @@ -64,6 +64,7 @@ public void add_task(Task task) throws TaskListFullException { throw new TaskListFullException("Sorry, the task list is full."); } list.add(task); + sortTaskList(); } /** @@ -174,6 +175,28 @@ public Task getTask(int taskID) throws IndexOutOfBoundsException { return list.get(taskID - 1); } + private void sortTaskList() { + list.sort((task1, task2) -> { + if (task1 instanceof Deadline && task2 instanceof Deadline) { + return ((Deadline) task1).getByTime().compareTo(((Deadline) task2).getByTime()); + } else if (task1 instanceof Event && task2 instanceof Event) { + return ((Event) task1).getFromTime().compareTo(((Event) task2).getFromTime()); + } else if (task1 instanceof Todo && task2 instanceof Todo) { + return 0; + } else if (task1 instanceof Deadline && task2 instanceof Event) { + return ((Deadline) task1).getByTime().compareTo(((Event) task2).getFromTime()); + } else if (task1 instanceof Event && task2 instanceof Deadline) { + return ((Event) task1).getFromTime().compareTo(((Deadline) task2).getByTime()); + } else if (!(task1 instanceof Todo) && task2 instanceof Todo) { + return 1; + } else if (task1 instanceof Todo && !(task2 instanceof Todo)) { + return -1; + } else { + return 0; + } + }); + } + /** * Returns a string representation of the list of tasks. * From c239dc35ac689ce71a115beac536fb053ae598ac Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 4 Mar 2024 01:40:15 +0800 Subject: [PATCH 148/153] Added testing for sorting tasks --- src/test/java/dude/tasks/TaskListTest.java | 45 ++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 src/test/java/dude/tasks/TaskListTest.java diff --git a/src/test/java/dude/tasks/TaskListTest.java b/src/test/java/dude/tasks/TaskListTest.java new file mode 100644 index 0000000000..c049ae78ca --- /dev/null +++ b/src/test/java/dude/tasks/TaskListTest.java @@ -0,0 +1,45 @@ +package dude.tasks; + +import dude.exceptions.TaskListFullException; +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Array; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TaskListTest { + + @Test + public void testSortingTasks() throws TaskListFullException { + TaskList taskList = new TaskList(); + + LocalDateTime dateTime1 = LocalDateTime.parse("2021-08-25T10:00"); + LocalDateTime dateTime2 = LocalDateTime.parse("2021-08-26T12:00"); + LocalDateTime dateTime3 = LocalDateTime.parse("2021-08-27T10:00"); + + Todo todo = new Todo("test"); + Todo todo2 = new Todo("test2"); + Event event = new Event("test", dateTime1, dateTime2); + Event event2 = new Event("test", dateTime2, dateTime3); + Deadline deadline1 = new Deadline("test", dateTime1); + Deadline deadline2 = new Deadline("test", dateTime3); + + taskList.add_task(deadline2); + taskList.add_task(deadline1); + taskList.add_task(todo); + taskList.add_task(event); + taskList.add_task(event2); + taskList.add_task(todo2); + + ArrayList tasksActual = taskList.getList(); + List t = Arrays.asList(todo, todo2, deadline1, event, event2, deadline2); + ArrayList tasksExpected = new ArrayList<>(t); + + System.out.println(taskList.toString()); + assertEquals(tasksExpected, tasksActual); + } +} From a94ef4556057b186a836ca6d6f6a3f9880994541 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 4 Mar 2024 01:54:37 +0800 Subject: [PATCH 149/153] Removed white line from GUI --- src/main/resources/view/MainView.fxml | 31 ++++++++++++++++----------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/main/resources/view/MainView.fxml b/src/main/resources/view/MainView.fxml index 2cac3eefad..c312617214 100644 --- a/src/main/resources/view/MainView.fxml +++ b/src/main/resources/view/MainView.fxml @@ -10,13 +10,13 @@ - @@ -24,16 +24,21 @@ - - + + + + + + From ce8663b55642aeb0653548617ea6ea96d8a16990 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 4 Mar 2024 01:59:08 +0800 Subject: [PATCH 150/153] Added showing welcome message --- src/main/java/dude/Dude.java | 9 +++++++++ src/main/java/dude/gui/MainView.java | 6 ++++++ 2 files changed, 15 insertions(+) diff --git a/src/main/java/dude/Dude.java b/src/main/java/dude/Dude.java index 8b28f385de..84700239f0 100644 --- a/src/main/java/dude/Dude.java +++ b/src/main/java/dude/Dude.java @@ -79,4 +79,13 @@ private TaskList loadTaskList() { return temp; } + /** + * Returns the welcome message of the application. + * + * @return The welcome message of the application. + */ + public String getWelcomeMessage() { + return "Hello! I'm Dude\nWhat can I do for you?"; + } + } diff --git a/src/main/java/dude/gui/MainView.java b/src/main/java/dude/gui/MainView.java index 3508e85e0f..1f0837cd80 100644 --- a/src/main/java/dude/gui/MainView.java +++ b/src/main/java/dude/gui/MainView.java @@ -39,6 +39,8 @@ public void initialize() { this.dude = new Dude("data/tasks.ser"); this.userImage = new Image(this.getClass().getResourceAsStream(USER_IMAGE_PATH)); this.dudeImage = new Image(this.getClass().getResourceAsStream(DUDE_IMAGE_PATH)); + + this.showWelcomeMessage(); } /** @@ -73,4 +75,8 @@ private void showInputAndResponse(String input, String response) { ); } + private void showWelcomeMessage() { + String welcomeMessage = dude.getWelcomeMessage(); + dialogContainer.getChildren().add(DialogBox.getDukeDialog(welcomeMessage, dudeImage)); + } } From 88fd05eb0838f61ee3b2627530ea86f0d4af4520 Mon Sep 17 00:00:00 2001 From: tahsinhasem Date: Mon, 4 Mar 2024 02:32:26 +0800 Subject: [PATCH 151/153] Tried to fix bug where dialog is truncated --- docs/Ui.png | Bin 0 -> 13688 bytes src/main/java/dude/gui/DialogBox.java | 5 +++++ src/main/resources/view/DialogBox.fxml | 5 +++-- 3 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 docs/Ui.png diff --git a/docs/Ui.png b/docs/Ui.png new file mode 100644 index 0000000000000000000000000000000000000000..7d94b317343f00a1a8f57a5867b9bfb34fed3b1b GIT binary patch literal 13688 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 U)gOKU{4ffnp{lEb1h^0X2il*EY5)KL literal 0 HcmV?d00001 diff --git a/src/main/java/dude/gui/DialogBox.java b/src/main/java/dude/gui/DialogBox.java index d0147e4700..2edb1a7d71 100644 --- a/src/main/java/dude/gui/DialogBox.java +++ b/src/main/java/dude/gui/DialogBox.java @@ -29,6 +29,9 @@ public class DialogBox extends HBox { @FXML private ImageView displayPicture; + @FXML + private HBox dialogBox; + private DialogBox(String text, Image img) { try { FXMLLoader fxmlLoader = new FXMLLoader(MainView.class.getResource("/view/DialogBox.fxml")); @@ -40,7 +43,9 @@ private DialogBox(String text, Image img) { } dialog.setText(text); + dialog.setMaxHeight(Double.MAX_VALUE); displayPicture.setImage(img); + dialog.prefHeightProperty().bind(dialog.heightProperty()); } /** diff --git a/src/main/resources/view/DialogBox.fxml b/src/main/resources/view/DialogBox.fxml index bb4ca7aae8..ea5cde91a5 100644 --- a/src/main/resources/view/DialogBox.fxml +++ b/src/main/resources/view/DialogBox.fxml @@ -5,8 +5,9 @@ - +