From 68c58c12c1d631736a4b25500248a2956171496f Mon Sep 17 00:00:00 2001 From: damithc <damithch@damithch-mbp.comp.nus.edu.sg> Date: Mon, 25 May 2020 00:58:18 +0800 Subject: [PATCH 01/76] 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 000000000..885198fcf --- /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 000000000..b7c8c5dbf --- /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 000000000..2fe81a7d9 --- /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 000000000..62bd9b9cc --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,103 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/text-ui-test/runtest.sh b/text-ui-test/runtest.sh old mode 100644 new mode 100755 From 03523ec89e823ff5457b647df22a4e395641da7a Mon Sep 17 00:00:00 2001 From: lzq <li.zhaoqi@dhs.sg> Date: Sat, 5 Aug 2023 15:24:02 +0800 Subject: [PATCH 02/76] 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 885198fcf..a388517ae 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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	JWO768iA1&) zPYeOEgq;?UUpzNN4WkQcCsg<D!yWe%F!TuVO4@!Qe1!H$fxQ6c6o@0ps16y9XISJC z*E?8?TdON$q#<e5i7I4NOhthIq*h1(HUBh7-eO;iGHjS4<I&0`X3Q2I$eqjRDt37x zi+&am(i@eFV+nC@kv&u6%(R^R<=+tQ*Iqg9;s$&JuMIj|L;UG-0p9ZWdE40!0Gx7Z z<?fV0OMh!7ua)EJ7Ff|?QtWH5tZ2$2T+DXI@t}V~ucxLlR5_=+Ka)Af*EZC5#xn4X z<s`Q`tX207)<p2`qO5o`*O<sT_&APEu2TK0qpQK2?K>Kcv?BtU#{Y)2Bl)nL(^7<f zdAw>`SM`V6!BeeAi77`dr$i1Bps*8Ps<X304&g76kaSHat7`ON*4!f~^AS-|FM}3N z<Lm(8FFvH@W0VV}z6p+yV^2E=D4>LTom7%dW(?6V5_aDQ&i!mL+GATOM;P2n)Q>D` z@WW?G1z91~g?6GZTLTN#B6+MYv+RVlc|ee6Un5oBjr`$9VBA4e2oN9!_<&uNafKW( zJimFS+~cVPIsQ0BBo5k!HzoxC(mQ+GdqhWFSd!+RBSY!=S=}G=NGR<}w>IyvE#3C; z;to|`!so;Bdj^XH2PSw2u0;Cam2-BfpGRc3@aBh^3i#xcvnLBV%;94QNQ*?*Db%AF zZIF8LBiW;D;TRUlP(n~60IL#Z;4Y;^$`B|@?u$se@C!w!pWzYhl?Fo;((@mt3)@F* zAR=7q9V>>oBL=UM>IAuVs;zqE0%u&_>M2fK-pVOYD3Dgm#T0AM1+|bF4TG-gS2ZO` zcUn4PTfWR`#xLnvRJ&#f(D!%pDp3i+A16rC^YWq->4!-e37zk{fPR^Kt$|rp?sKL2 zR#1KJR<<m;yYJW#<JcVHd$(oqG?_s%VNXa)^1XV&Thg58G5LFf$*~|W9P&$~n-({m zu8?G(>f>Kpy^YFU1$*0d1L8g#=lgjRZjpOEIRtO`zsqD>zi(P>Nz{_Voyf!>hM|8H z&GKbMmlO;ueSjO70LBoL#mb-=)c@WC_x{pkJb_9lmn`-FRvL5p@?pLRUQbpuV>n}9 z73~8RhHdbpAP(rCs9;_dsszu=&22rQMgG9VR{!@W(M_uZ#d0gPMA<9Xi(baWspNKv zJ+EZ#-?C3JYkUVYA@$=ZScbjp3fn50%;s-(ax8p$N=R6{9)MqRGZuIkQDJ~o!-GfD z!`}|R0LED<2Q9W64bQ0HNM1+x^!}F~=r_Ato2?4SG?HftsK=8Z?+6uy)gb9|1%^z) z#_0drA@|)Fen?+>(9knuq4yQ<9)?2lW`F+7gJW|$OL(O6c1GuHJ*ktJ_+tBj=rJVE z>MNqc?qG4azyqWjl=@zk_bu#_6l=Gq!BP(NDi2_TJ|aa0(NP5vYWd0nVaqBf@0ENf zM81O>QEXew5J$EiB0&_LE4Nw84dvG?ykI_$?oc8XK2x;Ho4d+RWT()#o>xii;g@(1 zPf1mQAp9T5G=HUpN7Z!JZR9SNj@1ucyCFVH9pB-SN&u8g>jN4m6t<1^o#PV2m&Rp_ z9nw2R;sIu|%ZwcUYIUS*r5GwhAC)FRxwv|zgqY>$@W=J50JpHZpTS`pL7;{CXxJdz zKfoM~RE&imI>5ku9gGVG4I(6~k?@P#@MVmCTw1^KH2dLxSnVZPp-9XXy7MRKO)@n( zR<v<r(pZ&Wv<v%qlTh4tqQopOF?Xd%FqSarmpE4ZZqECCim{(_<a`0@s&!i9)_Axs zX^N2~TO2Fw$k9Q5;ixlAIMV)8PTj7+7DY8NW{2{#a(;hSwtp5Zi1v(td#u3Bec0fA z_rJ%Gz?>Bv;1tp7x1Hl{1?N{6@zsA-+Uu|40RIZ00n=7-f89_8d^h3)k=Ag49_;h~ zS3KLfkAaor+Yyou2Xtb`1<ngY0t?ol0jZj2YUo<XUjm*c#`qWmWZtM0COSb73E~Gy z#L~kcMN=eM8Pl_Z=}9J*Y;1H{8E?HeB{hHCdjG`mXjf>b`roO2mZ&GoK1~l^AIQQi z|MUA@e{;R&^!a-8Bm{!r@8z)`vjh)`lVfrVA3}oh#$0189v1uyR#IcxBqPbK8^C82 zLtbwtk7LC=V4OSvfdQ7Gx)2fr&$zO$!#~zFMVmJUH(kUgCmR;j3_GC<=^Tc{3R|Xe z8C02!q=hj}-GDv~yKJ;ni#f&Oeo>T3z|26?U~*a&sGyXg7<^a!<06B~!8fq)43?eI zq%L#vrOYg$Yqcqn;bZvuMFe$o7+@c6X2inAqh%!+)JifoL(W>4*J^G$yYfrtjFNJw zr9LI~kKMb?lHD2Vx{i$X{6GKSO&K>CHrbyrpj@rEW<K(%4HRoc>tn4jLDu=evJ?k= zRtKKsYy}xFc_kNAym0Pvv`#x#Lt;rDN>GRSR+-FFzdUmHC)&U^ceO~BMSwU>T|!H3 zO{`_OeZbOULGotMHR+Kcj?tpQr0nFf&hOkL$93=vV6Wpe{KZD_#d+mL__XVG-VZ6` zhh(-iM=Mk-HLcQpV0>puW}}DDNwV}!4?Ia&=cuf*9X8KeYHR)}8P)n^<Nd8-gObd5 zGZE{f4Na?}WpPP<6T;M;Jb;gl{=<f<mbiLfq8)d0p>Q9Czp5}*1l|GnV7<N&E$35} z4%eTbv7z?VHW_zoHfK6hQ#ZK|zs@FO$RkL)oUM2t@-Ww1W@xItavuY-p7n~OyKWz$ z`@1@@yLOKN;pRX9;pPwwg2?t6n#k@sv_ojb3RZCK7NS@EHZ{Ed4iFda<f3Nmw-EEd zv&Cg~<hr^+N#h-x`@2K8PdUFvzN^1Z<AHJh^{0VoTVI9$2AAvm=e@evP--XBn~gd2 zqk4B~>do4uW5V$BWbK?ZK>Y+{uud78Xu;}eG7tV@94**m%O)s(y=Ux67M)fpxTO~@ z8T{V}ZCos?#Gg&xB|tHX435_}UQid-MCVyppd-1EpIV;Tkv~t>+foYlZ{`vyvAUR1 zeao4{YW`S`?T6qEN6xL@tPNM0cuSdoAXA!k78V<+E%Y{ve-P%<AJHXB<mRT*EM`@r zr^}y91oaO7inRLs&!kQ16*UGUoR`p>Vg7wclg$-{sFRVCdj&L|&XD}GykeTW*Ha5@ zO-r|uf;bMenr+3;)it<#q;uWoIP-`~&9>KjQMN1fW@#G2*BQelg}b)&UXl8P51f}L z!h0j04?chOB^(E-tqn^Zb!}KQN7T&Pe7r(0G@?Q!Uy<lyQ7;T%J%0Z5iS&NsuR0)j zh#bx?dWam&t^%B>5Eu#1%nhrBIR<l(!#pl=VK<~&lgET`!-Mm+lAPurQ|Bf@xZtb= z&2)Jc$d3TTGzeR~l(||!IEGh`3OQ=1634<Je9xkACyGBY<1gpTmKfa8M3`Clt+mAu zo!>|~cSRW(^c=r}YnvUX4oME2vgn<)7MOGss|<(#p#mrtBreCztW=cPh??poE=dWx zsKmyyD8W9w8myub=nG!vhygiaXzS9>KV9G11BmlRks*_YarFC{Rk1}NPfk~47q{5L zZ&>1qSc3AIql}`=P||}hM^Gp_2)KibMF?*&@3Duz7v11MC;zR%Eui=~6Zswk2a66N z05BU8!qzNB@cFSwc55EMWbskSd?6Chp}2C#PuOeF=&d`h%-mTMZtT<#Kn)n!Oi&xx z015Mr^h6Nfin*<is8ACAAo@>nsL{N9$@kmZiv_$E5CgoAGNsU%5fc!ZMw-TwO9BhA z*yL`nYw#rtn}1y`e~sfYvL{)y-z~y@Q6Ks#!r_@grdizZIQix6zI6+fe>^;mF@eBo zb0$jYglFQ1>EK*XxhqOZ#6Li~YR@;08?%G;o<(DQ<{4vGUf(`#yZT>r97apIo5b)r z@*!W4!UKGOn&<}@j89pb46yk1GS!df7$Gl<aAen=c3Xox8kJPR9O)5-&^VfMR4Ypw zLe{#CFc)I|dJHJqFs17X#k`wYeKHb~)$vq@El;?l-a~kGu18zjwGaJCKCUXeeC)Lm z4qIiRCZ+D(Ln2jHM0|N@0wx)kL60_7-}vGX0iZ=x9dI7(gwA1*vS%%kTXMp=Z;9OM zy68@2w{TvOap_ex$zaIEVbrNiNJTUj`Jo93@<<pbHeUo@iwMsf7>sB#mC6`{q@nt- z6~th^FngB;ghoqu-WZ0S&16pEGBI8s_Sl|p9A@^A6r!x#tAa<u9_5`i<njz9V2S-A z0u;Aa#KZXJyFPA~DkmaZYbJVHPpc?i3!ea+D6HARV)Mrx8}7MI^Hb0HM{2r<vf72+ z*bKvBqD{sr-%uuNkW8MiNj!nc2$Z1+lZ))}sxO82)1b}wm!OMA@yrmkpvNL+g03}T zDE|~ms7!H2T@aMnV61E@vlSK+^88hg0XT8@hQ03?n@*>jRMuw!or%}?xE?+;RD0Qv zbHp6)DRBt<m>O|DnuAk`SJQz?b8(D{kZlwZ!(PljqVkr$MA`rs6tB0)B`dUDzRkP% zXFk>Ps0UeokLHcvrk+{cJ15D}OW0~%N<{R*^O7I`k4|~Y3`YvH^&M7u<NyI71~%AW z0_TJg0smX3Jej$t1VWjU^fw?%lbc&ep^A&4l4pR+Yr|_>BzKb+12bJLe+;*HR2Es+ zuIe^>T!_}<HFE^1O4wDew%XSIzO=P_3V6|NvF-ipxS5fJ4E;P$*nZkEm=&1%qJN5? z>w7DuinLB@U67;b*3E*n!R=X|P~fe10U-C?m!#|aYZ7*@$u7~)@Y>A&TZG#_IMQ@{ zSUl`D%tGMJKP>&>m@YxU>y*Ni?Y?taYPv((JeOLwB=_K5-R%H8=Fi=wntSl*6+XE# z%o<T3L>&Jmm*t4`G>%4R*;MIPAMq9%Or!o*3M1=QIE!_Lf3M1c<Xss(v?yK@1vvL_ zj4(5dcN-iEG29v86X>3ji}8`>>=i$e6Y$SO?${pE@~)gc?_<q3JbXG?VtNK!)IZv< zE`7sAGNN-6I^DmxfAQU6AmWmCD~@>bJ~Q$M&T{!xDm*`P0i=B$liDh}1J<Y7?i~za zAEd-9wk#47e4i0>g(!3VdLCVR0cyNA_qSt5FEC8IGf&>nhBzHc*zHD?fr~@=_xI&5 zY)yB9xk4AEf{w`vQ06Nq<_95!fzl@t9)ZI{3BKNav4ppaAm0;pCT|~BfXd0(AD+un z5yFL+f^^TQSEPvtxkdYxmxlDd=>)ll&~(NV5+tI#TcBZJbYJqA(t}nQAiv({8OKME zE}OsnVXdcG54|Bff9}NgGn{>Q`9;sL6X)Ln*0Y3<pRi?L$wQk*;D#Jg5=7gbm-z}E zX}?#GKAG)S9Hi6k(#xB?q#Ji0bf_r8hvk#RIh*|`u4s_=b}ZWqZuaW3lkJALh?(2i z=)dEYY);O4r!Hf$kI@!+fCK{;q$jwoXppm!f)ptx{L>0coLwYzkF%*8F}t<zGnBmV z*ybx7CWAqE+doQVn{(p>OQ`Qk^FN3ZudmbCOU-H0HT7jon5QtA9DHU$*2}Rg%@rbv ze;>s?!^M(>k(Q?Q(X#QbTuexCr61QqzJlr!mGgjh1L4y=+UzUafE5DVSSYUyyI_)E zy<J<eV|rlwKM!gtvBJvC7(sZRCXKl>v`5?nH(dVk_LASs{Cl5~pADBzm|!oYz~<b7 zgzB7L9|eIN;ZM32wss@NOmXU3$~;9HtXXoqwg&~>_UkgUBsSrMJcKF3;GtMI6)?Hl zG2S(%PlT2n^mt$p2Y{1t6rr(5cpY;uy`xb=MEN!Z(64h)?`E5ll-*&zG-Ot6Ebqk9 zgpr^$vY6$~3W<A7E&P_3+fmDQ8><;a>||cRjxFU>nzF2zX@e}jN5}<5vQ$qK=?m+z zEb0=<4w<poKyM1;vAqoCKm?D4%eGYNW;r76#sHLI>nsfa0~BV-1ux(>WF4Tqr<<R* z6$^nNU18&cxch+_gStOvM7c!$IOIhQx{lEWQwbx@H45vCO=1oi-k?IvwC^}Mfu-3Q z7G^KC<VxHi6Xc<2as6xTRFA{vx49B2ohCw|W?D=IM<ev(Y=D`)7=DhOt~^M!#z7H9 zQtRPWeh}z44M@yn#>kCJvX1E(0#7vk5!%$KjxP{QMV7?TNIay?V2q|tWx;o=%ziff zS$teKy<?`4J1eyMLWNw<g?hoc7FilkVTcMCTn7(3jSJGw&unNmNMwd8k}=mYkjPjR zz!vo$XMWBp9+|d~3P)@2N@>h!cBn3l3UtGI4T+TN0YtZRf^5$;V2;gP4`?&9s4qp2 zM>lL@U$Uhd;`g8qvf87>BT_cR;9w`pFK~p8V@QK%+zan)5=7a<OI1UKkPO7k3az|Y z@qU2f?wX7S_lRXyI3|dr!p`%!r_&hDj$2ACcVyCN4p5kdNV4q^z)99(?_a7I-|D)r zN<vPv1JqhE(39G!18g?5Id^~x89YpcIN<c^(lcCM5;NDK8^zNZSf`5ckfP@XL=DS` zap5)C(4+4iS2<C->Ds7jRQ6MORlnj9c!LA>g-w|uo8WdrR<YHGP7W=LY_Ob@kfqj* zM<Ijn+A&->215DrPNU!{Rri#eSH(@ig2Y870FYMDI;g;6gGghX%?;!j=}$$`9~rT% z7zw$`>8^q+TlkP0>&ED>Q}9rS^bZ{3kdQx2KsNhJq^H9hXN4jNgYOsym~C;Huc)&V zeqO~7Z~ZX6=BG=m$YG=OH7+6~Qg4C0T>OpXX-4U+*6mPJ>5&IvR{;`Hj`O|vs;UYb z9e`>)lD2WrFf9R3*>tj;9GRj+JAZ*`L#3h$o`omGQO(=AU%u2OVsn>fxN$Gp96z5w z4TZ0saZ<t7Vx&<!-TNtPwh!dElWd_d*12EZAdOA_52kdE7@TM>A_S?FwE6`Cwa1)6 zgE6R@(d=*<ea>e(i|AI1a8}qNy{ucKIG{Z;mmTXXgjQ^;MLUba#xM<*NrP%2Ch^X* zV$bYwI!}vX34XSm2<K7bHA}>4Q4dmJvJd<NSk-N@Z~-YGpMc$*AZRxa_Q(@LSP}vM ziSea-vOE6J2Kf~aaJnUWexgo}H%kr^y-tAqiu!^#WRqZdW_s5OO*CWTe0I8I1DvLV zdm4u6zk7XFi`*<$i0o3~N0$+Hak8CC_|ou*?Ux5I=RhN7RN^@2o0+qj&zTo7`@LuS zj54`wINb_8=P$k!ZEq6Az73&##S2rfA3|Z-%C<m%)R%N~I`4I?xTIbqe72olBP1QG z1fr?CrkhZsvtn3!m_}ths{~H%eS4vP^f6E}&Z^Xsm~e?hiV5s7?Q4~m^$8*0JQWw* zUA)H++}u+axwq6M6*k^p3}D_#x34-`XC>w_=zgD7Usxpr)Z9mr!#7nd7eWaN&$(n} zFApC@K(p;U1}&6~nw)2I#}yll9S&!9!&Q>9u8oH@g%O)FBWg}t?v-Bwa4;cP9N}e= zgpN+w^T2CG5w_fIhL#XGP*{jli_y))BGgLLaW+TkM%5{>HcxD#i#^z=nFu;$6)L2E zwC0!2r#qbal-~J#=0)OYksd&&L4yx{3VTzJ@SA$J^i3#!ka{pRCGBp9y%XWyGs(m0 zAUKrH{OY|Bb;sL;cPJ|a%q$kPZEUKSJrMw5{BF2gBcGu@`4Hh9;yt75W;mKvuhh#t zZWtQ5O^GSR)tcViYJME~=w^!a74G70`q$=k0Dh(D4me``eNWoauYO;>v-Y%UXWx#} zPIH?THiq{8ZSvYB&vvN<4q0@7^DVlH13YZBA=cJ^3M~*x7qEN)9$X1Wj$eu!p)o1L z-;qtE|23H^q!QRwUAdet-a9_Kd682_hqU;aM+qT=+2LfQTwNZ0?r58XRLKlO9-4wz z)7M}Qyk}B05T%;d_OTn{Dh6*cQK8{9b*fojw%RS}S|BIhtyKrRPXDaaz}79*w6I>$ zRajKeV6I6R`5~qX_{7=#;gS`m+cBU9e!f#@ypGsfVHU5^WwFnp^WN3@21QCej6apm z$k8l8>uD2%;1Cr)XYs?tD4up8UT4$wiaoQBG-gg+BdURf7rDH`BFpFfKzZ#P-l5d9 zv#>UKTq_Szyuv={)7<7Fq0CM%%BLkzJYKq+Hx^Z8ZI-ziz}DhxpyyzXpj%wXVPnVK zy+lima7FJ>TgYK|p$vIa(+Hnep6g)EP_&~7;|O%c((GKdw7zKZ726_y%@1@hFv`~; zSDc77&lD@_aubiaf@InY3tuh7V4L9^P=#J`ch$}TFFh^-_Ki>U7}Tj!(cw8<CP;Yd zN?qS=SOLueo@xX$Ff=M;t`R;tA$FFmlQqh4W5hgDjyM?1OT+pW)x07FO|GdNT-9p) ziZ>gBSSd3?ugBBhEtKY+d*;_4pVd<>MaA42R(a^Z&ayd~j!PMTD)v4LNYePTj@0uR z=XadD8G=*Gk*xJ!bH`KI;`T@HQC<)Z%jUU83&>sqV*OI0EO?w0w+GrOx~WiPM%mjM zXv?Rn@Yg`hDoYYtbsikb;<@_Bu>v|gL$UFGkk*f6$2(m>`%U`orWpsg_@)K8QS}gZ z?Aoc6yK8w-qmH@hBFdFI@%{BKSldR2BmI{~;8E(qei|^=9hE+0STZN7Yj?jRhF{rB zM+k!epp*w?%YZA>4^Y)P4v=64AJ4@0u+8p(`@Dv)mTFZ{qjuIic{j@uUc8^7<=a6~ z3|iW@kdQo8L>(T5RulBr5=6Nk#e_>hNHW`L;u%3k)o88FOL*NCz`lZk?&9UG5k9<b z1k3(q-@AQmA<jAxAY1zqHNN>sp)aH3=IDP2DEUnVD@i_NxHN?u4<#*t?Svai8UCkA z*TUp4-UxQnmLmAE$JyZ}E6;3Ro|+m}puN|3ouIG`Vg(?!oo4AoR<fEb30zc^cr)6! zg)9gytimZ+eS{%sfEl)8y;GPT;l9{$hBdg9Vb&GJY9wQWiZObt8@p8Ry#ge0`Oj(% zfPMuTCT!lpVB{#%lz>km?Wmn}8VEPSvC3gW(%{w%{W9Qf*7P312qw^P0?NLL3@tTS zF)NnFrARyFa#6}^qW?%0YgHu_5LSKz4~}Lx95Y78H6dLJWNT9T*K?n;%_Y;cI|&rs z&5)aj4aUHTxbJlFq?8G?8bhwuLdTH@tY&Oj+#sL7fYL$RHzXj-m**+xN#B{_$Tzj> zXE>fqf9zzlD3{}RQ#7IRun`yXc1RuP<oJ0fQ;CH>$@k*Ef;A$7%!zNS61#<?$IGfR zPm~=_4Ql<HIRqC!Se2f(hs^|=r)Zr_kF*C^8ZlHJ$!6~hOQ$m8nQ`}x9Dq&%h=y?x zCfHfcEqI>#B~~4JnBrnt)}lBvVJA9U_%Ubo`B35&zWWK6WyE=3P6<2HGp>iyC7%x8 zfH=Dr&!6Z4ynjD%Xp^&<y0IpX(tQP`kt$Dy9-;F_GTx}Kr2IgPZm6($?sD`5MQ87a z{+!dhVlBFnl?X}Z-A9j6*LU9oSnkub1SDUemJ#!%_)@p6)6Kp$N9ppQ2n=?h?HPJi zF_Ur0c9D!x$ynra_U-VwLi^(P{z&+SIj%seVpqy1`hGFmgjIK{Px{3hXHAns{?IPh znrgXo{_L&;QBB0EWA4aJQ!`e1pBY0yX5>xnQXyDbym~%Q=CG2Gz77C66&Ky2u?k7E znzksy3r?xu{Igd)Ld1lBrkH67rGXR0(mOdXm|4vRHvqzk(HGY)C!-IWtxwkI7xoF% ze0oHZUcjtLmiC1!y<1oMnQ`Ev;eAT`Q}Xq;l;RkxQj`^wx~>Y3C~&G;(pt8Io;iF% zYu_zye)%5OU2*6<U>Tr&L9_7tNu_Y^FFj5Ml#JDKXU^32+G#PxE7fVr5c{tO=9zPR z62QWxNmj^}B289Ix(O{op;|&p`wf22J%~4fl--$q7Gjh*-&JA^HHfuGQhF!Lrd;58 zvFdp_Y$voYb^#l;r~>*(r(DCmsck8CuAEB^ZVBOL&;}okco)DL$v~E<Y%0alPh<v3 zSWs*(8H#SU;N<keJ491;vsc3=X(hYV!3T|iZ#jE?5N6h~<OI|ei`r0W7es)oy*sTJ zrr_d{VOn1#&&wu9(d5{FEc2ZchhO&Bc(GcP;>foN<qFRBN2B7>Zd%Zp6KG~8q<@lO z)BDc^V>XsOv|vDY>kvCrrB1=@|LW^2prUNvx0gk_yIZ<Jy1PL-Bve2eq(NdqIt7-F zrMtUBN<tbzx)G#78u43sLw$eW`9J5t!!vW;F|#wzVQ1#PFN6gA1ln`K&Kb|-a3SW9 z;zh{Y+3+&P1ixZG99dCi?JTV&#+h=WY`A*+Os{18nXjjMn^TvwZ_4<_Vh!l4GLoL` zU}KgF$}9C146}6i)CoKHTkYU|E0d2p^_9o>Bg&0=j0_%}f^#+oTIE`9S@~z-b2PSr zelU5ge{#W}ZiQ6zd|lE5(ah}khm*Y67SVIXQTFCuQlWTjx|kEWgx)inKQa`mT4t=g zqH~BP&f<~M0UKZhU+5KWtRA}>h6{jHEvYO&LMEOe%{h7-E=A-fV3qq>PdC_`%1UWC zUHj$WQB=3;=*Jhkc&5IYzRyEq2_%#oKq9&V1_z>og{+#6%&aB?Mz#&eD*4}iZFyiH zS>(Z&Mw31THoce6C?8GfqMeYNa3^?k1h5wiu4+o+oye#Q5``d#8(;M~f0GKjaMn~5 z;M>Cc!elZY&vYtpGgEvhrWe<1OBQULPcc`0n?_0FZ*L?Z*^^S95K;swF8_*|4I*4o z8a|%v%F<0oE0ZPREiBB(%j311<Gb01saF&1UJ1A`e)Rr!_2cCfu^Hr*Sy~=PEf$w= zSvQS`JW{P{nBQHf-z{`km;avVO_bKynB7S~_#(RL*hcXCIxFoQ`>yMPU*%{0VkO~n z>H{mhhQe|M&(zJ}+6J?sMjaMw0g&nt^c)RC?i^LbEET2hKq^z6g+uHT3(lx|wlxJL z6RtoM!I&aYPWVxznDRmlC+tAV?&3^BTw{c<IZ5R(x|MT`n{T;f>cB2lV4<C#we04} zKz?n8;Gqu8yPblZ#DM8}r{sCT*ofIiK^;8&@g$M@QKET~%~D*jogUA|A!q`mb(J1X z)Z;SRF|h({KDZqyavh8qbA3b&T~-S(l4)^FXexm;Wm+R!)s^(tUxf$MO(2V>rC(}v zjOkZBPv&(v5y-b0O|&s=bNEI(SL7m=oCc7!(Js;}h9su)=5kOmbfdv3i+^R4K7{}a zAuxOp6u5W^xQJMhBv|-*kOw5p0`|Bae?2oGvKdXFmO^0trSv(~W(Y>sk)XJ~mKQmP z3F7&8bjM|wlBu1`ZwN(&6cStS06A&AZ!a=An5sI%?onwYD2(Mm*`1QrI6KHUB;U!} zDrGKi5M~6cz9`<%f2Sx4<;0H@Meb(96S&Wx>ckRSrhEe~sF1Lf0I4!|HLBJ=uW6Pi zcc4Bn+m7JdWnH+GegBqYqSRY0-9CbUsW-<t<DI5OVQ$R^rJacU!iDLkaD4UU^Bo^K z3<30s>(s4m(JvA$tNP0GzSED15ck!tw~CpR+8<?iqB)w#cKg7E-m%?%K?v;@d-T#I z|KM0r{R?(P53Yun-54mo@rQT@agl9d<616yS%%CJgNdqFY2^1s*^@_3Z7RMVds_J^ zFIjvE6ss1`&21mA<z#==cOv&YbImruA$2`Ua5!nmAvYS-o|xE;_gI+NE&00Ra+^+V zQLdy&q!3$3t^iX``aZ6z6Ko87J<CYp%Zuf!4fIfk<Jf-RrF0B3ggGlfX$_9A3-u{c zrGx7%gq}h0vtBhGA1j>F>q)~YZQp;IA57+C<S_L}PjqVkG$QMuEIF%Nx>Y((NI^_~ z+qdnaK}XcahqOSH-vsn5Klxjjxdvillak@(lx=2hZ#$x=2}QxGF;|KA4OPq2T-Mp9 zHCM56#k3~keXOUTVp#iY4lS6E99aD+K>a(+=Wu$J2vd8<9sWy<nw5S>p>jJ+BJ`ie z?Md1J`tQ-|Z2Ue_FYG92J`+*UOp0TsfJ+#KsFM=AwC25h7ifL)Tr>3=zFF^eQ8fYR zdN49iUm<qKO1dhd_kzinAPBSQ8IiwL*3@_YAR#gttgb8u5HcnJg}^=Xsq!?B@`*vx z7>{yTdtE<MI=s-9*9XJ{t@^1K^Kb{~`k$t{M-9ffpUf2!7`?oX9Gl`)PNII-&ZgK= zW=EmYH~{gV?Ka?_#OrZ^F8_Cye<eD#col__w+CRhA@zGg%Me}>Vl#Ng+p-A1t&`4< z_;wF-v1g+w8T3IDiD3LCTb=>iTSx>JD&3?TM4I5ltR>FJh4ps#4Mdjj*rf&TsPP1~ zCBtIUNI2qfWA2+3M9O5Xc_>j`51NF(HhZY(Kx=5DDj=GHKY$)kLjJra1Ener2kXL? zt=pHa1;#nQ=Jn)3)vohrlga5RMpEJO#k95N+h*xzDG-tf5dEmWd|8_OvzJm!V1H+o zDy*QI>{fp641)Bl95w1pZfEQX>v+aJmlp4I3d>}mV>zKGFE3UlGh547N~7<dEw7R* z?1~v~RymC55j6J7wi6hIG2pyY;(X)kd$$+-5(}C5W;SQt(vHC~+LF(Vf==^gJPcP1 zu2Dza%Rs5>VcvYLhHDj0{nP-A{1GmTurpOB0rHl97?azSydNPNj<PaZ6}__B&vR0d zo8T)N{I<^|3148bc3pBA$2!$sCkwz14kLX@E{%(YwM{%zPS((?R4Q&$)s`!p7K$c4 zdKx?G3pt?+wLJYn|Cw`((RGw+-Z|OLojPrik_R*r^>$IJPA)E-(Sc8a(Y;n$F<qpW zQPd^IJ~lV_nW$)FD7B~~^Z1Xu7cFQNXR)f8UV-)$+3#k)ZfSGvqGyUqQsAt7ZhhCk zwo2u|@3BwP4lA_G7$gm8yE=WkCg^`=%*l42^ED-;c3IoQSZ21UklQD9bBgiZSQe6@ zny4`dt(SM5V^Z4UnAm!~){?a{w|r5ueG&eh-a9FM614T^2)^<BMRbhatkUB)@-Y%m z)31K&ie$neYW}{7H0vWlTuZCgbV;Yh$010#>z?9KtKMpgyIvk08Jicco4Y;9jYjY| zUJEYkGnekCW<kEWKi)o?X}%#7R4GjJ-&3~*L3WY3ETeY10@9_Hv)UTvHO-}7`LK05 z&Rd<}?BFCP;tQ$|)N6}3k_aXV9OaxOXh&lQX188M-6K7>m0O)lW0Th29eFk|@~k+f zal%EE!tn<%b$Ee$@{N_^x`yAkBj|5q)Dd}u%zP$#gz){rwnv!tk9p+1(iV$ezb4)W zJ(+?dHy#?cU9s+F63E#3y1yxJQquGZ|5G?zCr?n)0?UqfYPky;<n0jfu}$;nOpm8q z`6k>TlYosSf|Ex5qqBmdH=0`QS=L7Q9-jF=`m1m|n>CaPMb%%J{Km0!XQD;yi^upc zeRYZ)3oo1(ZmqlvhV0JyPr?OA`MVOja8ivQtM7GwXvX_8+x7$DVfV5&NV^pH8yn9q z_VeUuu$Z12Xkx~rllkgtDIw+xt^}?G0~5pB4!ec?C1P-k%BL}nr;jM^0Ah;iOZe4H zq3qnwueLv?&-r+PJmIRMuURw*$GYAJ@`Bk4j6QNSY0oLLnSozaO|S9^$2eB8OI6RY z9w_w1EXTzvHxO;3w5zmRUPr#4iz<Cfr5hK^Z)=he1QOiZisABQtT;Z7WG;5(+kNah z_mYsSUc{i#tT|(V|K%}yj(pKlOrybD175}I5;&f|(riR~JO|z&<Y-TgmFyclG)*P3 z;BhoxmB%KU+v(mfu5Zirzvk+Whju9}>flYl_>RT#jGV>1FAEWEBA<M1^pUgdhY2|n zCzB-kr?;S7Cn+s#_|_~F$F)i;y*xGLi7|uYdiZc}*3dRI*_#@(Tcixl5EW5fZ+PYk z;rC1xqVIh<w8q9sYg}vMEYVQcv0>x&cg7JhVCW_{Qo_DTM!clxS>l25G*ZH&c(DXR zS4-QhC)#l(Zh<9|^`%`{8FcTAVT~jf3KsVCDG8utoJ_d>EAiaF3FWfZ8iXD}GZHYP z0|0anyL#dVq##zB;SIPxg{o?tKBQ`vL3{<Ic>X-;hA=!9p>x>`z^FX&Fj$`ZWn%BH zDv}Kf>#c_3W#VB0twuPC_tDDq>0Udx=^(F@KfA-Bm-C9q7l`|p(c8;H3SZP!eo^EN zLLCDvx!90T99o9xVAr4!Yz%WOV)i}Z;!qFaNZzvJaM1fiqPKl&LXnsir>8vRGt!0_ zxg;y78_%xX2v=T&@OO}OUv^)KLJ&8weY<AB)b__`#T+*$PcX(pJ#>1Vse~!|0ltLY z?>=8cC	^*sDEyYGdRzb6yjqwNIGFC~K}4AgSIopnclpnUj?v53AJ3Tw;k0FfX!z zv0qPt7o^gMTlHgqKjox2Y%8caY;J2XWxw}y@y_<uO_|@owE1;OI@6#5CyyLV-FlJV z1*Z`=t9~v1R$Mva4!@X?v;9lkj*ik?%YmS{n&(XYdB(3W_##UR$+eV_gLX;?Z_H^O zqDtYTS{#kUkK;><XRKflOc&Z4$Aa<Uu0DJN%76~iHF(VD*}mYK8jmL677RDD4FwN5 zJ4`r~m&9*&#oOa*vei!WNL6Uz(zqHo=#0f6nx8%i)wNKsZcwTxwP`qdaj76#RwT0! zGw1HI<BS#Uz0IOGdN;!WObxa|W}u7*tC$<Sijsmu-b=L$uBfd$RNf?ba#n_7Ez_mE zUkgIGr9HLPz|FCXr!#j>V3{1RkLH!IYH4mSOD-_f>i?AU(g1j4M6Wrx5NvIvX5QFA z_e1=!r7vi~iIY`4i}cbyOt3mpmkA;&G38GgD4;ZIGB|`+$smZ9UuL3BH^U;sO*Z#E zH8)ZGD<aY4c<CeE9vF5Um1+%?+7zS5&pkl|ks9sGeC>=LK||ub&w$;yd@3Q^qyt@t zK%Ndfu}n_8^eH=<%42H0n}!<VH8O13lZL>`bx|aG$IQ@7MfnXfB!ZLBzz|N>7uXmR zjh#GgfthPYNL)_SaBdn33)aP1gxJ2LqMcpr3Muh{CMUK~dg5b}2HyyGIMN@d31c8m z)v&9Kz?BUVEKp2LUmd{2?Jh7BN-K<W&$7mTRT|j&!brTar$U)i)2cpsf+c@odf6gG z{Vv1myHpp1&YUu<v0Bi^Cec8rp>3aJ>Oh04WLL)}p@g@@8gC)I#g)6eS}dz>uqmu0 zkl0?~ioVduv}xx{zDkC@g+szI6)&hrudP6VXK3p+mm)2J_DE5=(Zn~KXu%&jOK98N z0`|!ZiQ8@K7ky34=)Uidk|cYB-SBrHWKrw~(}wP4R@p}`+wqJT!IQ|q;LdT2BW(gc zPNkKPo3E#qJ6XqbZqd|9oCV(CB=wM~JRzhPP-;=`mDV&?$4Axf^50%@mcjs8?WM2Z zXZmhlgh!q!eZ<K&Z7uAykwS6QeeIPh#@lPeYN?A{BeMpqj<8Y{)H@!3TOHY2!<T6F zM)>5_NP9I`r}fTk6N;cg!vwA006~0x3Lg4gpwQNe^?dV)P78aYRrGMw3Nzf6<1@At zq4j1wVL_J{1nDxQIbIW-Em7B?iGWr|An-6-9|ikKr~9xsA(p+1nOxKCgl3-mw3=mG z<}0Pmja&<hHh3yXQ&^(MDV_I`P@0<1!rc?{tP@HDEExm|Xl|;ULtbG&Za-7b$W=Ym zX-PL?Q}U06h?pF&X&^=2CQ_6nYBQMW(HQjBm})nCm<H>*<vf9W;|*G%0O{HbCPC_q zC*Q8DigHSW7gXVSeP|ZEFKy3U%gjtQU&AgbiTFdFqj}BlHJ?+<Z%}UG(acDFR?CTw z4YZLL6i{tR-xFBw;-_QC)oFo<%2PLvvyoT~o=z-tU1w5e^bZJ0AwOb>4s<qy8wB4o zK=A2C^rqhPV|`oc?qIqA&Az^Mp&>}RuTtui;8RvxWdn+Ak4Ln=`1%c=jOnc@r+R_A zPyy*1*1NG|#5TEGk1z6hU+~}5KJxhB5;uOsJKniTuYq9A|JgM!eCLfDEUZ#&kBg3+ zs3SE+&cZ2G_-xD(4Dr~wk!Tc~qK{t;1`h98YuaPP91L!LwJW>F6QEg6B`*xHNQftW zTCCtL77PDA!63TiKv>{ZH^}tex%vDc?QBNqqJH1R?d`GzWi{mZT$^)%__`r}Pe8CK z1koJ%psrKBV#&46-n&NvXV4Uh0CBMAJI4HOL$59j#wF7HAg7l?p&sv`obxvqF@O45 z@b`NqZB(A|OZEONQV?u>rZkb8x+>OCwxdD2D}1{L?mH}5fLHZCE?Am^!1+YL(17ZW z01GQA8Qn-oSa3{}5dTn%S~4)sfeQBrfORiy;I+^8voD%wLyTOK=9|-6)@RO5dtkCa zcI?kIkM0@BCQMzPCy{pF8m0@bX%5U{gz~%8P2IlLOh@imk4LBf4$nBUVfpuQtlD=k zFyMYW`6_NAlWY#nxuK8rkPB`26$vQbPIF2e^TQ=aOar{7e<JcwKo%=pSk5XeB5*5P zqbu8wdj}QAlEpucLxG9gm(FA-lFY(;4dGZy;E+yY$kEZe)~k8x$02)T(%sGX4SIlb zmn`Z!2Xl|%BV(CtvTbv{&@O7$Gqc12mf<Q%-vnj<k2YL3T)5_X7FqFVAL>C-0jV~6 zbO8<P)feiTDofh#4aifd>rp3gBNId}R|482Wks}+DR`nsQQPF4^1Sv5(RE>i#Tp0k z{&$1?XUr2rV|G2!UlM(4?9#vLjF@*Jqqc}yYv-0Vzv;*xk2dPtArD9-f|8c&!}Hb9 zw4&z8lt$7nL<AQ*OsitJcs&CN6}@Si$<|r=WE%hpP#F~AB88`s8LlY8d&aEmdcHU_ zI_mPwXYW>K`0lxub%U(Y3EBd4OIoLs-pM{9$nXF?Gk(B$gla~$A|6C+M6gu>u`Q%g zRDD(XC0z0L!|?2}`;?)5PvoSkB|~sYdjwK{dOw2LIspdty%dm!WHAurXv@D5=qy5Q zj`EF3gkc`76{e_PXnf<2MrP<xJw<P@WG>{UM#8z1miUlABM<1F_3pjjs^qxPN1<rn zaNQ66)s?m*Um}!lh4S;uzkeDzr-c*DMtSjQ^6hSu0p1G(cDJ3}*SPYMNx&tu$-DzR z%d?qg{rb8ZU}Kh?zj0GJNE|4LD<4aJmdQup$<98s{l40Fr<?K~X8j5yOdLnMR~x7O z?H91W8eE6a@opDQ#1||CA0S}{$-J+(;Cr87-^Z6^dKDY8WO;^iN@QjZWG6EdhSWHf zJtOH_2wSDP)&M(-0n1kL?tV^N;t#Tnwyq>3XxU`FMe771txd2^Ao5@@2~#|gzEtOx ztn=ZO9M<Jmpn#_9$}3Sb;0ensK6N+yI`r}+c}@p+M4lewp!iHYtt`9@GM-WDX;;iJ zgh50JCk`fHtVfLcbYzg<_;JxmGN$ylgcj8RENAG)0Abk?FlLMyfQ#*s)rJHFSwf3b zo&<v{Dm4W&MhkEXdWwj>Cb1nz`L34|i`)#0=NdES5MU;Wh`lAD11;^NR3|q><LSeU zaRHn@qJyL46LY3alZ;^`CBm4DFyY3~kQ{MCMEovMbi(by22l5iX_Sm1;P-(E?G9*@ z8o9;9ya`g@AW}O!{SRAWWqhLSE)oD1;DHY=x8eXH8RE_o{lM7g8s^Vpkqms<!bx65 zskdIvDbd>!Te_bEw=n5X_S|J|?&E0q{1X*$YJru_o5F(K1o8{{XSOt-pPEh;SWn$5 z9({(MOQ%se_2KT}YK;uOzv4Xd`EU#R;I(qOEPAsUfB|EPA1>Xd*qZ^<W*`Y;OtW5( zeaBA+lISw}=$R2Zi*O8&<q-cG*CFm{B%hL=pDFb+^$V(KJn;6?ohLIW`mEc_V{O61 ztunB2gRJaw6tLX4(VF5zF}94;<>l#30a~W$LLwLITE{rumxA$5{&0JJ77Gv^+W2tA zjn$<<E;ibdxjF|6lfLd4C!i@T#JUcK5gs@MsUjRRM(?7cP^^y;VOh}Hb{D36uL@N6 z4xaVa>880#4|L`qt2T}~_7onfWtYFA?!fIzg3~$(l{OWLJ!r3%*Zm^ypmr<nuBPk$ zOsz~!yvnE3>8X_>!(ePdk(K3OEGtma;M{CpD{h;dHdY-DdOF(HA*`Vp(<x|)wc3ac zv=&GD!bNvj{H*01c48SFM)#Xs3qnpc^bEYWbkbvridxo&#!`z*ahA!6nNK9nVI>!J zb#iWXz4P#=xp<WMs3Q5q1qB6gTJu;I%B&O98C#mu`LzZ@^^by#tZl5{;7sMIKgpvH zsmFqGJ!s*aeDadvByj$TJp-e`Y~3vRGZ1S=WOi~YBu{3mr$xf;qEu=deI%>Wo)o{T zftTRUDby}xIvbUhhQp+koPG?y!A7B;o13?YnA1GQ2d!aGO7Z2pmzK&x%FzqeO3gH4 zq+N$?;z~IMTrOEs3IcoK4b}=Hi*(PmAxX={r3*CTS>|{ZwbO2v@+tyE$0@nQv>@N> zJ4qH!E!qw#rL^E>o5zn>D$36UbMujm!rWUgc(P~}ikM9G<p%cTxe_?-F7UBTuuimx z6lWUiLMzp|<g})03ejFAGe4h*9L%%kJ-?71Sfth%n$w3lum3T|iK)#jtvJ;&@8b-6 zDjEJ7iw+x7bI@WRH>_A9wbq2!qXj~<q45sql$>L@tddZ*<jwO-9VW`l!+5i5vcBlm zB5Bp|$!*sZ_YA0*S*!1Ir8_eU4IBoW7e2;tXNs(uFkSMFUH@7Yr|{9GP7xzd-Y9U? zvG>_$lUX&%o0TW*6gMInh=gCGh`z!&!rTY!hlW;8S@BHA+b5G52&!1u>c@d{-t-e{ z9AF!z>oP>4vOk~WPQvXwtat%a?|H-9JWoYp(V7)Wuuft&U%I1zp>p3Q-`{vlXark( za$y!%z+3QYSXn$^L(>vp_=)mppia4bC32rDHMoUH14EsNSEG95r7M~fEcnFEJEYtv z>CL3DjjAjzCy~)k;)(FLfv0nz*`u{vu3$`p6Idd#-VH9cbvZN6Lu<f7LLJk_htOgE z$TYLNz>#fB7v}Av$jqAlF+IICd|5fXmd%_LP9m{JPWyxt6dmw8%VGw*FzaVmv`U}^ znks+L$lH~wta!okCVSFQb<uOwt+mE0GMZ(Ujms-oqXd`8x~7*Uhw!o>JI#KI6GG-? z>J7Ck?sM38Gs?G<B^KC@%$JL*QXAw8W;>=cygW|#KO_&hAP!$Sq6eDD<Oawt6`aqF zjc;^`Ks_twcL8H6KvU{_#toCJ#?T)FSL~3O6ER`Nb;gvh%9N4}m_d^I$4I^~tQl_x zn3BhvUPT9^7lj;v!K%d|srjmcekp^=sp}N(8Gf+;q7W55d$qb0MI(Ec{t}yR1O8T0 zonNU4`#`$Av`BMRVyDc^iR!b*JaN=5?>^v8wdOXpHW~q!?aI4L!Exo-hmGOcbSkae zwS4pYrmu2Kqs!K3;-;IxiZ2UNPor`1W+gs#z~9jsjimbVjFI|)?nPQSGC*^QpSHhN z-EMj6a?PSRPC*uhjo7lATX@|SAodMf3h^Cz@;Tby4TgB>^OpiytKXA_sl><TaTmIk z`xGwZvxw-fmqxw*{Hf0Jox22>!-pulvLO?uJE=3hhJI1eN&g-v-UMS2o`I+y!p<;r zj6v&y-hMNAgrL|5!rWc3H~8Y!F_tF~GF>|7)y_9i`DAP-VfVTv6{pCu9$fK)Ej!f0 zDq-Z5T8oIr_Hm3x<P#p=GwcL{7af;NM{jch*d<V^3A7$_1+@WRLz&Kd{PCk@xFSgs zH|%r69OSC#9V51u@Ox^uH;fZ}O*@zqtw!IRau$rfG35vuf?Se!R0)<sDOU=fV4Mb7 zN4fM(>M3^Wc~yrzxy1eyPMr#)J%xEwpgvB3j<5Qj4-K?}8(u)Es`q-Vu(Dh)MD%9p zg8JLD@xISVaHRg0gT&on#Ki#GDTYH7#SU)0ab3b_NU(5FT&*ojx=rqQjk+RDRVoLu zdH@gGGc;8~c2Jc|5HazNh$#u)VGf+=x*@7scDx?}_Hm9T0}5ZdB!?jgdFy<0#8KFA z<u!3c4@Oqx4zfmta1=9Lb)dl7b36=i5v048PTlk@alVb2b-C8gcwpN|Cd`00tkiDX zDXqC%!_ewXXRgg4Lf7J~o43*z84avwcSdYyJcT=>3|beUf4XF4en2c_bDm!RNmI}3 z;&Bj3Hx2*0SM(;(uU5d>r^n3Im^Rg)1ugd!Y-n_z<M2M`Cd*|d?9xeY!gqg8a@gmZ z+;tu}r6|wZ<agkaj?Vl=P+6Yfslp9=gWEbaE-G*)@{C=NTT~BjMpY|kl@Z98Cqkf3 z**#{;?FhP_+fENP&haqfks(5@Nb9{hi|Kyvs`<HUmY8?@=m*>U8RF33+1&R^H(|$% zPEzbnETmMGMHQCiANf<Cr{xw}nsXsFtwHyV5Wnfc4QpnvKC^6Un*&8b-Ym;-#s&?h zca(VYa8aM0%*3qNikNxUO$+!4Z|o3RaR%?!wL<?7dhfaVIFxWp*iz=R8W)8XMHc9d ztN@W!L98kA=UZPp->3uUKC;*A_%VTpWe!d=x1K)t>k_jsL2i!7e1gr2PsM!?5zrdW z?b3Wo_e#CNO^0UqgUi7$hE5QN7zkwzZ7PSzLn%@7SeYdR4TuZ|YXb-i>#>`CLb11p z>9SHlo8P{<06#0X0hwXW-@Yqh5DSJ)>{EP3Z^P-Aq(>GVYwr}}hOLnuHN6^?*UIb2 zhCODiSPMisdxhZ4XI1N~(A2U0q@wVvNL1qOnco!KY8=aJ1^lK!Ka*|1$~scp63~7G zfjkr8c$jSU8QJP>==#zc9d6!CgKur+kUP2zNV_8}*!h@GnMEXeo#Q+m4X4|-nl*Pv zq6ypFnJOE8a81$44QXv=l{b#U_2BNbjD5JagT=k(L+!!<^YXQITlYL38wyg88YRPe zQD<_U{n#Oh50AXEr21wNy>sfzjrS(#`Xg;@Qj(C7MGoDbQq)F-pRU1;yD-{QB^V$s z5cVhI2H13x3QE1fMg)dTGW_J=AOf#W5<ZY|fYGOD{`y01ikaY7a@OFTS$BG50Kk|4 z0AK=#O+5yuFcGjk=!E@+TIgqUWQS(h|H-^T1O55u%JYvz0i!z8f|oa;;ge7gFd6@; zg5LA|?@++D&dgwpg}-XS%nRtmGN`}N+?%tT+FG&yZ4Nx*Oa!)FKnA*?f*st5z~7yT zp$qHK*1_U}YZhpLKhUAYBL5bVEYbk0aKKdgq+r8EGH9q~rZ*8(_g`0@zbxKERr&%R zv}yv1Ex>;$XxPAp7SJxy0QX6u1vFq#Aj1DNc<0KhQwjP_w-X5f5c)?a^q%KGOZFgS z9Yl=#-(G5ReVz$ES;7Z;Q9WSL!?3}k%kXr+`VoP-^YM46T2~YRK===}_KzP#qL!(C zgCE-+V=F<UppKx~b7lX4_c1)cFPE8rg9{g;C?P|av^}r@0Fgi7F3b;bn-%Kc;H4rk z>v>S^-=LH#e>yYA^#Gq)`Q4ciW8jMtD7+U6|5N)c4;0P_=Fh+fcdf&t|7tF34cHj` zdKDkI$p3&4$-?}fo=#!u+$e+r0CJ(-!vBZU`$7*wD!Euc)&AzV01N$oG1QX=Xb|qt z5&6%R=f5ig72)|G8^5UK|LgjOI8=ZgtX%ZJj{U*!{f`OgJ<oqi3MxbcW-tA(V}I~G z{~^L4`ydifPX3>^{Nj3sZbSSb@=^gRLJehpMuiU7rS9K{Hk=_CW|$i7FWQQKW{ATE z4G`N5TEPY;U-}u$j6V9i46g<Fa6=MW%(+PeM79E7j|u%Vlc4jK@h4Z$Ul%6eKw`=I zk2(6l-1D~`DENW7=NA~w=6}Ke^7#CBj{KL$=O3%k`TBpV`JL4V^ariae=Yo%737x% z4Tt~3(f=<;$bTt9{<8Jk7T;ea5B^hlz&%HBwG|$eAAt0KhTks=0RVvYA9tYlJpWVY zzlDC13jF+>nWt%hvYyannB-vlX|&(Q{GUm*e<{iHXM6*NEBpril^GYBT=N$aYOdb* zK{MMY^55Wp=HdK>&-2fJ3x)s8%K6i?^iMQE@+9#4PXf?~Tj&FN@`LZAl$8IBBWU<M z4G=FA>_5W;#bC_R0OztFFbcDHzZv`$KMw#<|FQ@5uP5gLJ|>O;ji^WeP2}HjQ0Tko z&mQD2`d8$5mgqN;9gg3k_WrQ)z2t8Zw0|Af`%DAG?|UeY`;7gYmWM4|=-cTC`nvh^ z?bQ9@0WNNU2HyYtdw>41vG|AKg2BH<aQ-!HGDibE9DgWoeL?m=Bj?wG>wnvQ{|PEY u3cjEFz0H3w3PIO|004$ROjpc7;Y|2XmEfQ~__HbefOH%HU}@v$)Bghlt6}c| delta 38942 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b7c8c5dbf..66c01cfeb 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 2fe81a7d9..fcb6fca14 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 62bd9b9cc..6689b85be 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,103 +1,92 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega From 81a9c537afe8492675eb253968939364d65db091 Mon Sep 17 00:00:00 2001 From: aureliony <39163684+aureliony@users.noreply.github.com> Date: Tue, 16 Jul 2024 23:35:06 +0800 Subject: [PATCH 03/76] build.gradle: Prevent generating a second JAR file In build.gradle, the dependencies on distZip and/or distTar causes the shadowJar task to generate a second JAR file for which the mainClass.set("seedu.duke.Duke") does not take effect. Hence, this additional JAR file cannot be run. For this product, there is no need to generate a second JAR file to begin with. Let's remove this dependency from the build.gradle to prevent the shadowJar task from generating the extra JAR file. --- build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/build.gradle b/build.gradle index a388517ae..c361f9811 100644 --- a/build.gradle +++ b/build.gradle @@ -34,7 +34,6 @@ application { shadowJar { archiveBaseName = "duke" archiveClassifier = null - dependsOn("distZip", "distTar") } run{ From c671da2c799ed91d898b9d867a193c8b02fff239 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Thu, 22 Aug 2024 22:46:55 +0800 Subject: [PATCH 04/76] Restore reverse commit files --- build.gradle | 41 ---- gradle/wrapper/gradle-wrapper.jar | Bin 63375 -> 0 bytes gradle/wrapper/gradle-wrapper.properties | 7 - gradlew | 248 ----------------------- gradlew.bat | 92 --------- 5 files changed, 388 deletions(-) delete mode 100644 build.gradle delete mode 100644 gradle/wrapper/gradle-wrapper.jar delete mode 100644 gradle/wrapper/gradle-wrapper.properties delete mode 100755 gradlew delete mode 100644 gradlew.bat diff --git a/build.gradle b/build.gradle deleted file mode 100644 index c361f9811..000000000 --- a/build.gradle +++ /dev/null @@ -1,41 +0,0 @@ -plugins { - id 'java' - id 'application' - id 'com.github.johnrengelman.shadow' version '7.1.2' -} - -repositories { - mavenCentral() -} - -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' -} - -test { - useJUnitPlatform() - - testLogging { - events "passed", "skipped", "failed" - - showExceptions true - exceptionFormat "full" - showCauses true - showStackTraces true - showStandardStreams = false - } -} - -application { - mainClass.set("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 deleted file mode 100644 index 033e24c4cdf41af1ab109bc7f253b2b887023340..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63375 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≫L+crb^Bz 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 E0aA=+Q2+n{ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index 66c01cfeb..000000000 --- a/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -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 deleted file mode 100755 index fcb6fca14..000000000 --- a/gradlew +++ /dev/null @@ -1,248 +0,0 @@ -#!/bin/sh - -# -# 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. -# 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 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 -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 - -# 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 - -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 ;; #( - 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 - 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 - 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" && ! "$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 - -# 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" || "$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 - 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 - # 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 -fi - - -# 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 deleted file mode 100644 index 6689b85be..000000000 --- a/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@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 0e4f6ac73da0f3f6028ce13cf36adbf9c106be3d Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Thu, 22 Aug 2024 22:51:42 +0800 Subject: [PATCH 05/76] Chatbot: rename Duke to Mel Remove all traces of Duke from the source code. Rename Duke.java to Mel.java. Replace Duke with Mel in Mel.java and README.md. Ensure chatbot name consistency. --- docs/README.md | 2 +- src/main/java/Duke.java | 10 ---------- src/main/java/Mel.java | 11 +++++++++++ 3 files changed, 12 insertions(+), 11 deletions(-) delete mode 100644 src/main/java/Duke.java create mode 100644 src/main/java/Mel.java diff --git a/docs/README.md b/docs/README.md index 47b9f984f..d35be9c22 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,4 +1,4 @@ -# Duke User Guide +# Mel User Guide // Update the title above to match the actual product name diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java deleted file mode 100644 index 5d313334c..000000000 --- a/src/main/java/Duke.java +++ /dev/null @@ -1,10 +0,0 @@ -public class Duke { - public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); - } -} diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java new file mode 100644 index 000000000..36aaa8dfa --- /dev/null +++ b/src/main/java/Mel.java @@ -0,0 +1,11 @@ +public class Mel { + public static void main(String[] args) { + System.out.println("________________________________________"); + System.out.println("Hello! I'm Mel"); + System.out.println("What can I do for you?"); + System.out.println("________________________________________"); + System.out.println("Bye. Hope to see you again soon!"); + System.out.println("________________________________________"); + + } +} From 06ecd084ab8f00f4403b8fd8f4044a12f2a6ce89 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Wed, 28 Aug 2024 13:11:28 +0800 Subject: [PATCH 06/76] Chatbot: add echo --- src/main/java/Mel.java | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index 36aaa8dfa..8cca745e8 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -1,11 +1,28 @@ +import java.util.Scanner; + public class Mel { public static void main(String[] args) { System.out.println("________________________________________"); System.out.println("Hello! I'm Mel"); System.out.println("What can I do for you?"); System.out.println("________________________________________"); - System.out.println("Bye. Hope to see you again soon!"); - System.out.println("________________________________________"); + String line; + Scanner in = new Scanner(System.in); + + while (true) { + line = in.nextLine(); + System.out.println("________________________________________"); + + + if (line.equals("bye")) { + System.out.println("Bye. Hope to see you again soon!"); + System.out.println("________________________________________"); + break; + } else { + System.out.println(line); + System.out.println("________________________________________"); + } + } } } From 250b0010a275ddfb5525f1204d55cfaf9c75e2f7 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Wed, 28 Aug 2024 19:29:03 +0800 Subject: [PATCH 07/76] Chatbot: add indentation --- src/main/java/Mel.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index 8cca745e8..acb1ba19f 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -2,26 +2,26 @@ public class Mel { public static void main(String[] args) { - System.out.println("________________________________________"); - System.out.println("Hello! I'm Mel"); - System.out.println("What can I do for you?"); - System.out.println("________________________________________"); + System.out.println("\t________________________________________"); + System.out.println("\tHello! I'm Mel"); + System.out.println("\tWhat can I do for you?"); + System.out.println("\t________________________________________"); String line; Scanner in = new Scanner(System.in); while (true) { line = in.nextLine(); - System.out.println("________________________________________"); + System.out.println("\t________________________________________"); if (line.equals("bye")) { - System.out.println("Bye. Hope to see you again soon!"); - System.out.println("________________________________________"); + System.out.println("\tBye. Hope to see you again soon!"); + System.out.println("\t________________________________________"); break; } else { - System.out.println(line); - System.out.println("________________________________________"); + System.out.println("\t" + line); + System.out.println("\t________________________________________"); } } } From a6b13997f98b2e15f26ee2fde2c382e3f95f34a2 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Wed, 28 Aug 2024 20:01:24 +0800 Subject: [PATCH 08/76] List class: implement add item and print full list function The chatbot cannot store and list user-entered text. Create class to store entered text and display them to user when requested. No disk storage used due to focus on temporary session-based interactions. --- src/main/java/List.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/main/java/List.java diff --git a/src/main/java/List.java b/src/main/java/List.java new file mode 100644 index 000000000..628beb928 --- /dev/null +++ b/src/main/java/List.java @@ -0,0 +1,19 @@ +public class List { + private int numItems; + private String[] itemList = new String[100]; + + public List() { + numItems = 0; + } + + public void addItem(String item) { + itemList[numItems] = item; + numItems += 1; + } + + public void printList() { + for (int i = 0; i < numItems; i++) { + System.out.println("\t" + (i + 1) + ". " + itemList[i]); + } + } +} From 22b8ba245408aabb29213a256be256f18aabdb8a Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Wed, 28 Aug 2024 20:03:09 +0800 Subject: [PATCH 09/76] Chatbot: store text and print list function Use List class to store user text and print list when requested. --- src/main/java/Mel.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index acb1ba19f..514eb6b13 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -9,6 +9,7 @@ public static void main(String[] args) { String line; Scanner in = new Scanner(System.in); + List userList = new List(); while (true) { line = in.nextLine(); @@ -19,9 +20,14 @@ public static void main(String[] args) { System.out.println("\tBye. Hope to see you again soon!"); System.out.println("\t________________________________________"); break; - } else { - System.out.println("\t" + line); + } else if (line.equals("list")) { + userList.printList(); System.out.println("\t________________________________________"); + + } else { + System.out.println("\t" + "added: " + line); + System.out.println("\t________________________________________"); + userList.addItem(line); } } } From be711897198592cfdafd160d26674b769f97ecfc Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Wed, 28 Aug 2024 23:09:51 +0800 Subject: [PATCH 10/76] Task class: add class Task are strings in an array in List class. Incorporating additional information such as isDone status will be increasingly complex. Let's create a new Task class to contain task related attributes and methods. This is a more natural representation of the tasks. --- src/main/java/Task.java | 21 +++++++++++++++++++++ 1 file changed, 21 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 000000000..b76731574 --- /dev/null +++ b/src/main/java/Task.java @@ -0,0 +1,21 @@ +public class Task { + protected String description; + protected boolean isDone; + + public Task(String description) { + this.description = description; + this.isDone = false; + } + + public String getStatusIcon() { + return (isDone ? "X" : " "); // mark done task with X + } + + public void markAsDone() { + isDone = true; + } + + public void markAsUnDone() { + isDone = false; + } +} \ No newline at end of file From 0f5d58b4f926a774c25db8e1d92b7572376da64c Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Wed, 28 Aug 2024 23:11:20 +0800 Subject: [PATCH 11/76] List class: mark and unmark tasks in list as done --- src/main/java/List.java | 49 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 3 deletions(-) diff --git a/src/main/java/List.java b/src/main/java/List.java index 628beb928..1e91b3572 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -1,19 +1,62 @@ public class List { private int numItems; - private String[] itemList = new String[100]; + private Task[] itemList = new Task[100]; public List() { numItems = 0; } + public int getNumItems() { + return numItems; + } + public void addItem(String item) { - itemList[numItems] = item; + itemList[numItems] = new Task(item); numItems += 1; } public void printList() { + System.out.println("\tHere are the tasks in your list:"); for (int i = 0; i < numItems; i++) { - System.out.println("\t" + (i + 1) + ". " + itemList[i]); + System.out.println("\t" + (i + 1) + ".[" + itemList[i].getStatusIcon() + "] " + itemList[i].description); + } + } + + public void markItem(String line) { + int itemNum = Integer.parseInt(line.substring(5)); + if (itemNum > this.getNumItems() || itemNum <= 0) { + System.out.println("Input item number out of range."); + } else { + this.markListItemAsDone(itemNum); + System.out.println("\tNice! I've marked this task as done:"); + System.out.println("\t\t[" + this.itemGetStatusIcon(itemNum) + "] " + this.getItemDescription(itemNum)); + } + } + + public void unmarkItem(String line) { + int itemNum = Integer.parseInt(line.substring(7)); + if (itemNum > this.getNumItems() || itemNum <= 0) { + System.out.println("Input item number out of range."); + } else { + this.markListItemAsUnDone(itemNum); + System.out.println("\tOK, I've marked this task as not done yet:"); + System.out.println("\t\t[" + this.itemGetStatusIcon(itemNum) + "] " + this.getItemDescription(itemNum)); } } + + public String getItemDescription(int itemNum) { + return itemList[itemNum - 1].description; + } + + public void markListItemAsDone(int itemNum) { + itemList[itemNum - 1].markAsDone(); + } + + public void markListItemAsUnDone(int itemNum) { + itemList[itemNum - 1].markAsUnDone(); + } + + public String itemGetStatusIcon(int itemNum) { + return itemList[itemNum - 1].getStatusIcon(); + } } From 86a1b525bdebd08f2cbebb210b7cd377d45dbbba Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Wed, 28 Aug 2024 23:12:10 +0800 Subject: [PATCH 12/76] Chatbot: use List class function to mark and unmark tasks as done --- src/main/java/Mel.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index 514eb6b13..a95ea2d99 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -12,6 +12,7 @@ public static void main(String[] args) { List userList = new List(); while (true) { + System.out.print(System.lineSeparator()); line = in.nextLine(); System.out.println("\t________________________________________"); @@ -23,7 +24,12 @@ public static void main(String[] args) { } else if (line.equals("list")) { userList.printList(); System.out.println("\t________________________________________"); - + } else if (line.substring(0, 4).equals("mark")) { + userList.markItem(line); + System.out.println("\t________________________________________"); + } else if (line.substring(0, 6).equals("unmark")) { + userList.unmarkItem(line); + System.out.println("\t________________________________________"); } else { System.out.println("\t" + "added: " + line); System.out.println("\t________________________________________"); From 907e5a9d109a7852bbb2c30a0ac68f0f520f834c Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Wed, 28 Aug 2024 23:34:07 +0800 Subject: [PATCH 13/76] Chatbot: Follow coding standard --- src/main/java/Mel.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index a95ea2d99..693d8e58b 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -16,24 +16,27 @@ public static void main(String[] args) { line = in.nextLine(); System.out.println("\t________________________________________"); - if (line.equals("bye")) { System.out.println("\tBye. Hope to see you again soon!"); System.out.println("\t________________________________________"); break; + } else if (line.equals("list")) { userList.printList(); System.out.println("\t________________________________________"); + } else if (line.substring(0, 4).equals("mark")) { userList.markItem(line); System.out.println("\t________________________________________"); + } else if (line.substring(0, 6).equals("unmark")) { userList.unmarkItem(line); System.out.println("\t________________________________________"); + } else { - System.out.println("\t" + "added: " + line); - System.out.println("\t________________________________________"); - userList.addItem(line); + System.out.println("\t" + "added: " + line); + System.out.println("\t________________________________________"); + userList.addItem(line); } } } From 1839a797d7ac7948589f5f55667e52753cd0e2bc Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Mon, 2 Sep 2024 23:49:04 +0800 Subject: [PATCH 14/76] Task class: rename getStatusIcon function to getDoneStatusIcon --- src/main/java/Task.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/Task.java b/src/main/java/Task.java index b76731574..024399514 100644 --- a/src/main/java/Task.java +++ b/src/main/java/Task.java @@ -7,7 +7,7 @@ public Task(String description) { this.isDone = false; } - public String getStatusIcon() { + public String getDoneStatusIcon() { return (isDone ? "X" : " "); // mark done task with X } From ba587a8236618036a0548cb38a7c6776bbfdc5e3 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Mon, 2 Sep 2024 23:51:15 +0800 Subject: [PATCH 15/76] Todo class: add class Todo extends Task class. Class overrides the toString method to print out special description of the Todo task. --- src/main/java/Todo.java | 10 ++++++++++ 1 file changed, 10 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 000000000..1d0e088a6 --- /dev/null +++ b/src/main/java/Todo.java @@ -0,0 +1,10 @@ +public class Todo extends Task { + public Todo(String description) { + super(description); + } + + @Override + public String toString() { + return ("[T][" + getDoneStatusIcon() + "] " + description); + } +} From e9a03bdb02988f95e7f62085b7fe02b1839c6696 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Mon, 2 Sep 2024 23:53:16 +0800 Subject: [PATCH 16/76] Deadline class: add class Deadline extends Task class. On top of the description attribute in Task, it also contains the String by attribute to store the deadline as a string. Class overrides the toString method to print out special description of the Deadline task. --- src/main/java/Deadline.java | 15 +++++++++++++++ 1 file changed, 15 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 000000000..531ce45c3 --- /dev/null +++ b/src/main/java/Deadline.java @@ -0,0 +1,15 @@ +public class Deadline extends Task { + + protected String by; + + public Deadline(String description, String by) { + super(description); + this.by = by; + } + + @Override + public String toString() { + return ("[D][" + getDoneStatusIcon() + "] " + description + " (by: " + by + ")"); + } + +} From d6e75cba2fb72f1f0c710c98771b252f820afdfc Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Mon, 2 Sep 2024 23:54:34 +0800 Subject: [PATCH 17/76] Event class: add class Event extends Task class. On top of the description attribute in Task, it also contains the String startDate and String endDate attributes to store the start and end date or timings of the event. Class overrides the toString method to print out special description of the Event task. --- src/main/java/Event.java | 15 +++++++++++++++ 1 file changed, 15 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 000000000..1b08bdff7 --- /dev/null +++ b/src/main/java/Event.java @@ -0,0 +1,15 @@ +public class Event extends Task { + protected String startDate; + protected String endDate; + + public Event(String description, String startDate, String endDate) { + super(description); + this.startDate = startDate; + this.endDate = endDate; + } + + @Override + public String toString() { + return ("[E][" + getDoneStatusIcon() + "] " + description + " (from: " + startDate + " to: " + endDate + ")"); + } +} From 4e31adb43414d615cf14e74f20d934ff186ca1e7 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Mon, 2 Sep 2024 23:57:06 +0800 Subject: [PATCH 18/76] List class: modify addItem method Modify addItem method to add Todo, Deadline, and Event class objects into the list of Tasks. --- src/main/java/List.java | 133 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 124 insertions(+), 9 deletions(-) diff --git a/src/main/java/List.java b/src/main/java/List.java index 1e91b3572..16dbc4955 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -1,4 +1,7 @@ public class List { + public static final String INVALID_EVENT_INPUT_MESSAGE = "event <event name> /from <start date/time> /end <end date/time>"; + public static final String INVALID_DEADLINE_INPUT_MESSAGE = "deadline <deadline name> /by <deadline>"; + public static final String INVALID_TODO_INPUT_MESSAGE = "todo <task name>"; private int numItems; private Task[] itemList = new Task[100]; @@ -10,37 +13,149 @@ public int getNumItems() { return numItems; } - public void addItem(String item) { - itemList[numItems] = new Task(item); + public void addItem(String line) { + if (line.length() >= 7 && line.substring(0, 5).equals("event")) { + if (line.contains("/from") && line.contains("/to")) { + addEvent(line); + } else { + System.out.println("\tInvalid command format: " + System.lineSeparator() + "\t\t" + + INVALID_EVENT_INPUT_MESSAGE); + } + } else if (line.length() >= 10 && line.substring(0, 8).equals("deadline")) { + if (line.contains("/by")) { + addDeadline(line); + } else { + System.out.println("\tInvalid command format: " + System.lineSeparator() + "\t\t" + + INVALID_DEADLINE_INPUT_MESSAGE); + } + } else if (line.length() >= 6 && line.substring(0, 4).equals("todo")){ + addTodo(line); + } else { + System.out.println("\tInvalid command format: " + System.lineSeparator() + "\t\t" + INVALID_TODO_INPUT_MESSAGE + + System.lineSeparator() + "\t\t" + INVALID_DEADLINE_INPUT_MESSAGE + System.lineSeparator() + "\t\t" + + INVALID_EVENT_INPUT_MESSAGE); + } + } + + private void addEvent(String line) { + String eventStartDate = extractEventStartDate(line); + String eventEndDate = extractEventEndDate(line); + String eventDescription = extractEventDescription(line); + itemList[numItems] = new Event(eventDescription, eventStartDate, eventEndDate); + outputAddedMessage(itemList[numItems]); + numItems += 1; + } + + private void addTodo(String line) { + String todoDescription = extractTodoDescription(line); + itemList[numItems] = new Todo(todoDescription); + outputAddedMessage(itemList[numItems]); + numItems += 1; + } + + private void addDeadline(String line) { + String deadlineDate = extractDeadlineDate(line); + String deadlineDescription = extractDeadlineDescription(line); + itemList[numItems] = new Deadline(deadlineDescription, deadlineDate); + outputAddedMessage(itemList[numItems]); numItems += 1; } + private void outputAddedMessage(Task task) { + System.out.println("\tGot it. I've added this task: "); + System.out.println("\t " + task); + System.out.println("\tNow you have " + (numItems+1) + " tasks in the list."); + } + + private String extractTodoDescription(String line) { + String todoDescription; + todoDescription = line.trim().replace("todo ", ""); + + return todoDescription; + } + + private String extractDeadlineDescription(String line) { + String deadlineDescription; + final int indexOfDeadlinePrefix = line.indexOf("/by"); + deadlineDescription = line.substring(0, indexOfDeadlinePrefix).trim().replace("deadline ", ""); + + return deadlineDescription; + } + + private String extractDeadlineDate(String line) { + String deadlineDate; + final int indexOfDeadlinePrefix = line.indexOf("/by"); + deadlineDate = line.substring(indexOfDeadlinePrefix).trim().replace("/by ", ""); + + return deadlineDate; + } + + private String extractEventDescription(String line) { + String eventDescription; + final int indexOfStartDatePrefix = line.indexOf("/from"); + final int indexOfEndDatePrefix = line.indexOf("/to"); + if (indexOfEndDatePrefix > indexOfStartDatePrefix) { + eventDescription = line.substring(0, indexOfStartDatePrefix).trim().replace("event ", ""); + } else { + eventDescription = line.substring(0, indexOfEndDatePrefix).trim().replace("event ", ""); + } + + return eventDescription; + } + + private String extractEventEndDate(String line) { + String eventEndDate; + final int indexOfStartDatePrefix = line.indexOf("/from"); + final int indexOfEndDatePrefix = line.indexOf("/to"); + if (indexOfEndDatePrefix > indexOfStartDatePrefix) { + eventEndDate = line.substring(indexOfEndDatePrefix).trim().replace("/to ", ""); + } else { + eventEndDate = line.substring(indexOfEndDatePrefix, indexOfStartDatePrefix).trim().replace("/to ", ""); + } + + return eventEndDate; + } + + private String extractEventStartDate(String line) { + String eventStartDate; + final int indexOfStartDatePrefix = line.indexOf("/from"); + final int indexOfEndDatePrefix = line.indexOf("/to"); + if (indexOfStartDatePrefix > indexOfEndDatePrefix) { + eventStartDate = line.substring(indexOfStartDatePrefix).trim().replace("/from ", ""); + } else { + eventStartDate = line.substring(indexOfStartDatePrefix, indexOfEndDatePrefix).trim().replace("/from ", ""); + } + + return eventStartDate; + } + public void printList() { System.out.println("\tHere are the tasks in your list:"); for (int i = 0; i < numItems; i++) { - System.out.println("\t" + (i + 1) + ".[" + itemList[i].getStatusIcon() + "] " + itemList[i].description); + //System.out.println("\t" + (i + 1) + ".[" + itemList[i].getTaskTypeIcon() + "][" + itemList[i].getDoneStatusIcon() + "] " + itemList[i].description); + System.out.println("\t" + (i + 1) + "." + itemList[i]); } } public void markItem(String line) { int itemNum = Integer.parseInt(line.substring(5)); if (itemNum > this.getNumItems() || itemNum <= 0) { - System.out.println("Input item number out of range."); + System.out.println("\tInput item number out of range."); } else { this.markListItemAsDone(itemNum); System.out.println("\tNice! I've marked this task as done:"); - System.out.println("\t\t[" + this.itemGetStatusIcon(itemNum) + "] " + this.getItemDescription(itemNum)); + System.out.println("\t\t[" + this.itemGetDoneStatusIcon(itemNum) + "] " + this.getItemDescription(itemNum)); } } public void unmarkItem(String line) { int itemNum = Integer.parseInt(line.substring(7)); if (itemNum > this.getNumItems() || itemNum <= 0) { - System.out.println("Input item number out of range."); + System.out.println("\tInput item number out of range."); } else { this.markListItemAsUnDone(itemNum); System.out.println("\tOK, I've marked this task as not done yet:"); - System.out.println("\t\t[" + this.itemGetStatusIcon(itemNum) + "] " + this.getItemDescription(itemNum)); + System.out.println("\t\t[" + this.itemGetDoneStatusIcon(itemNum) + "] " + this.getItemDescription(itemNum)); } } @@ -56,7 +171,7 @@ public void markListItemAsUnDone(int itemNum) { itemList[itemNum - 1].markAsUnDone(); } - public String itemGetStatusIcon(int itemNum) { - return itemList[itemNum - 1].getStatusIcon(); + public String itemGetDoneStatusIcon(int itemNum) { + return itemList[itemNum - 1].getDoneStatusIcon(); } } From 100da0c762524a112af2a4014fa8668ff156846a Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Mon, 2 Sep 2024 23:58:10 +0800 Subject: [PATCH 19/76] Mel: Refactor line prints --- src/main/java/Mel.java | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index 693d8e58b..d4ea0f81c 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -1,6 +1,9 @@ import java.util.Scanner; public class Mel { + + public static final String DRAW_HORIZONTAL_LINE = "\t________________________________________"; + public static void main(String[] args) { System.out.println("\t________________________________________"); System.out.println("\tHello! I'm Mel"); @@ -14,29 +17,28 @@ public static void main(String[] args) { while (true) { System.out.print(System.lineSeparator()); line = in.nextLine(); - System.out.println("\t________________________________________"); + System.out.println(DRAW_HORIZONTAL_LINE); if (line.equals("bye")) { System.out.println("\tBye. Hope to see you again soon!"); - System.out.println("\t________________________________________"); + System.out.println(DRAW_HORIZONTAL_LINE); break; } else if (line.equals("list")) { userList.printList(); - System.out.println("\t________________________________________"); + System.out.println(DRAW_HORIZONTAL_LINE); - } else if (line.substring(0, 4).equals("mark")) { + } else if (line.length() >= 6 && line.substring(0, 4).equals("mark")) { userList.markItem(line); - System.out.println("\t________________________________________"); + System.out.println(DRAW_HORIZONTAL_LINE); - } else if (line.substring(0, 6).equals("unmark")) { + } else if (line.length() >= 8 && line.substring(0, 6).equals("unmark")) { userList.unmarkItem(line); - System.out.println("\t________________________________________"); + System.out.println(DRAW_HORIZONTAL_LINE); } else { - System.out.println("\t" + "added: " + line); - System.out.println("\t________________________________________"); userList.addItem(line); + System.out.println(DRAW_HORIZONTAL_LINE); } } } From 3a22ebed8f8b72cad8cddefe2adc983739fa1ba5 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 3 Sep 2024 22:44:49 +0800 Subject: [PATCH 20/76] Refactor List.java and Mel.java --- src/main/java/List.java | 41 ++++++++++++++++++++++--------- src/main/java/Mel.java | 53 +++++++++++++++++++++++++++++------------ 2 files changed, 68 insertions(+), 26 deletions(-) diff --git a/src/main/java/List.java b/src/main/java/List.java index 16dbc4955..c668f29d9 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -2,6 +2,13 @@ public class List { public static final String INVALID_EVENT_INPUT_MESSAGE = "event <event name> /from <start date/time> /end <end date/time>"; public static final String INVALID_DEADLINE_INPUT_MESSAGE = "deadline <deadline name> /by <deadline>"; public static final String INVALID_TODO_INPUT_MESSAGE = "todo <task name>"; + public static final int DEADLINE_WORD_LEN = 8; + public static final int INPUT_SPACE_BUFFER = 2; + public static final int TODO_WORD_LEN = 4; + public static final String DEADLINE_BY_KEYWORD = "/by"; + public static final String EVENT_FROM_KEYWORD = "/from"; + public static final String EVENT_TO_KEYWORD = "/to"; + private int numItems; private Task[] itemList = new Task[100]; @@ -15,28 +22,40 @@ public int getNumItems() { public void addItem(String line) { if (line.length() >= 7 && line.substring(0, 5).equals("event")) { - if (line.contains("/from") && line.contains("/to")) { + if (line.contains(EVENT_FROM_KEYWORD) && line.contains(EVENT_TO_KEYWORD)) { addEvent(line); } else { - System.out.println("\tInvalid command format: " + System.lineSeparator() + "\t\t" + - INVALID_EVENT_INPUT_MESSAGE); + invalidEventMessage(); } - } else if (line.length() >= 10 && line.substring(0, 8).equals("deadline")) { - if (line.contains("/by")) { + } else if (line.length() >= (DEADLINE_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, DEADLINE_WORD_LEN).equals("deadline")) { + if (line.contains(DEADLINE_BY_KEYWORD)) { addDeadline(line); } else { - System.out.println("\tInvalid command format: " + System.lineSeparator() + "\t\t" + - INVALID_DEADLINE_INPUT_MESSAGE); + invalidDeadlineMessage(); } - } else if (line.length() >= 6 && line.substring(0, 4).equals("todo")){ + } else if (line.length() >= (TODO_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, TODO_WORD_LEN).equals("todo")){ addTodo(line); } else { - System.out.println("\tInvalid command format: " + System.lineSeparator() + "\t\t" + INVALID_TODO_INPUT_MESSAGE - + System.lineSeparator() + "\t\t" + INVALID_DEADLINE_INPUT_MESSAGE + System.lineSeparator() + "\t\t" - + INVALID_EVENT_INPUT_MESSAGE); + invalidTaskMessage(); } } + private static void invalidTaskMessage() { + System.out.println("\tInvalid command format: " + System.lineSeparator() + "\t\t" + INVALID_TODO_INPUT_MESSAGE + + System.lineSeparator() + "\t\t" + INVALID_DEADLINE_INPUT_MESSAGE + System.lineSeparator() + "\t\t" + + INVALID_EVENT_INPUT_MESSAGE); + } + + private static void invalidEventMessage() { + System.out.println("\tInvalid command format: " + System.lineSeparator() + "\t\t" + + INVALID_EVENT_INPUT_MESSAGE); + } + + private static void invalidDeadlineMessage() { + System.out.println("\tInvalid command format: " + System.lineSeparator() + "\t\t" + + INVALID_DEADLINE_INPUT_MESSAGE); + } + private void addEvent(String line) { String eventStartDate = extractEventStartDate(line); String eventEndDate = extractEventEndDate(line); diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index d4ea0f81c..4f1178fc8 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -3,43 +3,66 @@ public class Mel { public static final String DRAW_HORIZONTAL_LINE = "\t________________________________________"; + public static final int MARK_WORD_LEN = 4; + public static final int UNMARK_WORD_LEN = 6; + public static final int INPUT_SPACE_BUFFER = 2; public static void main(String[] args) { - System.out.println("\t________________________________________"); - System.out.println("\tHello! I'm Mel"); - System.out.println("\tWhat can I do for you?"); - System.out.println("\t________________________________________"); - + printIntroMessage(); + + // Set up scanner for user input String line; Scanner in = new Scanner(System.in); List userList = new List(); + getUserInput(in, userList); + } + + private static void getUserInput(Scanner in, List userList) { + String line; while (true) { - System.out.print(System.lineSeparator()); - line = in.nextLine(); - System.out.println(DRAW_HORIZONTAL_LINE); + line = getLine(in); if (line.equals("bye")) { System.out.println("\tBye. Hope to see you again soon!"); - System.out.println(DRAW_HORIZONTAL_LINE); + printHorizontalLine(); break; } else if (line.equals("list")) { userList.printList(); - System.out.println(DRAW_HORIZONTAL_LINE); + printHorizontalLine(); - } else if (line.length() >= 6 && line.substring(0, 4).equals("mark")) { + } else if (line.length() >= (MARK_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 4).equals("mark")) { userList.markItem(line); - System.out.println(DRAW_HORIZONTAL_LINE); + printHorizontalLine(); - } else if (line.length() >= 8 && line.substring(0, 6).equals("unmark")) { + } else if (line.length() >= (UNMARK_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 6).equals("unmark")) { userList.unmarkItem(line); - System.out.println(DRAW_HORIZONTAL_LINE); + printHorizontalLine(); } else { userList.addItem(line); - System.out.println(DRAW_HORIZONTAL_LINE); + printHorizontalLine(); } } } + + private static void printHorizontalLine() { + System.out.println(DRAW_HORIZONTAL_LINE); + } + + private static String getLine(Scanner in) { + String line; + System.out.print(System.lineSeparator()); + line = in.nextLine(); + printHorizontalLine(); + return line; + } + + private static void printIntroMessage() { + printHorizontalLine(); + System.out.println("\tHello! I'm Mel"); + System.out.println("\tWhat can I do for you?"); + printHorizontalLine(); + } } From 27dd19881439c226a469d274803d92307e8c2f5d Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 3 Sep 2024 23:09:07 +0800 Subject: [PATCH 21/76] List: Handle error for non-integer input index for mark and unmark --- src/main/java/List.java | 67 ++++++++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 21 deletions(-) diff --git a/src/main/java/List.java b/src/main/java/List.java index c668f29d9..b146a97b2 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -25,33 +25,33 @@ public void addItem(String line) { if (line.contains(EVENT_FROM_KEYWORD) && line.contains(EVENT_TO_KEYWORD)) { addEvent(line); } else { - invalidEventMessage(); + printInvalidEventMessage(); } } else if (line.length() >= (DEADLINE_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, DEADLINE_WORD_LEN).equals("deadline")) { if (line.contains(DEADLINE_BY_KEYWORD)) { addDeadline(line); } else { - invalidDeadlineMessage(); + printInvalidDeadlineMessage(); } } else if (line.length() >= (TODO_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, TODO_WORD_LEN).equals("todo")){ addTodo(line); } else { - invalidTaskMessage(); + printInvalidTaskMessage(); } } - private static void invalidTaskMessage() { + private static void printInvalidTaskMessage() { System.out.println("\tInvalid command format: " + System.lineSeparator() + "\t\t" + INVALID_TODO_INPUT_MESSAGE + System.lineSeparator() + "\t\t" + INVALID_DEADLINE_INPUT_MESSAGE + System.lineSeparator() + "\t\t" + INVALID_EVENT_INPUT_MESSAGE); } - private static void invalidEventMessage() { + private static void printInvalidEventMessage() { System.out.println("\tInvalid command format: " + System.lineSeparator() + "\t\t" + INVALID_EVENT_INPUT_MESSAGE); } - private static void invalidDeadlineMessage() { + private static void printInvalidDeadlineMessage() { System.out.println("\tInvalid command format: " + System.lineSeparator() + "\t\t" + INVALID_DEADLINE_INPUT_MESSAGE); } @@ -151,33 +151,58 @@ private String extractEventStartDate(String line) { public void printList() { System.out.println("\tHere are the tasks in your list:"); for (int i = 0; i < numItems; i++) { - //System.out.println("\t" + (i + 1) + ".[" + itemList[i].getTaskTypeIcon() + "][" + itemList[i].getDoneStatusIcon() + "] " + itemList[i].description); System.out.println("\t" + (i + 1) + "." + itemList[i]); } } public void markItem(String line) { - int itemNum = Integer.parseInt(line.substring(5)); - if (itemNum > this.getNumItems() || itemNum <= 0) { - System.out.println("\tInput item number out of range."); - } else { - this.markListItemAsDone(itemNum); - System.out.println("\tNice! I've marked this task as done:"); - System.out.println("\t\t[" + this.itemGetDoneStatusIcon(itemNum) + "] " + this.getItemDescription(itemNum)); + try { + int itemNum = Integer.parseInt(line.substring(5)); + + if (itemNum > this.getNumItems() || itemNum <= 0) { + printInputIndexOutOfRangeMessage(); + } else { + this.markListItemAsDone(itemNum); + printTaskMarkedMessage(itemNum); + } + } catch (Exception e) { + printInputIndexNotAnIntegerMessage(); } } + private void printTaskMarkedMessage(int itemNum) { + System.out.println("\tNice! I've marked this task as done:"); + System.out.println("\t " + itemList[itemNum -1]); + } + + private static void printInputIndexOutOfRangeMessage() { + System.out.println("\tInput index number out of range."); + } + public void unmarkItem(String line) { - int itemNum = Integer.parseInt(line.substring(7)); - if (itemNum > this.getNumItems() || itemNum <= 0) { - System.out.println("\tInput item number out of range."); - } else { - this.markListItemAsUnDone(itemNum); - System.out.println("\tOK, I've marked this task as not done yet:"); - System.out.println("\t\t[" + this.itemGetDoneStatusIcon(itemNum) + "] " + this.getItemDescription(itemNum)); + try { + int itemNum = Integer.parseInt(line.substring(7)); + + if (itemNum > this.getNumItems() || itemNum <= 0) { + printInputIndexOutOfRangeMessage(); + } else { + this.markListItemAsUnDone(itemNum); + printTaskUnmarkedMessage(itemNum); + } + } catch (Exception e) { + printInputIndexNotAnIntegerMessage(); } } + private void printTaskUnmarkedMessage(int itemNum) { + System.out.println("\tOK, I've marked this task as not done yet:"); + System.out.println("\t " + itemList[itemNum -1]); + } + + private static void printInputIndexNotAnIntegerMessage() { + System.out.println("\tInput index was not a integer."); + } + public String getItemDescription(int itemNum) { return itemList[itemNum - 1].description; } From 217305f9c5a49da523dd55ed8d9b09c212afabb6 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 3 Sep 2024 23:32:21 +0800 Subject: [PATCH 22/76] Implement automated text UI testing --- text-ui-test/EXPECTED.TXT | 102 +++++++++++++++++++++++++++++++++++--- text-ui-test/input.txt | 16 ++++++ text-ui-test/runtest.bat | 2 +- 3 files changed, 113 insertions(+), 7 deletions(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 657e74f6e..50d5c9462 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,7 +1,97 @@ -Hello from - ____ _ -| _ \ _ _| | _____ -| | | | | | | |/ / _ \ -| |_| | |_| | < __/ -|____/ \__,_|_|\_\___| + ________________________________________ + Hello! I'm Mel + What can I do for you? + ________________________________________ + ________________________________________ + Got it. I've added this task: + [T][ ] borrow book + Now you have 1 tasks in the list. + ________________________________________ + + ________________________________________ + Here are the tasks in your list: + 1.[T][ ] borrow book + ________________________________________ + + ________________________________________ + Got it. I've added this task: + [D][ ] return book (by: Sunday) + Now you have 2 tasks in the list. + ________________________________________ + + ________________________________________ + Here are the tasks in your list: + 1.[T][ ] borrow book + 2.[D][ ] return book (by: Sunday) + ________________________________________ + + ________________________________________ + Got it. I've added this task: + [E][ ] project meeting (from: Mon 2pm to: 4pm) + Now you have 3 tasks in the list. + ________________________________________ + + ________________________________________ + Here are the tasks in your list: + 1.[T][ ] borrow book + 2.[D][ ] return book (by: Sunday) + 3.[E][ ] project meeting (from: Mon 2pm to: 4pm) + ________________________________________ + + ________________________________________ + Nice! I've marked this task as done: + [T][X] borrow book + ________________________________________ + + ________________________________________ + Here are the tasks in your list: + 1.[T][X] borrow book + 2.[D][ ] return book (by: Sunday) + 3.[E][ ] project meeting (from: Mon 2pm to: 4pm) + ________________________________________ + + ________________________________________ + OK, I've marked this task as not done yet: + [T][ ] borrow book + ________________________________________ + + ________________________________________ + Here are the tasks in your list: + 1.[T][ ] borrow book + 2.[D][ ] return book (by: Sunday) + 3.[E][ ] project meeting (from: Mon 2pm to: 4pm) + ________________________________________ + + ________________________________________ + Input index was not a integer. + ________________________________________ + + ________________________________________ + Here are the tasks in your list: + 1.[T][ ] borrow book + 2.[D][ ] return book (by: Sunday) + 3.[E][ ] project meeting (from: Mon 2pm to: 4pm) + ________________________________________ + + ________________________________________ + Input index was not a integer. + ________________________________________ + + ________________________________________ + Here are the tasks in your list: + 1.[T][ ] borrow book + 2.[D][ ] return book (by: Sunday) + 3.[E][ ] project meeting (from: Mon 2pm to: 4pm) + ________________________________________ + + ________________________________________ + Invalid command format: + todo <task name> + deadline <deadline name> /by <deadline> + event <event name> /from <start date/time> /end <end date/time> + ________________________________________ + + ________________________________________ + Bye. Hope to see you again soon! + ________________________________________ diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index e69de29bb..175436d10 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -0,0 +1,16 @@ +todo borrow book +list +deadline return book /by Sunday +list +event project meeting /from Mon 2pm /to 4pm +list +mark 1 +list +unmark 1 +list +mark <non-int index> +list +unmark <non-int index> +list +<invalid input> +bye \ No newline at end of file diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat index 087374464..9d12d8b65 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 Mel < input.txt > ACTUAL.TXT REM compare the output to the expected output FC ACTUAL.TXT EXPECTED.TXT From 549b2e2242d4fd1b2295d2c0ae0ebfe9d8b21b15 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 3 Sep 2024 23:33:56 +0800 Subject: [PATCH 23/76] List class: remove trailing spaces --- src/main/java/List.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/List.java b/src/main/java/List.java index b146a97b2..09f08f4e7 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -41,18 +41,18 @@ public void addItem(String line) { } private static void printInvalidTaskMessage() { - System.out.println("\tInvalid command format: " + System.lineSeparator() + "\t\t" + INVALID_TODO_INPUT_MESSAGE + System.out.println("\tInvalid command format:" + System.lineSeparator() + "\t\t" + INVALID_TODO_INPUT_MESSAGE + System.lineSeparator() + "\t\t" + INVALID_DEADLINE_INPUT_MESSAGE + System.lineSeparator() + "\t\t" + INVALID_EVENT_INPUT_MESSAGE); } private static void printInvalidEventMessage() { - System.out.println("\tInvalid command format: " + System.lineSeparator() + "\t\t" + + System.out.println("\tInvalid command format:" + System.lineSeparator() + "\t\t" + INVALID_EVENT_INPUT_MESSAGE); } private static void printInvalidDeadlineMessage() { - System.out.println("\tInvalid command format: " + System.lineSeparator() + "\t\t" + + System.out.println("\tInvalid command format:" + System.lineSeparator() + "\t\t" + INVALID_DEADLINE_INPUT_MESSAGE); } @@ -81,7 +81,7 @@ private void addDeadline(String line) { } private void outputAddedMessage(Task task) { - System.out.println("\tGot it. I've added this task: "); + System.out.println("\tGot it. I've added this task:"); System.out.println("\t " + task); System.out.println("\tNow you have " + (numItems+1) + " tasks in the list."); } From eede78222d45f93424fd610eee05ad9e21787abf Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Thu, 5 Sep 2024 23:10:50 +0800 Subject: [PATCH 24/76] List: refactor addItem method for readability --- src/main/java/List.java | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/main/java/List.java b/src/main/java/List.java index 09f08f4e7..b16ee3b7c 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -2,9 +2,6 @@ public class List { public static final String INVALID_EVENT_INPUT_MESSAGE = "event <event name> /from <start date/time> /end <end date/time>"; public static final String INVALID_DEADLINE_INPUT_MESSAGE = "deadline <deadline name> /by <deadline>"; public static final String INVALID_TODO_INPUT_MESSAGE = "todo <task name>"; - public static final int DEADLINE_WORD_LEN = 8; - public static final int INPUT_SPACE_BUFFER = 2; - public static final int TODO_WORD_LEN = 4; public static final String DEADLINE_BY_KEYWORD = "/by"; public static final String EVENT_FROM_KEYWORD = "/from"; public static final String EVENT_TO_KEYWORD = "/to"; @@ -13,7 +10,7 @@ public class List { private Task[] itemList = new Task[100]; public List() { - numItems = 0; + this.numItems = 0; } public int getNumItems() { @@ -21,25 +18,31 @@ public int getNumItems() { } public void addItem(String line) { - if (line.length() >= 7 && line.substring(0, 5).equals("event")) { - if (line.contains(EVENT_FROM_KEYWORD) && line.contains(EVENT_TO_KEYWORD)) { - addEvent(line); - } else { - printInvalidEventMessage(); - } - } else if (line.length() >= (DEADLINE_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, DEADLINE_WORD_LEN).equals("deadline")) { - if (line.contains(DEADLINE_BY_KEYWORD)) { - addDeadline(line); - } else { - printInvalidDeadlineMessage(); - } - } else if (line.length() >= (TODO_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, TODO_WORD_LEN).equals("todo")){ + if (isValidEvent(line)) { + addEvent(line); + } else if (isValidDeadline(line)) { + addDeadline(line); + } else if (isTodo(line)) { addTodo(line); } else { printInvalidTaskMessage(); } } + private boolean isValidEvent(String line) { + return line.startsWith("event") && + line.contains(EVENT_FROM_KEYWORD) && + line.contains(EVENT_TO_KEYWORD); + } + + private boolean isValidDeadline(String line) { + return line.startsWith("deadline") && line.contains(DEADLINE_BY_KEYWORD); + } + + private boolean isTodo(String line) { + return line.startsWith("todo"); + } + private static void printInvalidTaskMessage() { System.out.println("\tInvalid command format:" + System.lineSeparator() + "\t\t" + INVALID_TODO_INPUT_MESSAGE + System.lineSeparator() + "\t\t" + INVALID_DEADLINE_INPUT_MESSAGE + System.lineSeparator() + "\t\t" @@ -172,7 +175,7 @@ public void markItem(String line) { private void printTaskMarkedMessage(int itemNum) { System.out.println("\tNice! I've marked this task as done:"); - System.out.println("\t " + itemList[itemNum -1]); + System.out.println("\t " + itemList[itemNum - 1]); } private static void printInputIndexOutOfRangeMessage() { @@ -196,7 +199,7 @@ public void unmarkItem(String line) { private void printTaskUnmarkedMessage(int itemNum) { System.out.println("\tOK, I've marked this task as not done yet:"); - System.out.println("\t " + itemList[itemNum -1]); + System.out.println("\t " + itemList[itemNum - 1]); } private static void printInputIndexNotAnIntegerMessage() { From 4fb89332a5ea8d1af2995d613d7f2b9fcab042a1 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Thu, 5 Sep 2024 23:12:57 +0800 Subject: [PATCH 25/76] List class: refactor code for readability --- src/main/java/List.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/main/java/List.java b/src/main/java/List.java index b16ee3b7c..e09415e9f 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -49,16 +49,6 @@ private static void printInvalidTaskMessage() { + INVALID_EVENT_INPUT_MESSAGE); } - private static void printInvalidEventMessage() { - System.out.println("\tInvalid command format:" + System.lineSeparator() + "\t\t" + - INVALID_EVENT_INPUT_MESSAGE); - } - - private static void printInvalidDeadlineMessage() { - System.out.println("\tInvalid command format:" + System.lineSeparator() + "\t\t" + - INVALID_DEADLINE_INPUT_MESSAGE); - } - private void addEvent(String line) { String eventStartDate = extractEventStartDate(line); String eventEndDate = extractEventEndDate(line); From f4e2b51a5d2286dfcc5569bc9409fedf3dc3830a Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Thu, 5 Sep 2024 23:13:56 +0800 Subject: [PATCH 26/76] Revert "List class: refactor code for readability" This reverts commit 4fb89332a5ea8d1af2995d613d7f2b9fcab042a1. --- src/main/java/List.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/List.java b/src/main/java/List.java index e09415e9f..b16ee3b7c 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -49,6 +49,16 @@ private static void printInvalidTaskMessage() { + INVALID_EVENT_INPUT_MESSAGE); } + private static void printInvalidEventMessage() { + System.out.println("\tInvalid command format:" + System.lineSeparator() + "\t\t" + + INVALID_EVENT_INPUT_MESSAGE); + } + + private static void printInvalidDeadlineMessage() { + System.out.println("\tInvalid command format:" + System.lineSeparator() + "\t\t" + + INVALID_DEADLINE_INPUT_MESSAGE); + } + private void addEvent(String line) { String eventStartDate = extractEventStartDate(line); String eventEndDate = extractEventEndDate(line); From 0dfc0b9a9c1fd616de85f52abab91dff2bb92a4d Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Thu, 5 Sep 2024 23:16:10 +0800 Subject: [PATCH 27/76] List class: remove unused print functions --- src/main/java/List.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/main/java/List.java b/src/main/java/List.java index b16ee3b7c..e09415e9f 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -49,16 +49,6 @@ private static void printInvalidTaskMessage() { + INVALID_EVENT_INPUT_MESSAGE); } - private static void printInvalidEventMessage() { - System.out.println("\tInvalid command format:" + System.lineSeparator() + "\t\t" + - INVALID_EVENT_INPUT_MESSAGE); - } - - private static void printInvalidDeadlineMessage() { - System.out.println("\tInvalid command format:" + System.lineSeparator() + "\t\t" + - INVALID_DEADLINE_INPUT_MESSAGE); - } - private void addEvent(String line) { String eventStartDate = extractEventStartDate(line); String eventEndDate = extractEventEndDate(line); From 00ebd294076c4fcee839cb98dd2d543b72178148 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Thu, 5 Sep 2024 23:31:05 +0800 Subject: [PATCH 28/76] Chatbot: insert ASCII name art --- src/main/java/Mel.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index 4f1178fc8..e3cda3341 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -61,7 +61,14 @@ private static String getLine(Scanner in) { private static void printIntroMessage() { printHorizontalLine(); - System.out.println("\tHello! I'm Mel"); + System.out.println("\tHello! I'm"); + System.out.println("\t.___ ___. _______ __ \n" + + "\t| \\/ | | ____|| | \n" + + "\t| \\ / | | |__ | | \n" + + "\t| |\\/| | | __| | | \n" + + "\t| | | | | |____ | `----.\n" + + "\t|__| |__| |_______||_______|\n" + + "\t "); System.out.println("\tWhat can I do for you?"); printHorizontalLine(); } From c45aaea0298ea31fdcc8fec9b69e6dc121137059 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Thu, 5 Sep 2024 23:31:53 +0800 Subject: [PATCH 29/76] Update expected test output --- text-ui-test/EXPECTED.TXT | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 50d5c9462..1f594b631 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,5 +1,12 @@ ________________________________________ - Hello! I'm Mel + Hello! I'm + .___ ___. _______ __ + | \/ | | ____|| | + | \ / | | |__ | | + | |\/| | | __| | | + | | | | | |____ | `----. + |__| |__| |_______||_______| + What can I do for you? ________________________________________ From b00c2e13b61c065c82ca94ea6e552195f9f33365 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 10 Sep 2024 22:25:22 +0800 Subject: [PATCH 30/76] Remove unused line variable --- src/main/java/Mel.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index e3cda3341..4695661ca 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -11,7 +11,6 @@ public static void main(String[] args) { printIntroMessage(); // Set up scanner for user input - String line; Scanner in = new Scanner(System.in); List userList = new List(); From 46f5cc7f3070a1429af216caea84add6e8dd5207 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 10 Sep 2024 22:30:20 +0800 Subject: [PATCH 31/76] Update test cases --- text-ui-test/EXPECTED.TXT | 53 +++++++++++++++++++++++++++++++++++++++ text-ui-test/input.txt | 11 ++++++++ 2 files changed, 64 insertions(+) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 1f594b631..74b177af3 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -99,6 +99,59 @@ event <event name> /from <start date/time> /end <end date/time> ________________________________________ + ________________________________________ + Error: The task description cannot be empty. + ________________________________________ + + ________________________________________ + Error: The task description cannot be empty. + ________________________________________ + + ________________________________________ + Error: The task description cannot be empty. + ________________________________________ + + ________________________________________ + Invalid command format: + todo <task name> + deadline <deadline name> /by <deadline> + event <event name> /from <start date/time> /end <end date/time> + ________________________________________ + + ________________________________________ + Error: Date field(s) cannot be empty + ________________________________________ + + ________________________________________ + Error: The task description cannot be empty. + ________________________________________ + + ________________________________________ + Error: Date field(s) cannot be empty + ________________________________________ + + ________________________________________ + Error: Date field(s) cannot be empty + ________________________________________ + + ________________________________________ + Got it. I've added this task: + [T][ ] todo todo + Now you have 4 tasks in the list. + ________________________________________ + + ________________________________________ + Got it. I've added this task: + [D][ ] deadline deadline (by: /by /by) + Now you have 5 tasks in the list. + ________________________________________ + + ________________________________________ + Got it. I've added this task: + [E][ ] event event (from: /from /from to: /to /to) + Now you have 6 tasks in the list. + ________________________________________ + ________________________________________ Bye. Hope to see you again soon! ________________________________________ diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index 175436d10..72f15bde4 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -13,4 +13,15 @@ list unmark <non-int index> list <invalid input> +todo +deadline /by <deadline date input> +event /from <start date> /to <end date> + +deadline <description> /by +event /from /to +event <event name> /from <start date> /to +event <event name>/from /to <end date> +todo todo todo +deadline deadline deadline /by /by /by +event event event /from /from /from /to /to /to bye \ No newline at end of file From 9b2fbc5fb87fdf87afe5aeb7bf4701d771d0eff2 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 10 Sep 2024 22:30:54 +0800 Subject: [PATCH 32/76] Manage empty description and date field exceptions --- src/main/java/EmptyDateFieldException.java | 3 + src/main/java/EmptyDescriptionException.java | 3 + src/main/java/List.java | 98 ++++++++++++++------ 3 files changed, 77 insertions(+), 27 deletions(-) create mode 100644 src/main/java/EmptyDateFieldException.java create mode 100644 src/main/java/EmptyDescriptionException.java diff --git a/src/main/java/EmptyDateFieldException.java b/src/main/java/EmptyDateFieldException.java new file mode 100644 index 000000000..3e4047c52 --- /dev/null +++ b/src/main/java/EmptyDateFieldException.java @@ -0,0 +1,3 @@ +public class EmptyDateFieldException extends RuntimeException { + //no other code needed +} diff --git a/src/main/java/EmptyDescriptionException.java b/src/main/java/EmptyDescriptionException.java new file mode 100644 index 000000000..9e5facee5 --- /dev/null +++ b/src/main/java/EmptyDescriptionException.java @@ -0,0 +1,3 @@ +public class EmptyDescriptionException extends Exception { + //no other code needed +} diff --git a/src/main/java/List.java b/src/main/java/List.java index e09415e9f..467d9d0d6 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -50,27 +50,47 @@ private static void printInvalidTaskMessage() { } private void addEvent(String line) { - String eventStartDate = extractEventStartDate(line); - String eventEndDate = extractEventEndDate(line); - String eventDescription = extractEventDescription(line); - itemList[numItems] = new Event(eventDescription, eventStartDate, eventEndDate); - outputAddedMessage(itemList[numItems]); - numItems += 1; + try { + String eventDescription = extractEventDescription(line); + String eventStartDate = extractEventStartDate(line); + String eventEndDate = extractEventEndDate(line); + itemList[numItems] = new Event(eventDescription, eventStartDate, eventEndDate); + outputAddedMessage(itemList[numItems]); + numItems += 1; + } catch (EmptyDescriptionException e) { + printTaskDescriptionEmptyMessage(); + } catch (EmptyDateFieldException e) { + System.out.println("\tError: Date field(s) cannot be empty"); + } } private void addTodo(String line) { - String todoDescription = extractTodoDescription(line); - itemList[numItems] = new Todo(todoDescription); - outputAddedMessage(itemList[numItems]); - numItems += 1; + try { + String todoDescription = extractTodoDescription(line); + itemList[numItems] = new Todo(todoDescription); + outputAddedMessage(itemList[numItems]); + numItems += 1; + } catch (EmptyDescriptionException e) { + printTaskDescriptionEmptyMessage(); + } + } + + private static void printTaskDescriptionEmptyMessage() { + System.out.println("\tError: The task description cannot be empty."); } private void addDeadline(String line) { - String deadlineDate = extractDeadlineDate(line); - String deadlineDescription = extractDeadlineDescription(line); - itemList[numItems] = new Deadline(deadlineDescription, deadlineDate); - outputAddedMessage(itemList[numItems]); - numItems += 1; + try { + String deadlineDescription = extractDeadlineDescription(line); + String deadlineDate = extractDeadlineDate(line); + itemList[numItems] = new Deadline(deadlineDescription, deadlineDate); + outputAddedMessage(itemList[numItems]); + numItems += 1; + } catch (EmptyDescriptionException e) { + printTaskDescriptionEmptyMessage(); + } catch (EmptyDateFieldException e) { + System.out.println("\tError: Date field(s) cannot be empty"); + } } private void outputAddedMessage(Task task) { @@ -79,39 +99,59 @@ private void outputAddedMessage(Task task) { System.out.println("\tNow you have " + (numItems+1) + " tasks in the list."); } - private String extractTodoDescription(String line) { + private String extractTodoDescription(String line) throws EmptyDescriptionException { String todoDescription; - todoDescription = line.trim().replace("todo ", ""); + todoDescription = line.replaceFirst("todo", "").trim(); + + taskDescriptionNotEmpty(todoDescription); return todoDescription; } - private String extractDeadlineDescription(String line) { + private String extractDeadlineDescription(String line) throws EmptyDescriptionException { String deadlineDescription; final int indexOfDeadlinePrefix = line.indexOf("/by"); - deadlineDescription = line.substring(0, indexOfDeadlinePrefix).trim().replace("deadline ", ""); + deadlineDescription = line.substring(0, indexOfDeadlinePrefix).replaceFirst("deadline", "").trim(); + + taskDescriptionNotEmpty(deadlineDescription); return deadlineDescription; } + private static void taskDescriptionNotEmpty(String taskDescription) throws EmptyDescriptionException { + if (taskDescription.isEmpty()) { + throw new EmptyDescriptionException(); + } + } + private String extractDeadlineDate(String line) { String deadlineDate; final int indexOfDeadlinePrefix = line.indexOf("/by"); - deadlineDate = line.substring(indexOfDeadlinePrefix).trim().replace("/by ", ""); + deadlineDate = line.substring(indexOfDeadlinePrefix).replaceFirst("/by", "").trim(); + + dateFieldNotEmpty(deadlineDate); return deadlineDate; } - private String extractEventDescription(String line) { + private static void dateFieldNotEmpty(String dateField) throws EmptyDateFieldException { + if (dateField.isEmpty()) { + throw new EmptyDateFieldException(); + } + } + + private String extractEventDescription(String line) throws EmptyDescriptionException { String eventDescription; final int indexOfStartDatePrefix = line.indexOf("/from"); final int indexOfEndDatePrefix = line.indexOf("/to"); if (indexOfEndDatePrefix > indexOfStartDatePrefix) { - eventDescription = line.substring(0, indexOfStartDatePrefix).trim().replace("event ", ""); + eventDescription = line.substring(0, indexOfStartDatePrefix).replaceFirst("event", "").trim(); } else { - eventDescription = line.substring(0, indexOfEndDatePrefix).trim().replace("event ", ""); + eventDescription = line.substring(0, indexOfEndDatePrefix).replaceFirst("event", "").trim(); } + taskDescriptionNotEmpty(eventDescription); + return eventDescription; } @@ -120,11 +160,13 @@ private String extractEventEndDate(String line) { final int indexOfStartDatePrefix = line.indexOf("/from"); final int indexOfEndDatePrefix = line.indexOf("/to"); if (indexOfEndDatePrefix > indexOfStartDatePrefix) { - eventEndDate = line.substring(indexOfEndDatePrefix).trim().replace("/to ", ""); + eventEndDate = line.substring(indexOfEndDatePrefix).replaceFirst("/to", "").trim(); } else { - eventEndDate = line.substring(indexOfEndDatePrefix, indexOfStartDatePrefix).trim().replace("/to ", ""); + eventEndDate = line.substring(indexOfEndDatePrefix, indexOfStartDatePrefix).replaceFirst("/to", "").trim(); } + dateFieldNotEmpty(eventEndDate); + return eventEndDate; } @@ -133,11 +175,13 @@ private String extractEventStartDate(String line) { final int indexOfStartDatePrefix = line.indexOf("/from"); final int indexOfEndDatePrefix = line.indexOf("/to"); if (indexOfStartDatePrefix > indexOfEndDatePrefix) { - eventStartDate = line.substring(indexOfStartDatePrefix).trim().replace("/from ", ""); + eventStartDate = line.substring(indexOfStartDatePrefix).replaceFirst("/from", "").trim(); } else { - eventStartDate = line.substring(indexOfStartDatePrefix, indexOfEndDatePrefix).trim().replace("/from ", ""); + eventStartDate = line.substring(indexOfStartDatePrefix, indexOfEndDatePrefix).replaceFirst("/from", "").trim(); } + dateFieldNotEmpty(eventStartDate); + return eventStartDate; } From fd7f8b8d1124914f6845c3e2b42b5f81d9f3c34e Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 10 Sep 2024 23:14:35 +0800 Subject: [PATCH 33/76] Organize into packages --- src/main/java/List.java | 6 +++- src/main/java/Mel.java | 30 +++++++++++++++---- .../EmptyDateFieldException.java | 2 ++ .../EmptyDescriptionException.java | 2 ++ src/main/java/{ => task}/Deadline.java | 2 ++ src/main/java/{ => task}/Event.java | 2 ++ src/main/java/{ => task}/Task.java | 6 ++++ src/main/java/{ => task}/Todo.java | 2 ++ 8 files changed, 46 insertions(+), 6 deletions(-) rename src/main/java/{ => exception}/EmptyDateFieldException.java (82%) rename src/main/java/{ => exception}/EmptyDescriptionException.java (81%) rename src/main/java/{ => task}/Deadline.java (95%) rename src/main/java/{ => task}/Event.java (96%) rename src/main/java/{ => task}/Task.java (83%) rename src/main/java/{ => task}/Todo.java (93%) diff --git a/src/main/java/List.java b/src/main/java/List.java index 467d9d0d6..c8b391a9c 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -1,3 +1,7 @@ +import exception.EmptyDateFieldException; +import exception.EmptyDescriptionException; +import task.*; + public class List { public static final String INVALID_EVENT_INPUT_MESSAGE = "event <event name> /from <start date/time> /end <end date/time>"; public static final String INVALID_DEADLINE_INPUT_MESSAGE = "deadline <deadline name> /by <deadline>"; @@ -241,7 +245,7 @@ private static void printInputIndexNotAnIntegerMessage() { } public String getItemDescription(int itemNum) { - return itemList[itemNum - 1].description; + return itemList[itemNum - 1].getDescription(); } public void markListItemAsDone(int itemNum) { diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index 4695661ca..d6007f55a 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -22,20 +22,20 @@ private static void getUserInput(Scanner in, List userList) { while (true) { line = getLine(in); - if (line.equals("bye")) { - System.out.println("\tBye. Hope to see you again soon!"); + if (isBye(line)) { + printByeMessage(); printHorizontalLine(); break; - } else if (line.equals("list")) { + } else if (isList(line)) { userList.printList(); printHorizontalLine(); - } else if (line.length() >= (MARK_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 4).equals("mark")) { + } else if (isMark(line)) { userList.markItem(line); printHorizontalLine(); - } else if (line.length() >= (UNMARK_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 6).equals("unmark")) { + } else if (isUnmark(line)) { userList.unmarkItem(line); printHorizontalLine(); @@ -46,6 +46,26 @@ private static void getUserInput(Scanner in, List userList) { } } + private static void printByeMessage() { + System.out.println("\tBye. Hope to see you again soon!"); + } + + private static boolean isList(String line) { + return line.equals("list"); + } + + private static boolean isBye(String line) { + return line.equals("bye"); + } + + private static boolean isMark(String line) { + return line.length() >= (MARK_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 4).equals("mark"); + } + + private static boolean isUnmark(String line) { + return line.length() >= (UNMARK_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 6).equals("unmark"); + } + private static void printHorizontalLine() { System.out.println(DRAW_HORIZONTAL_LINE); } diff --git a/src/main/java/EmptyDateFieldException.java b/src/main/java/exception/EmptyDateFieldException.java similarity index 82% rename from src/main/java/EmptyDateFieldException.java rename to src/main/java/exception/EmptyDateFieldException.java index 3e4047c52..b459b09ae 100644 --- a/src/main/java/EmptyDateFieldException.java +++ b/src/main/java/exception/EmptyDateFieldException.java @@ -1,3 +1,5 @@ +package exception; + public class EmptyDateFieldException extends RuntimeException { //no other code needed } diff --git a/src/main/java/EmptyDescriptionException.java b/src/main/java/exception/EmptyDescriptionException.java similarity index 81% rename from src/main/java/EmptyDescriptionException.java rename to src/main/java/exception/EmptyDescriptionException.java index 9e5facee5..5d50407c4 100644 --- a/src/main/java/EmptyDescriptionException.java +++ b/src/main/java/exception/EmptyDescriptionException.java @@ -1,3 +1,5 @@ +package exception; + public class EmptyDescriptionException extends Exception { //no other code needed } diff --git a/src/main/java/Deadline.java b/src/main/java/task/Deadline.java similarity index 95% rename from src/main/java/Deadline.java rename to src/main/java/task/Deadline.java index 531ce45c3..3fd52eef3 100644 --- a/src/main/java/Deadline.java +++ b/src/main/java/task/Deadline.java @@ -1,3 +1,5 @@ +package task; + public class Deadline extends Task { protected String by; diff --git a/src/main/java/Event.java b/src/main/java/task/Event.java similarity index 96% rename from src/main/java/Event.java rename to src/main/java/task/Event.java index 1b08bdff7..a4851a4bb 100644 --- a/src/main/java/Event.java +++ b/src/main/java/task/Event.java @@ -1,3 +1,5 @@ +package task; + public class Event extends Task { protected String startDate; protected String endDate; diff --git a/src/main/java/Task.java b/src/main/java/task/Task.java similarity index 83% rename from src/main/java/Task.java rename to src/main/java/task/Task.java index 024399514..f8b97cf82 100644 --- a/src/main/java/Task.java +++ b/src/main/java/task/Task.java @@ -1,3 +1,5 @@ +package task; + public class Task { protected String description; protected boolean isDone; @@ -7,6 +9,10 @@ public Task(String description) { this.isDone = false; } + public String getDescription() { + return description; + } + public String getDoneStatusIcon() { return (isDone ? "X" : " "); // mark done task with X } diff --git a/src/main/java/Todo.java b/src/main/java/task/Todo.java similarity index 93% rename from src/main/java/Todo.java rename to src/main/java/task/Todo.java index 1d0e088a6..987520760 100644 --- a/src/main/java/Todo.java +++ b/src/main/java/task/Todo.java @@ -1,3 +1,5 @@ +package task; + public class Todo extends Task { public Todo(String description) { super(description); From 39e9e705f9d9466985b95ea20afefbb56e9c0893 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 10 Sep 2024 23:15:34 +0800 Subject: [PATCH 34/76] Revert "Organize into packages" This reverts commit fd7f8b8d1124914f6845c3e2b42b5f81d9f3c34e. --- src/main/java/{task => }/Deadline.java | 2 -- .../EmptyDateFieldException.java | 2 -- .../EmptyDescriptionException.java | 2 -- src/main/java/{task => }/Event.java | 2 -- src/main/java/List.java | 6 +--- src/main/java/Mel.java | 30 ++++--------------- src/main/java/{task => }/Task.java | 6 ---- src/main/java/{task => }/Todo.java | 2 -- 8 files changed, 6 insertions(+), 46 deletions(-) rename src/main/java/{task => }/Deadline.java (95%) rename src/main/java/{exception => }/EmptyDateFieldException.java (82%) rename src/main/java/{exception => }/EmptyDescriptionException.java (81%) rename src/main/java/{task => }/Event.java (96%) rename src/main/java/{task => }/Task.java (83%) rename src/main/java/{task => }/Todo.java (93%) diff --git a/src/main/java/task/Deadline.java b/src/main/java/Deadline.java similarity index 95% rename from src/main/java/task/Deadline.java rename to src/main/java/Deadline.java index 3fd52eef3..531ce45c3 100644 --- a/src/main/java/task/Deadline.java +++ b/src/main/java/Deadline.java @@ -1,5 +1,3 @@ -package task; - public class Deadline extends Task { protected String by; diff --git a/src/main/java/exception/EmptyDateFieldException.java b/src/main/java/EmptyDateFieldException.java similarity index 82% rename from src/main/java/exception/EmptyDateFieldException.java rename to src/main/java/EmptyDateFieldException.java index b459b09ae..3e4047c52 100644 --- a/src/main/java/exception/EmptyDateFieldException.java +++ b/src/main/java/EmptyDateFieldException.java @@ -1,5 +1,3 @@ -package exception; - public class EmptyDateFieldException extends RuntimeException { //no other code needed } diff --git a/src/main/java/exception/EmptyDescriptionException.java b/src/main/java/EmptyDescriptionException.java similarity index 81% rename from src/main/java/exception/EmptyDescriptionException.java rename to src/main/java/EmptyDescriptionException.java index 5d50407c4..9e5facee5 100644 --- a/src/main/java/exception/EmptyDescriptionException.java +++ b/src/main/java/EmptyDescriptionException.java @@ -1,5 +1,3 @@ -package exception; - public class EmptyDescriptionException extends Exception { //no other code needed } diff --git a/src/main/java/task/Event.java b/src/main/java/Event.java similarity index 96% rename from src/main/java/task/Event.java rename to src/main/java/Event.java index a4851a4bb..1b08bdff7 100644 --- a/src/main/java/task/Event.java +++ b/src/main/java/Event.java @@ -1,5 +1,3 @@ -package task; - public class Event extends Task { protected String startDate; protected String endDate; diff --git a/src/main/java/List.java b/src/main/java/List.java index c8b391a9c..467d9d0d6 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -1,7 +1,3 @@ -import exception.EmptyDateFieldException; -import exception.EmptyDescriptionException; -import task.*; - public class List { public static final String INVALID_EVENT_INPUT_MESSAGE = "event <event name> /from <start date/time> /end <end date/time>"; public static final String INVALID_DEADLINE_INPUT_MESSAGE = "deadline <deadline name> /by <deadline>"; @@ -245,7 +241,7 @@ private static void printInputIndexNotAnIntegerMessage() { } public String getItemDescription(int itemNum) { - return itemList[itemNum - 1].getDescription(); + return itemList[itemNum - 1].description; } public void markListItemAsDone(int itemNum) { diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index d6007f55a..4695661ca 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -22,20 +22,20 @@ private static void getUserInput(Scanner in, List userList) { while (true) { line = getLine(in); - if (isBye(line)) { - printByeMessage(); + if (line.equals("bye")) { + System.out.println("\tBye. Hope to see you again soon!"); printHorizontalLine(); break; - } else if (isList(line)) { + } else if (line.equals("list")) { userList.printList(); printHorizontalLine(); - } else if (isMark(line)) { + } else if (line.length() >= (MARK_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 4).equals("mark")) { userList.markItem(line); printHorizontalLine(); - } else if (isUnmark(line)) { + } else if (line.length() >= (UNMARK_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 6).equals("unmark")) { userList.unmarkItem(line); printHorizontalLine(); @@ -46,26 +46,6 @@ private static void getUserInput(Scanner in, List userList) { } } - private static void printByeMessage() { - System.out.println("\tBye. Hope to see you again soon!"); - } - - private static boolean isList(String line) { - return line.equals("list"); - } - - private static boolean isBye(String line) { - return line.equals("bye"); - } - - private static boolean isMark(String line) { - return line.length() >= (MARK_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 4).equals("mark"); - } - - private static boolean isUnmark(String line) { - return line.length() >= (UNMARK_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 6).equals("unmark"); - } - private static void printHorizontalLine() { System.out.println(DRAW_HORIZONTAL_LINE); } diff --git a/src/main/java/task/Task.java b/src/main/java/Task.java similarity index 83% rename from src/main/java/task/Task.java rename to src/main/java/Task.java index f8b97cf82..024399514 100644 --- a/src/main/java/task/Task.java +++ b/src/main/java/Task.java @@ -1,5 +1,3 @@ -package task; - public class Task { protected String description; protected boolean isDone; @@ -9,10 +7,6 @@ public Task(String description) { this.isDone = false; } - public String getDescription() { - return description; - } - public String getDoneStatusIcon() { return (isDone ? "X" : " "); // mark done task with X } diff --git a/src/main/java/task/Todo.java b/src/main/java/Todo.java similarity index 93% rename from src/main/java/task/Todo.java rename to src/main/java/Todo.java index 987520760..1d0e088a6 100644 --- a/src/main/java/task/Todo.java +++ b/src/main/java/Todo.java @@ -1,5 +1,3 @@ -package task; - public class Todo extends Task { public Todo(String description) { super(description); From 3beef464e5b4ffa660faaa994191ec2840649038 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 10 Sep 2024 23:15:53 +0800 Subject: [PATCH 35/76] Reapply "Organize into packages" This reverts commit 39e9e705f9d9466985b95ea20afefbb56e9c0893. --- src/main/java/List.java | 6 +++- src/main/java/Mel.java | 30 +++++++++++++++---- .../EmptyDateFieldException.java | 2 ++ .../EmptyDescriptionException.java | 2 ++ src/main/java/{ => task}/Deadline.java | 2 ++ src/main/java/{ => task}/Event.java | 2 ++ src/main/java/{ => task}/Task.java | 6 ++++ src/main/java/{ => task}/Todo.java | 2 ++ 8 files changed, 46 insertions(+), 6 deletions(-) rename src/main/java/{ => exception}/EmptyDateFieldException.java (82%) rename src/main/java/{ => exception}/EmptyDescriptionException.java (81%) rename src/main/java/{ => task}/Deadline.java (95%) rename src/main/java/{ => task}/Event.java (96%) rename src/main/java/{ => task}/Task.java (83%) rename src/main/java/{ => task}/Todo.java (93%) diff --git a/src/main/java/List.java b/src/main/java/List.java index 467d9d0d6..c8b391a9c 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -1,3 +1,7 @@ +import exception.EmptyDateFieldException; +import exception.EmptyDescriptionException; +import task.*; + public class List { public static final String INVALID_EVENT_INPUT_MESSAGE = "event <event name> /from <start date/time> /end <end date/time>"; public static final String INVALID_DEADLINE_INPUT_MESSAGE = "deadline <deadline name> /by <deadline>"; @@ -241,7 +245,7 @@ private static void printInputIndexNotAnIntegerMessage() { } public String getItemDescription(int itemNum) { - return itemList[itemNum - 1].description; + return itemList[itemNum - 1].getDescription(); } public void markListItemAsDone(int itemNum) { diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index 4695661ca..d6007f55a 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -22,20 +22,20 @@ private static void getUserInput(Scanner in, List userList) { while (true) { line = getLine(in); - if (line.equals("bye")) { - System.out.println("\tBye. Hope to see you again soon!"); + if (isBye(line)) { + printByeMessage(); printHorizontalLine(); break; - } else if (line.equals("list")) { + } else if (isList(line)) { userList.printList(); printHorizontalLine(); - } else if (line.length() >= (MARK_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 4).equals("mark")) { + } else if (isMark(line)) { userList.markItem(line); printHorizontalLine(); - } else if (line.length() >= (UNMARK_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 6).equals("unmark")) { + } else if (isUnmark(line)) { userList.unmarkItem(line); printHorizontalLine(); @@ -46,6 +46,26 @@ private static void getUserInput(Scanner in, List userList) { } } + private static void printByeMessage() { + System.out.println("\tBye. Hope to see you again soon!"); + } + + private static boolean isList(String line) { + return line.equals("list"); + } + + private static boolean isBye(String line) { + return line.equals("bye"); + } + + private static boolean isMark(String line) { + return line.length() >= (MARK_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 4).equals("mark"); + } + + private static boolean isUnmark(String line) { + return line.length() >= (UNMARK_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 6).equals("unmark"); + } + private static void printHorizontalLine() { System.out.println(DRAW_HORIZONTAL_LINE); } diff --git a/src/main/java/EmptyDateFieldException.java b/src/main/java/exception/EmptyDateFieldException.java similarity index 82% rename from src/main/java/EmptyDateFieldException.java rename to src/main/java/exception/EmptyDateFieldException.java index 3e4047c52..b459b09ae 100644 --- a/src/main/java/EmptyDateFieldException.java +++ b/src/main/java/exception/EmptyDateFieldException.java @@ -1,3 +1,5 @@ +package exception; + public class EmptyDateFieldException extends RuntimeException { //no other code needed } diff --git a/src/main/java/EmptyDescriptionException.java b/src/main/java/exception/EmptyDescriptionException.java similarity index 81% rename from src/main/java/EmptyDescriptionException.java rename to src/main/java/exception/EmptyDescriptionException.java index 9e5facee5..5d50407c4 100644 --- a/src/main/java/EmptyDescriptionException.java +++ b/src/main/java/exception/EmptyDescriptionException.java @@ -1,3 +1,5 @@ +package exception; + public class EmptyDescriptionException extends Exception { //no other code needed } diff --git a/src/main/java/Deadline.java b/src/main/java/task/Deadline.java similarity index 95% rename from src/main/java/Deadline.java rename to src/main/java/task/Deadline.java index 531ce45c3..3fd52eef3 100644 --- a/src/main/java/Deadline.java +++ b/src/main/java/task/Deadline.java @@ -1,3 +1,5 @@ +package task; + public class Deadline extends Task { protected String by; diff --git a/src/main/java/Event.java b/src/main/java/task/Event.java similarity index 96% rename from src/main/java/Event.java rename to src/main/java/task/Event.java index 1b08bdff7..a4851a4bb 100644 --- a/src/main/java/Event.java +++ b/src/main/java/task/Event.java @@ -1,3 +1,5 @@ +package task; + public class Event extends Task { protected String startDate; protected String endDate; diff --git a/src/main/java/Task.java b/src/main/java/task/Task.java similarity index 83% rename from src/main/java/Task.java rename to src/main/java/task/Task.java index 024399514..f8b97cf82 100644 --- a/src/main/java/Task.java +++ b/src/main/java/task/Task.java @@ -1,3 +1,5 @@ +package task; + public class Task { protected String description; protected boolean isDone; @@ -7,6 +9,10 @@ public Task(String description) { this.isDone = false; } + public String getDescription() { + return description; + } + public String getDoneStatusIcon() { return (isDone ? "X" : " "); // mark done task with X } diff --git a/src/main/java/Todo.java b/src/main/java/task/Todo.java similarity index 93% rename from src/main/java/Todo.java rename to src/main/java/task/Todo.java index 1d0e088a6..987520760 100644 --- a/src/main/java/Todo.java +++ b/src/main/java/task/Todo.java @@ -1,3 +1,5 @@ +package task; + public class Todo extends Task { public Todo(String description) { super(description); From d4122482387dd56e7bc232f29c5a45466e15c378 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 17 Sep 2024 21:47:04 +0800 Subject: [PATCH 36/76] List: add invalid input message for delete --- src/main/java/List.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/List.java b/src/main/java/List.java index c8b391a9c..f332f1da4 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -9,6 +9,9 @@ public class List { public static final String DEADLINE_BY_KEYWORD = "/by"; public static final String EVENT_FROM_KEYWORD = "/from"; public static final String EVENT_TO_KEYWORD = "/to"; + private static final String INVALID_MARK_MESSAGE = "mark <task index>"; + private static final String INVALID_UNMARK_MESSAGE = "unmark <task index>"; + private static final String INVALID_DELETE_MESSAGE = "delete <task index>"; private int numItems; private Task[] itemList = new Task[100]; @@ -50,7 +53,10 @@ private boolean isTodo(String line) { private static void printInvalidTaskMessage() { System.out.println("\tInvalid command format:" + System.lineSeparator() + "\t\t" + INVALID_TODO_INPUT_MESSAGE + System.lineSeparator() + "\t\t" + INVALID_DEADLINE_INPUT_MESSAGE + System.lineSeparator() + "\t\t" - + INVALID_EVENT_INPUT_MESSAGE); + + INVALID_EVENT_INPUT_MESSAGE + System.lineSeparator() + "\t\t" + + INVALID_MARK_MESSAGE + System.lineSeparator() + "\t\t" + + INVALID_UNMARK_MESSAGE + System.lineSeparator() + "\t\t" + + INVALID_DELETE_MESSAGE); } private void addEvent(String line) { From cf5bf1e8e71f1cfec687725663bb925684984008 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 17 Sep 2024 21:49:30 +0800 Subject: [PATCH 37/76] Update test case --- text-ui-test/EXPECTED.TXT | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 74b177af3..7c1e7598f 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -97,6 +97,9 @@ todo <task name> deadline <deadline name> /by <deadline> event <event name> /from <start date/time> /end <end date/time> + mark <task index> + unmark <task index> + delete <task index> ________________________________________ ________________________________________ @@ -116,6 +119,9 @@ todo <task name> deadline <deadline name> /by <deadline> event <event name> /from <start date/time> /end <end date/time> + mark <task index> + unmark <task index> + delete <task index> ________________________________________ ________________________________________ From 2935e814d17d1bfdf7c21dbe966047d798f00db2 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 17 Sep 2024 21:50:20 +0800 Subject: [PATCH 38/76] Add delete helper functions except for delete function --- src/main/java/List.java | 26 ++++++++++++++++++++++++++ src/main/java/Mel.java | 9 +++++++++ 2 files changed, 35 insertions(+) diff --git a/src/main/java/List.java b/src/main/java/List.java index f332f1da4..c64e7cc90 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -265,4 +265,30 @@ public void markListItemAsUnDone(int itemNum) { public String itemGetDoneStatusIcon(int itemNum) { return itemList[itemNum - 1].getDoneStatusIcon(); } + + public void deleteItem(String line) { + try { + int itemNum = Integer.parseInt(line.substring(7)); + + if (itemNum > this.getNumItems() || itemNum <= 0) { + printInputIndexOutOfRangeMessage(); + } else { + Task deletedTask = itemList[itemNum - 1]; + this.deleteListItem(itemNum); + printTaskDeletedMessage(deletedTask); + } + } catch (Exception e) { + printInputIndexNotAnIntegerMessage(); + } + } + + private void deleteListItem(int itemNum) { + System.out.println("<Delete function to be filled>"); + } + + private void printTaskDeletedMessage(Task task) { + System.out.println("\tNoted. I've removed this task:"); + System.out.println("\t " + task); + System.out.println("\tNow you have " + (numItems+1) + " tasks in the list."); + } } diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index d6007f55a..088205bf5 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -6,6 +6,7 @@ public class Mel { public static final int MARK_WORD_LEN = 4; public static final int UNMARK_WORD_LEN = 6; public static final int INPUT_SPACE_BUFFER = 2; + private static final int DELETE_WORD_LEN = 6; public static void main(String[] args) { printIntroMessage(); @@ -39,6 +40,10 @@ private static void getUserInput(Scanner in, List userList) { userList.unmarkItem(line); printHorizontalLine(); + } else if (isDelete(line)) { + userList.deleteItem(line); + printHorizontalLine(); + } else { userList.addItem(line); printHorizontalLine(); @@ -66,6 +71,10 @@ private static boolean isUnmark(String line) { return line.length() >= (UNMARK_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 6).equals("unmark"); } + private static boolean isDelete(String line) { + return line.length() >= (DELETE_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 6).equals("delete"); + } + private static void printHorizontalLine() { System.out.println(DRAW_HORIZONTAL_LINE); } From b839ee133ff9b419581feb298b0215af8284aeb2 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 17 Sep 2024 23:06:14 +0800 Subject: [PATCH 39/76] List: implement list as ArrayList --- src/main/java/List.java | 57 +++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/src/main/java/List.java b/src/main/java/List.java index c64e7cc90..33a4d0ded 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -2,6 +2,9 @@ import exception.EmptyDescriptionException; import task.*; +import java.util.ArrayList; +import java.util.Arrays; + public class List { public static final String INVALID_EVENT_INPUT_MESSAGE = "event <event name> /from <start date/time> /end <end date/time>"; public static final String INVALID_DEADLINE_INPUT_MESSAGE = "deadline <deadline name> /by <deadline>"; @@ -14,14 +17,17 @@ public class List { private static final String INVALID_DELETE_MESSAGE = "delete <task index>"; private int numItems; - private Task[] itemList = new Task[100]; + private Task[] itemList = new Task[0]; + ArrayList<Task> itemArrayList = new ArrayList<>(Arrays.asList(itemList)); + + public List() { this.numItems = 0; } public int getNumItems() { - return numItems; + return itemArrayList.size(); } public void addItem(String line) { @@ -64,8 +70,10 @@ private void addEvent(String line) { String eventDescription = extractEventDescription(line); String eventStartDate = extractEventStartDate(line); String eventEndDate = extractEventEndDate(line); - itemList[numItems] = new Event(eventDescription, eventStartDate, eventEndDate); - outputAddedMessage(itemList[numItems]); + //itemList[numItems] = new Event(eventDescription, eventStartDate, eventEndDate); + Event newEvent = new Event(eventDescription, eventStartDate, eventEndDate); + itemArrayList.add(newEvent); + outputAddedMessage(newEvent); numItems += 1; } catch (EmptyDescriptionException e) { printTaskDescriptionEmptyMessage(); @@ -77,8 +85,10 @@ private void addEvent(String line) { private void addTodo(String line) { try { String todoDescription = extractTodoDescription(line); - itemList[numItems] = new Todo(todoDescription); - outputAddedMessage(itemList[numItems]); + //itemList[numItems] = new Todo(todoDescription); + Todo newTodo = new Todo(todoDescription); + itemArrayList.add(newTodo); + outputAddedMessage(newTodo); numItems += 1; } catch (EmptyDescriptionException e) { printTaskDescriptionEmptyMessage(); @@ -93,8 +103,10 @@ private void addDeadline(String line) { try { String deadlineDescription = extractDeadlineDescription(line); String deadlineDate = extractDeadlineDate(line); - itemList[numItems] = new Deadline(deadlineDescription, deadlineDate); - outputAddedMessage(itemList[numItems]); + //itemList[numItems] = new Deadline(deadlineDescription, deadlineDate); + Deadline newDeadline = new Deadline(deadlineDescription, deadlineDate); + itemArrayList.add(newDeadline); + outputAddedMessage(newDeadline); numItems += 1; } catch (EmptyDescriptionException e) { printTaskDescriptionEmptyMessage(); @@ -197,8 +209,13 @@ private String extractEventStartDate(String line) { public void printList() { System.out.println("\tHere are the tasks in your list:"); - for (int i = 0; i < numItems; i++) { - System.out.println("\t" + (i + 1) + "." + itemList[i]); +// for (int i = 0; i < numItems; i++) { +// System.out.println("\t" + (i + 1) + "." + itemList[i]); +// } + int i = 0; + for (Task a: itemArrayList) { + System.out.println("\t" + (i + 1) + "." + a); + i += 1; } } @@ -212,14 +229,20 @@ public void markItem(String line) { this.markListItemAsDone(itemNum); printTaskMarkedMessage(itemNum); } - } catch (Exception e) { + } catch (NumberFormatException e) { printInputIndexNotAnIntegerMessage(); + } catch (Exception e) { + printUnknownErrorMessage(); } } + private static void printUnknownErrorMessage() { + System.out.println("Unknown error experienced."); + } + private void printTaskMarkedMessage(int itemNum) { System.out.println("\tNice! I've marked this task as done:"); - System.out.println("\t " + itemList[itemNum - 1]); + System.out.println("\t " + itemArrayList.get(itemNum - 1)); } private static void printInputIndexOutOfRangeMessage() { @@ -236,14 +259,16 @@ public void unmarkItem(String line) { this.markListItemAsUnDone(itemNum); printTaskUnmarkedMessage(itemNum); } - } catch (Exception e) { + } catch (NumberFormatException e) { printInputIndexNotAnIntegerMessage(); + } catch (Exception e) { + printUnknownErrorMessage(); } } private void printTaskUnmarkedMessage(int itemNum) { System.out.println("\tOK, I've marked this task as not done yet:"); - System.out.println("\t " + itemList[itemNum - 1]); + System.out.println("\t " + itemArrayList.get(itemNum - 1)); } private static void printInputIndexNotAnIntegerMessage() { @@ -255,11 +280,11 @@ public String getItemDescription(int itemNum) { } public void markListItemAsDone(int itemNum) { - itemList[itemNum - 1].markAsDone(); + itemArrayList.get(itemNum - 1).markAsDone(); } public void markListItemAsUnDone(int itemNum) { - itemList[itemNum - 1].markAsUnDone(); + itemArrayList.get(itemNum - 1).markAsUnDone(); } public String itemGetDoneStatusIcon(int itemNum) { From a5dfd427fba5cedd65c3344eb1aa20183021899d Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 17 Sep 2024 23:08:17 +0800 Subject: [PATCH 40/76] Remove unused code --- src/main/java/List.java | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/main/java/List.java b/src/main/java/List.java index 33a4d0ded..9ae2b4e3e 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -70,7 +70,6 @@ private void addEvent(String line) { String eventDescription = extractEventDescription(line); String eventStartDate = extractEventStartDate(line); String eventEndDate = extractEventEndDate(line); - //itemList[numItems] = new Event(eventDescription, eventStartDate, eventEndDate); Event newEvent = new Event(eventDescription, eventStartDate, eventEndDate); itemArrayList.add(newEvent); outputAddedMessage(newEvent); @@ -85,7 +84,6 @@ private void addEvent(String line) { private void addTodo(String line) { try { String todoDescription = extractTodoDescription(line); - //itemList[numItems] = new Todo(todoDescription); Todo newTodo = new Todo(todoDescription); itemArrayList.add(newTodo); outputAddedMessage(newTodo); @@ -103,7 +101,6 @@ private void addDeadline(String line) { try { String deadlineDescription = extractDeadlineDescription(line); String deadlineDate = extractDeadlineDate(line); - //itemList[numItems] = new Deadline(deadlineDescription, deadlineDate); Deadline newDeadline = new Deadline(deadlineDescription, deadlineDate); itemArrayList.add(newDeadline); outputAddedMessage(newDeadline); @@ -209,9 +206,6 @@ private String extractEventStartDate(String line) { public void printList() { System.out.println("\tHere are the tasks in your list:"); -// for (int i = 0; i < numItems; i++) { -// System.out.println("\t" + (i + 1) + "." + itemList[i]); -// } int i = 0; for (Task a: itemArrayList) { System.out.println("\t" + (i + 1) + "." + a); @@ -275,10 +269,6 @@ private static void printInputIndexNotAnIntegerMessage() { System.out.println("\tInput index was not a integer."); } - public String getItemDescription(int itemNum) { - return itemList[itemNum - 1].getDescription(); - } - public void markListItemAsDone(int itemNum) { itemArrayList.get(itemNum - 1).markAsDone(); } @@ -287,10 +277,6 @@ public void markListItemAsUnDone(int itemNum) { itemArrayList.get(itemNum - 1).markAsUnDone(); } - public String itemGetDoneStatusIcon(int itemNum) { - return itemList[itemNum - 1].getDoneStatusIcon(); - } - public void deleteItem(String line) { try { int itemNum = Integer.parseInt(line.substring(7)); From 9c43b4143a61331cb17a59a797377dd593b15a1e Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 17 Sep 2024 23:26:38 +0800 Subject: [PATCH 41/76] List: implement delete using ArrayList functions --- src/main/java/List.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/List.java b/src/main/java/List.java index 9ae2b4e3e..a24f6b92c 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -284,22 +284,24 @@ public void deleteItem(String line) { if (itemNum > this.getNumItems() || itemNum <= 0) { printInputIndexOutOfRangeMessage(); } else { - Task deletedTask = itemList[itemNum - 1]; + Task deletedTask = itemArrayList.get(itemNum - 1); this.deleteListItem(itemNum); printTaskDeletedMessage(deletedTask); } - } catch (Exception e) { + } catch (NumberFormatException e) { printInputIndexNotAnIntegerMessage(); + } catch (Exception e) { + printUnknownErrorMessage(); } } private void deleteListItem(int itemNum) { - System.out.println("<Delete function to be filled>"); + itemArrayList.remove(itemNum - 1); } private void printTaskDeletedMessage(Task task) { System.out.println("\tNoted. I've removed this task:"); System.out.println("\t " + task); - System.out.println("\tNow you have " + (numItems+1) + " tasks in the list."); + System.out.println("\tNow you have " + itemArrayList.size() + " tasks in the list."); } } From d581a011e52edf98df85f54f21c3cfd33d0f5a22 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Wed, 18 Sep 2024 01:08:58 +0800 Subject: [PATCH 42/76] Add save function --- src/main/java/List.java | 8 +++ src/main/java/Mel.java | 103 ++++++++++++++++++++++++++++++- src/main/java/task/Deadline.java | 5 ++ src/main/java/task/Event.java | 5 ++ src/main/java/task/Task.java | 4 ++ src/main/java/task/Todo.java | 5 ++ 6 files changed, 129 insertions(+), 1 deletion(-) diff --git a/src/main/java/List.java b/src/main/java/List.java index a24f6b92c..fc079466b 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -304,4 +304,12 @@ private void printTaskDeletedMessage(Task task) { System.out.println("\t " + task); System.out.println("\tNow you have " + itemArrayList.size() + " tasks in the list."); } + + public String getFormattedTasks() { + String outputString = ""; + for (Task a: itemArrayList) { + outputString += a.formattedTask() + System.lineSeparator(); + } + return outputString; + } } diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index 088205bf5..f071caa6b 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -1,4 +1,11 @@ +import java.io.File; import java.util.Scanner; +import java.io.FileWriter; +import java.io.IOException; +import java.io.FileNotFoundException; +import task.Todo; // Import the Todo class +import task.Deadline; // Import the Deadline class +import task.Event; // Import the Event class public class Mel { @@ -7,17 +14,106 @@ public class Mel { public static final int UNMARK_WORD_LEN = 6; public static final int INPUT_SPACE_BUFFER = 2; private static final int DELETE_WORD_LEN = 6; + private static final String LIST_FILE_PATH = "C:\\Users\\YK Personal\\Desktop\\Y2S1\\CS2113\\indiv_proj\\ip\\data\\Mel.txt"; - public static void main(String[] args) { + private static void writeToFile(String filePath, String textToAdd) throws IOException { + FileWriter fw = new FileWriter(filePath); + fw.write(textToAdd); + fw.close(); + } + + public static void main(String[] args) throws IOException { printIntroMessage(); // Set up scanner for user input Scanner in = new Scanner(System.in); List userList = new List(); + try { + writerSetUp(LIST_FILE_PATH); + loadDataFromFile(LIST_FILE_PATH, userList); // Load saved tasks + } catch (IOException e) { + System.out.println("An error occurred when setting up writer."); + } + getUserInput(in, userList); } + private static void writerSetUp(String filePath) throws IOException { + File listFile = new File(filePath); + if (!listFile.exists()) { + File directory = listFile.getParentFile(); + if (!directory.exists()) { + directory.mkdirs(); // Create directory if it doesn't exist + } + listFile.createNewFile(); // Create file if it doesn't exist + } + } + + public static void loadDataFromFile(String filePath, List userList) { + File file = new File(filePath); + try { + Scanner scanner = new Scanner(file); + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + parseAndAddItem(line, userList); + } + scanner.close(); + } catch (FileNotFoundException e) { + System.out.println("File not found: " + filePath); + } + } + + private static void parseAndAddItem(String line, List userList) { + String[] parts = line.split(" \\| "); + String taskType = parts[0]; // T, D, E + boolean isDone = parts[1].equals("X"); + String taskDescription = parts[2]; + + + switch (taskType) { + case "T": + Todo todoTask = new Todo(taskDescription); + if (isDone) { + todoTask.markAsDone(); + } + userList.itemArrayList.add(todoTask); + break; + + case "D": + String deadlineDate = parts[3]; // Ignore remaining parts + Deadline deadlineTask = new Deadline(taskDescription, deadlineDate); + if (isDone) { + deadlineTask.markAsDone(); + } + userList.itemArrayList.add(deadlineTask); + break; + + case "E": + String eventStart = parts[3]; // Start date/time + String eventEnd = parts[4]; // End date/time + Event eventTask = new Event(taskDescription, eventStart, eventEnd); + if (isDone) { + eventTask.markAsDone(); + } + userList.itemArrayList.add(eventTask); + break; + + default: + System.out.println("Invalid task type in file: " + taskType); + break; + } + } + + + private static void saveListToFile(List userList) { + try { + writeToFile(LIST_FILE_PATH, userList.getFormattedTasks()); // getFormattedTasks returns a formatted String + } catch (IOException e) { + System.out.println("An error occurred while saving the list."); + } + } + private static void getUserInput(Scanner in, List userList) { String line; while (true) { @@ -35,18 +131,23 @@ private static void getUserInput(Scanner in, List userList) { } else if (isMark(line)) { userList.markItem(line); printHorizontalLine(); + saveListToFile(userList); } else if (isUnmark(line)) { userList.unmarkItem(line); printHorizontalLine(); + saveListToFile(userList); } else if (isDelete(line)) { userList.deleteItem(line); printHorizontalLine(); + saveListToFile(userList); } else { userList.addItem(line); printHorizontalLine(); + saveListToFile(userList); + } } } diff --git a/src/main/java/task/Deadline.java b/src/main/java/task/Deadline.java index 3fd52eef3..2e024b3d4 100644 --- a/src/main/java/task/Deadline.java +++ b/src/main/java/task/Deadline.java @@ -14,4 +14,9 @@ public String toString() { return ("[D][" + getDoneStatusIcon() + "] " + description + " (by: " + by + ")"); } + @Override + public String formattedTask() { + return ("D | " + getDoneStatusIcon() + " | " + description + " | " + by); + } + } diff --git a/src/main/java/task/Event.java b/src/main/java/task/Event.java index a4851a4bb..65eb24ae8 100644 --- a/src/main/java/task/Event.java +++ b/src/main/java/task/Event.java @@ -14,4 +14,9 @@ public Event(String description, String startDate, String endDate) { public String toString() { return ("[E][" + getDoneStatusIcon() + "] " + description + " (from: " + startDate + " to: " + endDate + ")"); } + + @Override + public String formattedTask() { + return ("E | " + getDoneStatusIcon() + " | " + description + " | " + startDate + " | " + endDate); + } } diff --git a/src/main/java/task/Task.java b/src/main/java/task/Task.java index f8b97cf82..d9019ea72 100644 --- a/src/main/java/task/Task.java +++ b/src/main/java/task/Task.java @@ -24,4 +24,8 @@ public void markAsDone() { public void markAsUnDone() { isDone = false; } + + public String formattedTask() { + return "NULL"; + } } \ No newline at end of file diff --git a/src/main/java/task/Todo.java b/src/main/java/task/Todo.java index 987520760..0b1e64c5d 100644 --- a/src/main/java/task/Todo.java +++ b/src/main/java/task/Todo.java @@ -9,4 +9,9 @@ public Todo(String description) { public String toString() { return ("[T][" + getDoneStatusIcon() + "] " + description); } + + @Override + public String formattedTask() { + return ("T | " + getDoneStatusIcon() + " | " + description); + } } From 9d2789c813714d3d7212e738aa51c79cc135c568 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Wed, 18 Sep 2024 01:12:25 +0800 Subject: [PATCH 43/76] Update test case --- text-ui-test/EXPECTED.TXT | 131 ++++++++++++++++++++++++++++++++++++++ text-ui-test/input.txt | 21 ++++++ 2 files changed, 152 insertions(+) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 7c1e7598f..4f32b246a 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -158,6 +158,137 @@ Now you have 6 tasks in the list. ________________________________________ + ________________________________________ + Here are the tasks in your list: + 1.[T][ ] borrow book + 2.[D][ ] return book (by: Sunday) + 3.[E][ ] project meeting (from: Mon 2pm to: 4pm) + 4.[T][ ] todo todo + 5.[D][ ] deadline deadline (by: /by /by) + 6.[E][ ] event event (from: /from /from to: /to /to) + ________________________________________ + + ________________________________________ + Nice! I've marked this task as done: + [E][X] project meeting (from: Mon 2pm to: 4pm) + ________________________________________ + + ________________________________________ + Here are the tasks in your list: + 1.[T][ ] borrow book + 2.[D][ ] return book (by: Sunday) + 3.[E][X] project meeting (from: Mon 2pm to: 4pm) + 4.[T][ ] todo todo + 5.[D][ ] deadline deadline (by: /by /by) + 6.[E][ ] event event (from: /from /from to: /to /to) + ________________________________________ + + ________________________________________ + Noted. I've removed this task: + [T][ ] todo todo + Now you have 5 tasks in the list. + ________________________________________ + + ________________________________________ + Here are the tasks in your list: + 1.[T][ ] borrow book + 2.[D][ ] return book (by: Sunday) + 3.[E][X] project meeting (from: Mon 2pm to: 4pm) + 4.[D][ ] deadline deadline (by: /by /by) + 5.[E][ ] event event (from: /from /from to: /to /to) + ________________________________________ + + ________________________________________ + Input index number out of range. + ________________________________________ + + ________________________________________ + Here are the tasks in your list: + 1.[T][ ] borrow book + 2.[D][ ] return book (by: Sunday) + 3.[E][X] project meeting (from: Mon 2pm to: 4pm) + 4.[D][ ] deadline deadline (by: /by /by) + 5.[E][ ] event event (from: /from /from to: /to /to) + ________________________________________ + + ________________________________________ + Noted. I've removed this task: + [E][X] project meeting (from: Mon 2pm to: 4pm) + Now you have 4 tasks in the list. + ________________________________________ + + ________________________________________ + Here are the tasks in your list: + 1.[T][ ] borrow book + 2.[D][ ] return book (by: Sunday) + 3.[D][ ] deadline deadline (by: /by /by) + 4.[E][ ] event event (from: /from /from to: /to /to) + ________________________________________ + + ________________________________________ + Noted. I've removed this task: + [D][ ] return book (by: Sunday) + Now you have 3 tasks in the list. + ________________________________________ + + ________________________________________ + Here are the tasks in your list: + 1.[T][ ] borrow book + 2.[D][ ] deadline deadline (by: /by /by) + 3.[E][ ] event event (from: /from /from to: /to /to) + ________________________________________ + + ________________________________________ + Noted. I've removed this task: + [T][ ] borrow book + Now you have 2 tasks in the list. + ________________________________________ + + ________________________________________ + Here are the tasks in your list: + 1.[D][ ] deadline deadline (by: /by /by) + 2.[E][ ] event event (from: /from /from to: /to /to) + ________________________________________ + + ________________________________________ + Input index number out of range. + ________________________________________ + + ________________________________________ + Here are the tasks in your list: + 1.[D][ ] deadline deadline (by: /by /by) + 2.[E][ ] event event (from: /from /from to: /to /to) + ________________________________________ + + ________________________________________ + Noted. I've removed this task: + [D][ ] deadline deadline (by: /by /by) + Now you have 1 tasks in the list. + ________________________________________ + + ________________________________________ + Here are the tasks in your list: + 1.[E][ ] event event (from: /from /from to: /to /to) + ________________________________________ + + ________________________________________ + Noted. I've removed this task: + [E][ ] event event (from: /from /from to: /to /to) + Now you have 0 tasks in the list. + ________________________________________ + + ________________________________________ + Here are the tasks in your list: + ________________________________________ + + ________________________________________ + Input index number out of range. + ________________________________________ + + ________________________________________ + Here are the tasks in your list: + ________________________________________ + ________________________________________ Bye. Hope to see you again soon! ________________________________________ diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index 72f15bde4..1b8fc29da 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -24,4 +24,25 @@ event <event name>/from /to <end date> todo todo todo deadline deadline deadline /by /by /by event event event /from /from /from /to /to /to +list +mark 3 +list +delete 4 +list +delete 0 +list +delete 3 +list +delete 2 +list +delete 1 +list +delete 0 +list +delete 1 +list +delete 1 +list +delete 1 +list bye \ No newline at end of file From 3c182c92eb99fa8c86c0494da8fbb90bcd742c0d Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Wed, 18 Sep 2024 08:07:10 +0800 Subject: [PATCH 44/76] Change file path to be relative --- src/main/java/Mel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index f071caa6b..72ad2e204 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -14,7 +14,7 @@ public class Mel { public static final int UNMARK_WORD_LEN = 6; public static final int INPUT_SPACE_BUFFER = 2; private static final int DELETE_WORD_LEN = 6; - private static final String LIST_FILE_PATH = "C:\\Users\\YK Personal\\Desktop\\Y2S1\\CS2113\\indiv_proj\\ip\\data\\Mel.txt"; + private static final String LIST_FILE_PATH = ".\\data\\Mel.txt"; private static void writeToFile(String filePath, String textToAdd) throws IOException { FileWriter fw = new FileWriter(filePath); From f63d039829597c50c8185ee656f15ff3df971fd3 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Thu, 19 Sep 2024 09:21:29 +0800 Subject: [PATCH 45/76] Update .gitignore to ignore data file --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 2873e189e..98ef5c9c5 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,5 @@ src/main/resources/docs/ bin/ /text-ui-test/ACTUAL.TXT -text-ui-test/EXPECTED-UNIX.TXT +/text-ui-test/EXPECTED-UNIX.TXT +/data/Mel.txt From ac3870d65a57094ec63e5468ba48fe1bfdf59c79 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Sat, 28 Sep 2024 19:22:10 +0800 Subject: [PATCH 46/76] Extract out closely related Ui code as a class --- src/main/java/List.java | 88 +++++++++-------------------------------- src/main/java/Mel.java | 40 +++++-------------- src/main/java/Ui.java | 77 ++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 100 deletions(-) create mode 100644 src/main/java/Ui.java diff --git a/src/main/java/List.java b/src/main/java/List.java index fc079466b..fd43f337d 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -6,22 +6,14 @@ import java.util.Arrays; public class List { - public static final String INVALID_EVENT_INPUT_MESSAGE = "event <event name> /from <start date/time> /end <end date/time>"; - public static final String INVALID_DEADLINE_INPUT_MESSAGE = "deadline <deadline name> /by <deadline>"; - public static final String INVALID_TODO_INPUT_MESSAGE = "todo <task name>"; public static final String DEADLINE_BY_KEYWORD = "/by"; public static final String EVENT_FROM_KEYWORD = "/from"; public static final String EVENT_TO_KEYWORD = "/to"; - private static final String INVALID_MARK_MESSAGE = "mark <task index>"; - private static final String INVALID_UNMARK_MESSAGE = "unmark <task index>"; - private static final String INVALID_DELETE_MESSAGE = "delete <task index>"; private int numItems; private Task[] itemList = new Task[0]; ArrayList<Task> itemArrayList = new ArrayList<>(Arrays.asList(itemList)); - - public List() { this.numItems = 0; } @@ -38,7 +30,7 @@ public void addItem(String line) { } else if (isTodo(line)) { addTodo(line); } else { - printInvalidTaskMessage(); + Ui.printInvalidTaskMessage(); } } @@ -56,15 +48,6 @@ private boolean isTodo(String line) { return line.startsWith("todo"); } - private static void printInvalidTaskMessage() { - System.out.println("\tInvalid command format:" + System.lineSeparator() + "\t\t" + INVALID_TODO_INPUT_MESSAGE - + System.lineSeparator() + "\t\t" + INVALID_DEADLINE_INPUT_MESSAGE + System.lineSeparator() + "\t\t" - + INVALID_EVENT_INPUT_MESSAGE + System.lineSeparator() + "\t\t" - + INVALID_MARK_MESSAGE + System.lineSeparator() + "\t\t" - + INVALID_UNMARK_MESSAGE + System.lineSeparator() + "\t\t" - + INVALID_DELETE_MESSAGE); - } - private void addEvent(String line) { try { String eventDescription = extractEventDescription(line); @@ -72,10 +55,10 @@ private void addEvent(String line) { String eventEndDate = extractEventEndDate(line); Event newEvent = new Event(eventDescription, eventStartDate, eventEndDate); itemArrayList.add(newEvent); - outputAddedMessage(newEvent); + Ui.printAddedMessage(itemArrayList, newEvent); numItems += 1; } catch (EmptyDescriptionException e) { - printTaskDescriptionEmptyMessage(); + Ui.printTaskDescriptionEmptyMessage(); } catch (EmptyDateFieldException e) { System.out.println("\tError: Date field(s) cannot be empty"); } @@ -86,38 +69,28 @@ private void addTodo(String line) { String todoDescription = extractTodoDescription(line); Todo newTodo = new Todo(todoDescription); itemArrayList.add(newTodo); - outputAddedMessage(newTodo); + Ui.printAddedMessage(itemArrayList, newTodo); numItems += 1; } catch (EmptyDescriptionException e) { - printTaskDescriptionEmptyMessage(); + Ui.printTaskDescriptionEmptyMessage(); } } - private static void printTaskDescriptionEmptyMessage() { - System.out.println("\tError: The task description cannot be empty."); - } - private void addDeadline(String line) { try { String deadlineDescription = extractDeadlineDescription(line); String deadlineDate = extractDeadlineDate(line); Deadline newDeadline = new Deadline(deadlineDescription, deadlineDate); itemArrayList.add(newDeadline); - outputAddedMessage(newDeadline); + Ui.printAddedMessage(itemArrayList, newDeadline); numItems += 1; } catch (EmptyDescriptionException e) { - printTaskDescriptionEmptyMessage(); + Ui.printTaskDescriptionEmptyMessage(); } catch (EmptyDateFieldException e) { System.out.println("\tError: Date field(s) cannot be empty"); } } - private void outputAddedMessage(Task task) { - System.out.println("\tGot it. I've added this task:"); - System.out.println("\t " + task); - System.out.println("\tNow you have " + (numItems+1) + " tasks in the list."); - } - private String extractTodoDescription(String line) throws EmptyDescriptionException { String todoDescription; todoDescription = line.replaceFirst("todo", "").trim(); @@ -218,45 +191,32 @@ public void markItem(String line) { int itemNum = Integer.parseInt(line.substring(5)); if (itemNum > this.getNumItems() || itemNum <= 0) { - printInputIndexOutOfRangeMessage(); + Ui.printInputIndexOutOfRangeMessage(); } else { this.markListItemAsDone(itemNum); - printTaskMarkedMessage(itemNum); + Ui.printTaskMarkedMessage(itemArrayList, itemNum); } } catch (NumberFormatException e) { - printInputIndexNotAnIntegerMessage(); + Ui.printInputIndexNotAnIntegerMessage(); } catch (Exception e) { - printUnknownErrorMessage(); + Ui.printUnknownErrorMessage(); } } - private static void printUnknownErrorMessage() { - System.out.println("Unknown error experienced."); - } - - private void printTaskMarkedMessage(int itemNum) { - System.out.println("\tNice! I've marked this task as done:"); - System.out.println("\t " + itemArrayList.get(itemNum - 1)); - } - - private static void printInputIndexOutOfRangeMessage() { - System.out.println("\tInput index number out of range."); - } - public void unmarkItem(String line) { try { int itemNum = Integer.parseInt(line.substring(7)); if (itemNum > this.getNumItems() || itemNum <= 0) { - printInputIndexOutOfRangeMessage(); + Ui.printInputIndexOutOfRangeMessage(); } else { this.markListItemAsUnDone(itemNum); printTaskUnmarkedMessage(itemNum); } } catch (NumberFormatException e) { - printInputIndexNotAnIntegerMessage(); + Ui.printInputIndexNotAnIntegerMessage(); } catch (Exception e) { - printUnknownErrorMessage(); + Ui.printUnknownErrorMessage(); } } @@ -265,10 +225,6 @@ private void printTaskUnmarkedMessage(int itemNum) { System.out.println("\t " + itemArrayList.get(itemNum - 1)); } - private static void printInputIndexNotAnIntegerMessage() { - System.out.println("\tInput index was not a integer."); - } - public void markListItemAsDone(int itemNum) { itemArrayList.get(itemNum - 1).markAsDone(); } @@ -282,16 +238,16 @@ public void deleteItem(String line) { int itemNum = Integer.parseInt(line.substring(7)); if (itemNum > this.getNumItems() || itemNum <= 0) { - printInputIndexOutOfRangeMessage(); + Ui.printInputIndexOutOfRangeMessage(); } else { Task deletedTask = itemArrayList.get(itemNum - 1); this.deleteListItem(itemNum); - printTaskDeletedMessage(deletedTask); + Ui.printTaskDeletedMessage(itemArrayList, deletedTask); } } catch (NumberFormatException e) { - printInputIndexNotAnIntegerMessage(); + Ui.printInputIndexNotAnIntegerMessage(); } catch (Exception e) { - printUnknownErrorMessage(); + Ui.printUnknownErrorMessage(); } } @@ -299,16 +255,10 @@ private void deleteListItem(int itemNum) { itemArrayList.remove(itemNum - 1); } - private void printTaskDeletedMessage(Task task) { - System.out.println("\tNoted. I've removed this task:"); - System.out.println("\t " + task); - System.out.println("\tNow you have " + itemArrayList.size() + " tasks in the list."); - } - public String getFormattedTasks() { String outputString = ""; for (Task a: itemArrayList) { - outputString += a.formattedTask() + System.lineSeparator(); + outputString += a.formattedTask() + System.lineSeparator(); } return outputString; } diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index 72ad2e204..c134c2795 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -9,7 +9,6 @@ public class Mel { - public static final String DRAW_HORIZONTAL_LINE = "\t________________________________________"; public static final int MARK_WORD_LEN = 4; public static final int UNMARK_WORD_LEN = 6; public static final int INPUT_SPACE_BUFFER = 2; @@ -23,7 +22,7 @@ private static void writeToFile(String filePath, String textToAdd) throws IOExce } public static void main(String[] args) throws IOException { - printIntroMessage(); + Ui.printIntroMessage(); // Set up scanner for user input Scanner in = new Scanner(System.in); @@ -120,42 +119,38 @@ private static void getUserInput(Scanner in, List userList) { line = getLine(in); if (isBye(line)) { - printByeMessage(); - printHorizontalLine(); + Ui.printByeMessage(); + Ui.printHorizontalLine(); break; } else if (isList(line)) { userList.printList(); - printHorizontalLine(); + Ui.printHorizontalLine(); } else if (isMark(line)) { userList.markItem(line); - printHorizontalLine(); + Ui.printHorizontalLine(); saveListToFile(userList); } else if (isUnmark(line)) { userList.unmarkItem(line); - printHorizontalLine(); + Ui.printHorizontalLine(); saveListToFile(userList); } else if (isDelete(line)) { userList.deleteItem(line); - printHorizontalLine(); + Ui.printHorizontalLine(); saveListToFile(userList); } else { userList.addItem(line); - printHorizontalLine(); + Ui.printHorizontalLine(); saveListToFile(userList); } } } - private static void printByeMessage() { - System.out.println("\tBye. Hope to see you again soon!"); - } - private static boolean isList(String line) { return line.equals("list"); } @@ -176,29 +171,12 @@ private static boolean isDelete(String line) { return line.length() >= (DELETE_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 6).equals("delete"); } - private static void printHorizontalLine() { - System.out.println(DRAW_HORIZONTAL_LINE); - } - private static String getLine(Scanner in) { String line; System.out.print(System.lineSeparator()); line = in.nextLine(); - printHorizontalLine(); + Ui.printHorizontalLine(); return line; } - private static void printIntroMessage() { - printHorizontalLine(); - System.out.println("\tHello! I'm"); - System.out.println("\t.___ ___. _______ __ \n" + - "\t| \\/ | | ____|| | \n" + - "\t| \\ / | | |__ | | \n" + - "\t| |\\/| | | __| | | \n" + - "\t| | | | | |____ | `----.\n" + - "\t|__| |__| |_______||_______|\n" + - "\t "); - System.out.println("\tWhat can I do for you?"); - printHorizontalLine(); - } } diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java new file mode 100644 index 000000000..13bc4e9ac --- /dev/null +++ b/src/main/java/Ui.java @@ -0,0 +1,77 @@ +import task.Task; + +import java.util.ArrayList; + +public class Ui { + public static final String DRAW_HORIZONTAL_LINE = "\t________________________________________"; + public static final String INVALID_EVENT_INPUT_MESSAGE = "event <event name> /from <start date/time> /end <end date/time>"; + public static final String INVALID_DEADLINE_INPUT_MESSAGE = "deadline <deadline name> /by <deadline>"; + public static final String INVALID_TODO_INPUT_MESSAGE = "todo <task name>"; + private static final String INVALID_MARK_MESSAGE = "mark <task index>"; + private static final String INVALID_UNMARK_MESSAGE = "unmark <task index>"; + private static final String INVALID_DELETE_MESSAGE = "delete <task index>"; + + public static void printHorizontalLine() { + System.out.println(DRAW_HORIZONTAL_LINE); + } + + public static void printIntroMessage() { + printHorizontalLine(); + System.out.println("\tHello! I'm"); + System.out.println("\t.___ ___. _______ __ \n" + + "\t| \\/ | | ____|| | \n" + + "\t| \\ / | | |__ | | \n" + + "\t| |\\/| | | __| | | \n" + + "\t| | | | | |____ | `----.\n" + + "\t|__| |__| |_______||_______|\n" + + "\t "); + System.out.println("\tWhat can I do for you?"); + printHorizontalLine(); + } + + public static void printByeMessage() { + System.out.println("\tBye. Hope to see you again soon!"); + } + + public static void printInvalidTaskMessage() { + System.out.println("\tInvalid command format:" + System.lineSeparator() + "\t\t" + INVALID_TODO_INPUT_MESSAGE + + System.lineSeparator() + "\t\t" + INVALID_DEADLINE_INPUT_MESSAGE + System.lineSeparator() + "\t\t" + + INVALID_EVENT_INPUT_MESSAGE + System.lineSeparator() + "\t\t" + + INVALID_MARK_MESSAGE + System.lineSeparator() + "\t\t" + + INVALID_UNMARK_MESSAGE + System.lineSeparator() + "\t\t" + + INVALID_DELETE_MESSAGE); + } + + public static void printTaskDescriptionEmptyMessage() { + System.out.println("\tError: The task description cannot be empty."); + } + + public static void printAddedMessage(ArrayList<Task> itemArrayList, Task task) { + System.out.println("\tGot it. I've added this task:"); + System.out.println("\t " + task); + System.out.println("\tNow you have " + (itemArrayList.size()) + " tasks in the list."); + } + + public static void printUnknownErrorMessage() { + System.out.println("Unknown error experienced."); + } + + public static void printTaskMarkedMessage(ArrayList<Task> itemArrayList, int itemNum) { + System.out.println("\tNice! I've marked this task as done:"); + System.out.println("\t " + itemArrayList.get(itemNum - 1)); + } + + public static void printInputIndexOutOfRangeMessage() { + System.out.println("\tInput index number out of range."); + } + + public static void printInputIndexNotAnIntegerMessage() { + System.out.println("\tInput index was not a integer."); + } + + public static void printTaskDeletedMessage(ArrayList<Task> itemArrayList, Task task) { + System.out.println("\tNoted. I've removed this task:"); + System.out.println("\t " + task); + System.out.println("\tNow you have " + itemArrayList.size() + " tasks in the list."); + } +} From a771dd7571fbc5a3ccd79d6986a51bef80a7c8e0 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Sat, 28 Sep 2024 19:32:54 +0800 Subject: [PATCH 47/76] Extract out closely related Storage code as a class --- src/main/java/Mel.java | 93 +++----------------------------------- src/main/java/Storage.java | 92 +++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 87 deletions(-) create mode 100644 src/main/java/Storage.java diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index c134c2795..d2eeb5076 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -15,12 +15,6 @@ public class Mel { private static final int DELETE_WORD_LEN = 6; private static final String LIST_FILE_PATH = ".\\data\\Mel.txt"; - private static void writeToFile(String filePath, String textToAdd) throws IOException { - FileWriter fw = new FileWriter(filePath); - fw.write(textToAdd); - fw.close(); - } - public static void main(String[] args) throws IOException { Ui.printIntroMessage(); @@ -29,8 +23,8 @@ public static void main(String[] args) throws IOException { List userList = new List(); try { - writerSetUp(LIST_FILE_PATH); - loadDataFromFile(LIST_FILE_PATH, userList); // Load saved tasks + Storage.writerSetUp(LIST_FILE_PATH); + Storage.loadDataFromFile(LIST_FILE_PATH, userList); // Load saved tasks } catch (IOException e) { System.out.println("An error occurred when setting up writer."); } @@ -38,81 +32,6 @@ public static void main(String[] args) throws IOException { getUserInput(in, userList); } - private static void writerSetUp(String filePath) throws IOException { - File listFile = new File(filePath); - if (!listFile.exists()) { - File directory = listFile.getParentFile(); - if (!directory.exists()) { - directory.mkdirs(); // Create directory if it doesn't exist - } - listFile.createNewFile(); // Create file if it doesn't exist - } - } - - public static void loadDataFromFile(String filePath, List userList) { - File file = new File(filePath); - try { - Scanner scanner = new Scanner(file); - while (scanner.hasNextLine()) { - String line = scanner.nextLine(); - parseAndAddItem(line, userList); - } - scanner.close(); - } catch (FileNotFoundException e) { - System.out.println("File not found: " + filePath); - } - } - - private static void parseAndAddItem(String line, List userList) { - String[] parts = line.split(" \\| "); - String taskType = parts[0]; // T, D, E - boolean isDone = parts[1].equals("X"); - String taskDescription = parts[2]; - - - switch (taskType) { - case "T": - Todo todoTask = new Todo(taskDescription); - if (isDone) { - todoTask.markAsDone(); - } - userList.itemArrayList.add(todoTask); - break; - - case "D": - String deadlineDate = parts[3]; // Ignore remaining parts - Deadline deadlineTask = new Deadline(taskDescription, deadlineDate); - if (isDone) { - deadlineTask.markAsDone(); - } - userList.itemArrayList.add(deadlineTask); - break; - - case "E": - String eventStart = parts[3]; // Start date/time - String eventEnd = parts[4]; // End date/time - Event eventTask = new Event(taskDescription, eventStart, eventEnd); - if (isDone) { - eventTask.markAsDone(); - } - userList.itemArrayList.add(eventTask); - break; - - default: - System.out.println("Invalid task type in file: " + taskType); - break; - } - } - - - private static void saveListToFile(List userList) { - try { - writeToFile(LIST_FILE_PATH, userList.getFormattedTasks()); // getFormattedTasks returns a formatted String - } catch (IOException e) { - System.out.println("An error occurred while saving the list."); - } - } - private static void getUserInput(Scanner in, List userList) { String line; while (true) { @@ -130,22 +49,22 @@ private static void getUserInput(Scanner in, List userList) { } else if (isMark(line)) { userList.markItem(line); Ui.printHorizontalLine(); - saveListToFile(userList); + Storage.saveListToFile(LIST_FILE_PATH, userList); } else if (isUnmark(line)) { userList.unmarkItem(line); Ui.printHorizontalLine(); - saveListToFile(userList); + Storage.saveListToFile(LIST_FILE_PATH, userList); } else if (isDelete(line)) { userList.deleteItem(line); Ui.printHorizontalLine(); - saveListToFile(userList); + Storage.saveListToFile(LIST_FILE_PATH, userList); } else { userList.addItem(line); Ui.printHorizontalLine(); - saveListToFile(userList); + Storage.saveListToFile(LIST_FILE_PATH, userList); } } diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java new file mode 100644 index 000000000..132d85f63 --- /dev/null +++ b/src/main/java/Storage.java @@ -0,0 +1,92 @@ +import task.Deadline; +import task.Event; +import task.Todo; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.util.Scanner; + +public class Storage { + private static void writeToFile(String filePath, String textToAdd) throws IOException { + FileWriter fw = new FileWriter(filePath); + fw.write(textToAdd); + fw.close(); + } + + public static void writerSetUp(String filePath) throws IOException { + File listFile = new File(filePath); + if (!listFile.exists()) { + File directory = listFile.getParentFile(); + if (!directory.exists()) { + directory.mkdirs(); // Create directory if it doesn't exist + } + listFile.createNewFile(); // Create file if it doesn't exist + } + } + + public static void loadDataFromFile(String filePath, List userList) { + File file = new File(filePath); + try { + Scanner scanner = new Scanner(file); + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + parseAndAddItem(line, userList); + } + scanner.close(); + } catch (FileNotFoundException e) { + System.out.println("File not found: " + filePath); + } + } + + private static void parseAndAddItem(String line, List userList) { + String[] parts = line.split(" \\| "); + String taskType = parts[0]; // T, D, E + boolean isDone = parts[1].equals("X"); + String taskDescription = parts[2]; + + + switch (taskType) { + case "T": + Todo todoTask = new Todo(taskDescription); + if (isDone) { + todoTask.markAsDone(); + } + userList.itemArrayList.add(todoTask); + break; + + case "D": + String deadlineDate = parts[3]; // Ignore remaining parts + Deadline deadlineTask = new Deadline(taskDescription, deadlineDate); + if (isDone) { + deadlineTask.markAsDone(); + } + userList.itemArrayList.add(deadlineTask); + break; + + case "E": + String eventStart = parts[3]; // Start date/time + String eventEnd = parts[4]; // End date/time + Event eventTask = new Event(taskDescription, eventStart, eventEnd); + if (isDone) { + eventTask.markAsDone(); + } + userList.itemArrayList.add(eventTask); + break; + + default: + System.out.println("Invalid task type in file: " + taskType); + break; + } + } + + public static void saveListToFile(String listFilePath, List userList) { + try { + writeToFile(listFilePath, userList.getFormattedTasks()); // getFormattedTasks returns a formatted String + } catch (IOException e) { + System.out.println("An error occurred while saving the list."); + } + } +} + From c6dac60b8c6ae9fbde8db9dbd07096b8b884ecc8 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Sat, 28 Sep 2024 19:41:18 +0800 Subject: [PATCH 48/76] Extract out closely related Parser code as a class --- src/main/java/Mel.java | 73 +------------------------------------- src/main/java/Parser.java | 74 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 72 deletions(-) create mode 100644 src/main/java/Parser.java diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index d2eeb5076..a10bade61 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -9,10 +9,6 @@ public class Mel { - public static final int MARK_WORD_LEN = 4; - public static final int UNMARK_WORD_LEN = 6; - public static final int INPUT_SPACE_BUFFER = 2; - private static final int DELETE_WORD_LEN = 6; private static final String LIST_FILE_PATH = ".\\data\\Mel.txt"; public static void main(String[] args) throws IOException { @@ -29,73 +25,6 @@ public static void main(String[] args) throws IOException { System.out.println("An error occurred when setting up writer."); } - getUserInput(in, userList); + Parser.getUserInput(in, LIST_FILE_PATH, userList); } - - private static void getUserInput(Scanner in, List userList) { - String line; - while (true) { - line = getLine(in); - - if (isBye(line)) { - Ui.printByeMessage(); - Ui.printHorizontalLine(); - break; - - } else if (isList(line)) { - userList.printList(); - Ui.printHorizontalLine(); - - } else if (isMark(line)) { - userList.markItem(line); - Ui.printHorizontalLine(); - Storage.saveListToFile(LIST_FILE_PATH, userList); - - } else if (isUnmark(line)) { - userList.unmarkItem(line); - Ui.printHorizontalLine(); - Storage.saveListToFile(LIST_FILE_PATH, userList); - - } else if (isDelete(line)) { - userList.deleteItem(line); - Ui.printHorizontalLine(); - Storage.saveListToFile(LIST_FILE_PATH, userList); - - } else { - userList.addItem(line); - Ui.printHorizontalLine(); - Storage.saveListToFile(LIST_FILE_PATH, userList); - - } - } - } - - private static boolean isList(String line) { - return line.equals("list"); - } - - private static boolean isBye(String line) { - return line.equals("bye"); - } - - private static boolean isMark(String line) { - return line.length() >= (MARK_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 4).equals("mark"); - } - - private static boolean isUnmark(String line) { - return line.length() >= (UNMARK_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 6).equals("unmark"); - } - - private static boolean isDelete(String line) { - return line.length() >= (DELETE_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 6).equals("delete"); - } - - private static String getLine(Scanner in) { - String line; - System.out.print(System.lineSeparator()); - line = in.nextLine(); - Ui.printHorizontalLine(); - return line; - } - } diff --git a/src/main/java/Parser.java b/src/main/java/Parser.java new file mode 100644 index 000000000..96866c797 --- /dev/null +++ b/src/main/java/Parser.java @@ -0,0 +1,74 @@ +import java.util.Scanner; + +public class Parser { + private static final int MARK_WORD_LEN = 4; + private static final int UNMARK_WORD_LEN = 6; + private static final int INPUT_SPACE_BUFFER = 2; + private static final int DELETE_WORD_LEN = 6; + + public static void getUserInput(Scanner in, String listFilePath, List userList) { + String line; + while (true) { + line = getLine(in); + + if (isBye(line)) { + Ui.printByeMessage(); + Ui.printHorizontalLine(); + break; + + } else if (isList(line)) { + userList.printList(); + Ui.printHorizontalLine(); + + } else if (isMark(line)) { + userList.markItem(line); + Ui.printHorizontalLine(); + Storage.saveListToFile(listFilePath, userList); + + } else if (isUnmark(line)) { + userList.unmarkItem(line); + Ui.printHorizontalLine(); + Storage.saveListToFile(listFilePath, userList); + + } else if (isDelete(line)) { + userList.deleteItem(line); + Ui.printHorizontalLine(); + Storage.saveListToFile(listFilePath, userList); + + } else { + userList.addItem(line); + Ui.printHorizontalLine(); + Storage.saveListToFile(listFilePath, userList); + + } + } + } + + private static String getLine(Scanner in) { + String line; + System.out.print(System.lineSeparator()); + line = in.nextLine(); + Ui.printHorizontalLine(); + return line; + } + + private static boolean isList(String line) { + return line.equals("list"); + } + + private static boolean isBye(String line) { + return line.equals("bye"); + } + + private static boolean isMark(String line) { + return line.length() >= (MARK_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 4).equals("mark"); + } + + private static boolean isUnmark(String line) { + return line.length() >= (UNMARK_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 6).equals("unmark"); + } + + private static boolean isDelete(String line) { + return line.length() >= (DELETE_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 6).equals("delete"); + } +} From 8f850470874e0e2d3d605b1effa86f06edf2dbe2 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Sat, 28 Sep 2024 19:43:16 +0800 Subject: [PATCH 49/76] Remove unused import statements --- src/main/java/Mel.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index a10bade61..2103fd353 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -1,11 +1,5 @@ -import java.io.File; import java.util.Scanner; -import java.io.FileWriter; import java.io.IOException; -import java.io.FileNotFoundException; -import task.Todo; // Import the Todo class -import task.Deadline; // Import the Deadline class -import task.Event; // Import the Event class public class Mel { From e852f3e3a3a6bd8c94e41301b040a7e214dc29cc Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Sat, 28 Sep 2024 20:11:56 +0800 Subject: [PATCH 50/76] Move printTaskUnmarkedMessage to Ui class --- src/main/java/List.java | 4 ---- src/main/java/Ui.java | 5 +++++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/List.java b/src/main/java/List.java index fd43f337d..c19572379 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -220,10 +220,6 @@ public void unmarkItem(String line) { } } - private void printTaskUnmarkedMessage(int itemNum) { - System.out.println("\tOK, I've marked this task as not done yet:"); - System.out.println("\t " + itemArrayList.get(itemNum - 1)); - } public void markListItemAsDone(int itemNum) { itemArrayList.get(itemNum - 1).markAsDone(); diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java index 13bc4e9ac..bd58eb792 100644 --- a/src/main/java/Ui.java +++ b/src/main/java/Ui.java @@ -61,6 +61,11 @@ public static void printTaskMarkedMessage(ArrayList<Task> itemArrayList, int ite System.out.println("\t " + itemArrayList.get(itemNum - 1)); } + public static void printTaskUnmarkedMessage(ArrayList<Task> itemArrayList, int itemNum) { + System.out.println("\tOK, I've marked this task as not done yet:"); + System.out.println("\t " + itemArrayList.get(itemNum - 1)); + } + public static void printInputIndexOutOfRangeMessage() { System.out.println("\tInput index number out of range."); } From 8ec7c4aae18bb19e88e80dc0189146ece787397e Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Sat, 28 Sep 2024 20:12:42 +0800 Subject: [PATCH 51/76] Refactor code to extract out closely related code as TaskList class --- src/main/java/List.java | 193 ++++-------------------------------- src/main/java/Parser.java | 106 ++++++++++++++++++++ src/main/java/TaskList.java | 66 ++++++++++++ 3 files changed, 189 insertions(+), 176 deletions(-) create mode 100644 src/main/java/TaskList.java diff --git a/src/main/java/List.java b/src/main/java/List.java index c19572379..e9d1935db 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -6,9 +6,6 @@ import java.util.Arrays; public class List { - public static final String DEADLINE_BY_KEYWORD = "/by"; - public static final String EVENT_FROM_KEYWORD = "/from"; - public static final String EVENT_TO_KEYWORD = "/to"; private int numItems; private Task[] itemList = new Task[0]; @@ -23,169 +20,17 @@ public int getNumItems() { } public void addItem(String line) { - if (isValidEvent(line)) { - addEvent(line); - } else if (isValidDeadline(line)) { - addDeadline(line); - } else if (isTodo(line)) { - addTodo(line); + if (Parser.isValidEvent(line)) { + TaskList.addEvent(itemArrayList, line); + } else if (Parser.isValidDeadline(line)) { + TaskList.addDeadline(itemArrayList, line); + } else if (Parser.isTodo(line)) { + TaskList.addTodo(itemArrayList, line); } else { Ui.printInvalidTaskMessage(); } } - private boolean isValidEvent(String line) { - return line.startsWith("event") && - line.contains(EVENT_FROM_KEYWORD) && - line.contains(EVENT_TO_KEYWORD); - } - - private boolean isValidDeadline(String line) { - return line.startsWith("deadline") && line.contains(DEADLINE_BY_KEYWORD); - } - - private boolean isTodo(String line) { - return line.startsWith("todo"); - } - - private void addEvent(String line) { - try { - String eventDescription = extractEventDescription(line); - String eventStartDate = extractEventStartDate(line); - String eventEndDate = extractEventEndDate(line); - Event newEvent = new Event(eventDescription, eventStartDate, eventEndDate); - itemArrayList.add(newEvent); - Ui.printAddedMessage(itemArrayList, newEvent); - numItems += 1; - } catch (EmptyDescriptionException e) { - Ui.printTaskDescriptionEmptyMessage(); - } catch (EmptyDateFieldException e) { - System.out.println("\tError: Date field(s) cannot be empty"); - } - } - - private void addTodo(String line) { - try { - String todoDescription = extractTodoDescription(line); - Todo newTodo = new Todo(todoDescription); - itemArrayList.add(newTodo); - Ui.printAddedMessage(itemArrayList, newTodo); - numItems += 1; - } catch (EmptyDescriptionException e) { - Ui.printTaskDescriptionEmptyMessage(); - } - } - - private void addDeadline(String line) { - try { - String deadlineDescription = extractDeadlineDescription(line); - String deadlineDate = extractDeadlineDate(line); - Deadline newDeadline = new Deadline(deadlineDescription, deadlineDate); - itemArrayList.add(newDeadline); - Ui.printAddedMessage(itemArrayList, newDeadline); - numItems += 1; - } catch (EmptyDescriptionException e) { - Ui.printTaskDescriptionEmptyMessage(); - } catch (EmptyDateFieldException e) { - System.out.println("\tError: Date field(s) cannot be empty"); - } - } - - private String extractTodoDescription(String line) throws EmptyDescriptionException { - String todoDescription; - todoDescription = line.replaceFirst("todo", "").trim(); - - taskDescriptionNotEmpty(todoDescription); - - return todoDescription; - } - - private String extractDeadlineDescription(String line) throws EmptyDescriptionException { - String deadlineDescription; - final int indexOfDeadlinePrefix = line.indexOf("/by"); - deadlineDescription = line.substring(0, indexOfDeadlinePrefix).replaceFirst("deadline", "").trim(); - - taskDescriptionNotEmpty(deadlineDescription); - - return deadlineDescription; - } - - private static void taskDescriptionNotEmpty(String taskDescription) throws EmptyDescriptionException { - if (taskDescription.isEmpty()) { - throw new EmptyDescriptionException(); - } - } - - private String extractDeadlineDate(String line) { - String deadlineDate; - final int indexOfDeadlinePrefix = line.indexOf("/by"); - deadlineDate = line.substring(indexOfDeadlinePrefix).replaceFirst("/by", "").trim(); - - dateFieldNotEmpty(deadlineDate); - - return deadlineDate; - } - - private static void dateFieldNotEmpty(String dateField) throws EmptyDateFieldException { - if (dateField.isEmpty()) { - throw new EmptyDateFieldException(); - } - } - - private String extractEventDescription(String line) throws EmptyDescriptionException { - String eventDescription; - final int indexOfStartDatePrefix = line.indexOf("/from"); - final int indexOfEndDatePrefix = line.indexOf("/to"); - if (indexOfEndDatePrefix > indexOfStartDatePrefix) { - eventDescription = line.substring(0, indexOfStartDatePrefix).replaceFirst("event", "").trim(); - } else { - eventDescription = line.substring(0, indexOfEndDatePrefix).replaceFirst("event", "").trim(); - } - - taskDescriptionNotEmpty(eventDescription); - - return eventDescription; - } - - private String extractEventEndDate(String line) { - String eventEndDate; - final int indexOfStartDatePrefix = line.indexOf("/from"); - final int indexOfEndDatePrefix = line.indexOf("/to"); - if (indexOfEndDatePrefix > indexOfStartDatePrefix) { - eventEndDate = line.substring(indexOfEndDatePrefix).replaceFirst("/to", "").trim(); - } else { - eventEndDate = line.substring(indexOfEndDatePrefix, indexOfStartDatePrefix).replaceFirst("/to", "").trim(); - } - - dateFieldNotEmpty(eventEndDate); - - return eventEndDate; - } - - private String extractEventStartDate(String line) { - String eventStartDate; - final int indexOfStartDatePrefix = line.indexOf("/from"); - final int indexOfEndDatePrefix = line.indexOf("/to"); - if (indexOfStartDatePrefix > indexOfEndDatePrefix) { - eventStartDate = line.substring(indexOfStartDatePrefix).replaceFirst("/from", "").trim(); - } else { - eventStartDate = line.substring(indexOfStartDatePrefix, indexOfEndDatePrefix).replaceFirst("/from", "").trim(); - } - - dateFieldNotEmpty(eventStartDate); - - return eventStartDate; - } - - public void printList() { - System.out.println("\tHere are the tasks in your list:"); - int i = 0; - for (Task a: itemArrayList) { - System.out.println("\t" + (i + 1) + "." + a); - i += 1; - } - } - public void markItem(String line) { try { int itemNum = Integer.parseInt(line.substring(5)); @@ -193,7 +38,7 @@ public void markItem(String line) { if (itemNum > this.getNumItems() || itemNum <= 0) { Ui.printInputIndexOutOfRangeMessage(); } else { - this.markListItemAsDone(itemNum); + TaskList.markListItemAsDone(itemArrayList, itemNum); Ui.printTaskMarkedMessage(itemArrayList, itemNum); } } catch (NumberFormatException e) { @@ -210,8 +55,8 @@ public void unmarkItem(String line) { if (itemNum > this.getNumItems() || itemNum <= 0) { Ui.printInputIndexOutOfRangeMessage(); } else { - this.markListItemAsUnDone(itemNum); - printTaskUnmarkedMessage(itemNum); + TaskList.markListItemAsUnDone(itemArrayList, itemNum); + Ui.printTaskUnmarkedMessage(itemArrayList, itemNum); } } catch (NumberFormatException e) { Ui.printInputIndexNotAnIntegerMessage(); @@ -220,15 +65,6 @@ public void unmarkItem(String line) { } } - - public void markListItemAsDone(int itemNum) { - itemArrayList.get(itemNum - 1).markAsDone(); - } - - public void markListItemAsUnDone(int itemNum) { - itemArrayList.get(itemNum - 1).markAsUnDone(); - } - public void deleteItem(String line) { try { int itemNum = Integer.parseInt(line.substring(7)); @@ -237,7 +73,7 @@ public void deleteItem(String line) { Ui.printInputIndexOutOfRangeMessage(); } else { Task deletedTask = itemArrayList.get(itemNum - 1); - this.deleteListItem(itemNum); + TaskList.deleteListItem(itemArrayList, itemNum); Ui.printTaskDeletedMessage(itemArrayList, deletedTask); } } catch (NumberFormatException e) { @@ -247,8 +83,13 @@ public void deleteItem(String line) { } } - private void deleteListItem(int itemNum) { - itemArrayList.remove(itemNum - 1); + public void printList() { + System.out.println("\tHere are the tasks in your list:"); + int i = 0; + for (Task a: itemArrayList) { + System.out.println("\t" + (i + 1) + "." + a); + i += 1; + } } public String getFormattedTasks() { diff --git a/src/main/java/Parser.java b/src/main/java/Parser.java index 96866c797..e08674158 100644 --- a/src/main/java/Parser.java +++ b/src/main/java/Parser.java @@ -1,3 +1,6 @@ +import exception.EmptyDateFieldException; +import exception.EmptyDescriptionException; + import java.util.Scanner; public class Parser { @@ -5,6 +8,9 @@ public class Parser { private static final int UNMARK_WORD_LEN = 6; private static final int INPUT_SPACE_BUFFER = 2; private static final int DELETE_WORD_LEN = 6; + public static final String DEADLINE_BY_KEYWORD = "/by"; + public static final String EVENT_FROM_KEYWORD = "/from"; + public static final String EVENT_TO_KEYWORD = "/to"; public static void getUserInput(Scanner in, String listFilePath, List userList) { String line; @@ -71,4 +77,104 @@ private static boolean isUnmark(String line) { private static boolean isDelete(String line) { return line.length() >= (DELETE_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 6).equals("delete"); } + + public static boolean isValidEvent(String line) { + return line.startsWith("event") && + line.contains(EVENT_FROM_KEYWORD) && + line.contains(EVENT_TO_KEYWORD); + } + + public static boolean isValidDeadline(String line) { + return line.startsWith("deadline") && line.contains(DEADLINE_BY_KEYWORD); + } + + public static boolean isTodo(String line) { + return line.startsWith("todo"); + } + + public static String extractTodoDescription(String line) throws EmptyDescriptionException { + String todoDescription; + todoDescription = line.replaceFirst("todo", "").trim(); + + taskDescriptionNotEmpty(todoDescription); + + return todoDescription; + } + + public static String extractDeadlineDescription(String line) throws EmptyDescriptionException { + String deadlineDescription; + final int indexOfDeadlinePrefix = line.indexOf("/by"); + deadlineDescription = line.substring(0, indexOfDeadlinePrefix).replaceFirst("deadline", "").trim(); + + taskDescriptionNotEmpty(deadlineDescription); + + return deadlineDescription; + } + + private static void taskDescriptionNotEmpty(String taskDescription) throws EmptyDescriptionException { + if (taskDescription.isEmpty()) { + throw new EmptyDescriptionException(); + } + } + + public static String extractDeadlineDate(String line) { + String deadlineDate; + final int indexOfDeadlinePrefix = line.indexOf("/by"); + deadlineDate = line.substring(indexOfDeadlinePrefix).replaceFirst("/by", "").trim(); + + dateFieldNotEmpty(deadlineDate); + + return deadlineDate; + } + + private static void dateFieldNotEmpty(String dateField) throws EmptyDateFieldException { + if (dateField.isEmpty()) { + throw new EmptyDateFieldException(); + } + } + + public static String extractEventDescription(String line) throws EmptyDescriptionException { + String eventDescription; + final int indexOfStartDatePrefix = line.indexOf("/from"); + final int indexOfEndDatePrefix = line.indexOf("/to"); + if (indexOfEndDatePrefix > indexOfStartDatePrefix) { + eventDescription = line.substring(0, indexOfStartDatePrefix).replaceFirst("event", "").trim(); + } else { + eventDescription = line.substring(0, indexOfEndDatePrefix).replaceFirst("event", "").trim(); + } + + taskDescriptionNotEmpty(eventDescription); + + return eventDescription; + } + + public static String extractEventEndDate(String line) { + String eventEndDate; + final int indexOfStartDatePrefix = line.indexOf("/from"); + final int indexOfEndDatePrefix = line.indexOf("/to"); + if (indexOfEndDatePrefix > indexOfStartDatePrefix) { + eventEndDate = line.substring(indexOfEndDatePrefix).replaceFirst("/to", "").trim(); + } else { + eventEndDate = line.substring(indexOfEndDatePrefix, indexOfStartDatePrefix).replaceFirst("/to", "").trim(); + } + + dateFieldNotEmpty(eventEndDate); + + return eventEndDate; + } + + public static String extractEventStartDate(String line) { + String eventStartDate; + final int indexOfStartDatePrefix = line.indexOf("/from"); + final int indexOfEndDatePrefix = line.indexOf("/to"); + if (indexOfStartDatePrefix > indexOfEndDatePrefix) { + eventStartDate = line.substring(indexOfStartDatePrefix).replaceFirst("/from", "").trim(); + } else { + eventStartDate = line.substring(indexOfStartDatePrefix, indexOfEndDatePrefix).replaceFirst("/from", "").trim(); + } + + dateFieldNotEmpty(eventStartDate); + + return eventStartDate; + } } diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java new file mode 100644 index 000000000..455c264ef --- /dev/null +++ b/src/main/java/TaskList.java @@ -0,0 +1,66 @@ +import exception.EmptyDateFieldException; +import exception.EmptyDescriptionException; +import task.Deadline; +import task.Event; +import task.Task; +import task.Todo; + +import java.util.ArrayList; + +public class TaskList { + + public static void addEvent(ArrayList<Task> itemArrayList, String line) { + try { + String eventDescription = Parser.extractEventDescription(line); + String eventStartDate = Parser.extractEventStartDate(line); + String eventEndDate = Parser.extractEventEndDate(line); + Event newEvent = new Event(eventDescription, eventStartDate, eventEndDate); + itemArrayList.add(newEvent); + Ui.printAddedMessage(itemArrayList, newEvent); + //numItems += 1; + } catch (EmptyDescriptionException e) { + Ui.printTaskDescriptionEmptyMessage(); + } catch (EmptyDateFieldException e) { + System.out.println("\tError: Date field(s) cannot be empty"); + } + } + + public static void addTodo(ArrayList<Task> itemArrayList, String line) { + try { + String todoDescription = Parser.extractTodoDescription(line); + Todo newTodo = new Todo(todoDescription); + itemArrayList.add(newTodo); + Ui.printAddedMessage(itemArrayList, newTodo); + //numItems += 1; + } catch (EmptyDescriptionException e) { + Ui.printTaskDescriptionEmptyMessage(); + } + } + + public static void addDeadline(ArrayList<Task> itemArrayList, String line) { + try { + String deadlineDescription = Parser.extractDeadlineDescription(line); + String deadlineDate = Parser.extractDeadlineDate(line); + Deadline newDeadline = new Deadline(deadlineDescription, deadlineDate); + itemArrayList.add(newDeadline); + Ui.printAddedMessage(itemArrayList, newDeadline); + //numItems += 1; + } catch (EmptyDescriptionException e) { + Ui.printTaskDescriptionEmptyMessage(); + } catch (EmptyDateFieldException e) { + System.out.println("\tError: Date field(s) cannot be empty"); + } + } + + public static void markListItemAsDone(ArrayList<Task> itemArrayList, int itemNum) { + itemArrayList.get(itemNum - 1).markAsDone(); + } + + public static void markListItemAsUnDone(ArrayList<Task> itemArrayList, int itemNum) { + itemArrayList.get(itemNum - 1).markAsUnDone(); + } + + public static void deleteListItem(ArrayList<Task> itemArrayList, int itemNum) { + itemArrayList.remove(itemNum - 1); + } +} From 1e461c09a88d323e270843c2de0c80b4e502280b Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Sat, 28 Sep 2024 21:43:56 +0800 Subject: [PATCH 52/76] Store and print deadline date and times --- src/main/java/Mel.java | 5 +++++ src/main/java/{ => main}/List.java | 4 ++-- src/main/java/{ => main}/Parser.java | 12 ++++++++---- src/main/java/{ => main}/Storage.java | 22 ++++++++++++++------- src/main/java/{ => main}/TaskList.java | 27 +++++++++++++++++++++++++- src/main/java/{ => main}/Ui.java | 2 ++ src/main/java/task/Deadline.java | 11 +++++++---- 7 files changed, 65 insertions(+), 18 deletions(-) rename src/main/java/{ => main}/List.java (97%) rename src/main/java/{ => main}/Parser.java (93%) rename src/main/java/{ => main}/Storage.java (77%) rename src/main/java/{ => main}/TaskList.java (68%) rename src/main/java/{ => main}/Ui.java (99%) diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index 2103fd353..75256f712 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -1,3 +1,8 @@ +import main.List; +import main.Parser; +import main.Storage; +import main.Ui; + import java.util.Scanner; import java.io.IOException; diff --git a/src/main/java/List.java b/src/main/java/main/List.java similarity index 97% rename from src/main/java/List.java rename to src/main/java/main/List.java index e9d1935db..b92c0cbaf 100644 --- a/src/main/java/List.java +++ b/src/main/java/main/List.java @@ -1,5 +1,5 @@ -import exception.EmptyDateFieldException; -import exception.EmptyDescriptionException; +package main; + import task.*; import java.util.ArrayList; diff --git a/src/main/java/Parser.java b/src/main/java/main/Parser.java similarity index 93% rename from src/main/java/Parser.java rename to src/main/java/main/Parser.java index e08674158..3ae62e813 100644 --- a/src/main/java/Parser.java +++ b/src/main/java/main/Parser.java @@ -1,6 +1,9 @@ +package main; + import exception.EmptyDateFieldException; import exception.EmptyDescriptionException; +import java.time.LocalDateTime; import java.util.Scanner; public class Parser { @@ -117,12 +120,13 @@ private static void taskDescriptionNotEmpty(String taskDescription) throws Empty } } - public static String extractDeadlineDate(String line) { - String deadlineDate; + public static LocalDateTime extractDeadlineDate(String line) { + LocalDateTime deadlineDate; final int indexOfDeadlinePrefix = line.indexOf("/by"); - deadlineDate = line.substring(indexOfDeadlinePrefix).replaceFirst("/by", "").trim(); + String deadlineDateString = line.substring(indexOfDeadlinePrefix).replaceFirst("/by", "").trim(); - dateFieldNotEmpty(deadlineDate); + dateFieldNotEmpty(deadlineDateString); + deadlineDate = TaskList.convertDeadlineDateAsLocalDateTime(deadlineDateString); return deadlineDate; } diff --git a/src/main/java/Storage.java b/src/main/java/main/Storage.java similarity index 77% rename from src/main/java/Storage.java rename to src/main/java/main/Storage.java index 132d85f63..5fd504ddd 100644 --- a/src/main/java/Storage.java +++ b/src/main/java/main/Storage.java @@ -1,3 +1,5 @@ +package main; + import task.Deadline; import task.Event; import task.Todo; @@ -6,6 +8,8 @@ import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; +import java.time.DateTimeException; +import java.time.LocalDateTime; import java.util.Scanner; public class Storage { @@ -57,12 +61,16 @@ private static void parseAndAddItem(String line, List userList) { break; case "D": - String deadlineDate = parts[3]; // Ignore remaining parts - Deadline deadlineTask = new Deadline(taskDescription, deadlineDate); - if (isDone) { - deadlineTask.markAsDone(); + try { + LocalDateTime deadlineDate = TaskList.getDeadlineDateAsLocalDateTimeFromFile(parts[3]); // Ignore remaining parts + Deadline deadlineTask = new Deadline(taskDescription, deadlineDate); + if (isDone) { + deadlineTask.markAsDone(); + } + userList.itemArrayList.add(deadlineTask); + } catch (DateTimeException e) { + System.out.println("\tInvalid date format: yyyy-mm-dd HH:mm"); } - userList.itemArrayList.add(deadlineTask); break; case "E": @@ -76,7 +84,7 @@ private static void parseAndAddItem(String line, List userList) { break; default: - System.out.println("Invalid task type in file: " + taskType); + System.out.println("\tInvalid task type in file: " + taskType); break; } } @@ -85,7 +93,7 @@ public static void saveListToFile(String listFilePath, List userList) { try { writeToFile(listFilePath, userList.getFormattedTasks()); // getFormattedTasks returns a formatted String } catch (IOException e) { - System.out.println("An error occurred while saving the list."); + System.out.println("\tAn error occurred while saving the list."); } } } diff --git a/src/main/java/TaskList.java b/src/main/java/main/TaskList.java similarity index 68% rename from src/main/java/TaskList.java rename to src/main/java/main/TaskList.java index 455c264ef..1785f6eda 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/main/TaskList.java @@ -1,3 +1,5 @@ +package main; + import exception.EmptyDateFieldException; import exception.EmptyDescriptionException; import task.Deadline; @@ -5,7 +7,10 @@ import task.Task; import task.Todo; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; +import java.time.DateTimeException; public class TaskList { @@ -40,7 +45,7 @@ public static void addTodo(ArrayList<Task> itemArrayList, String line) { public static void addDeadline(ArrayList<Task> itemArrayList, String line) { try { String deadlineDescription = Parser.extractDeadlineDescription(line); - String deadlineDate = Parser.extractDeadlineDate(line); + LocalDateTime deadlineDate = Parser.extractDeadlineDate(line); Deadline newDeadline = new Deadline(deadlineDescription, deadlineDate); itemArrayList.add(newDeadline); Ui.printAddedMessage(itemArrayList, newDeadline); @@ -49,6 +54,8 @@ public static void addDeadline(ArrayList<Task> itemArrayList, String line) { Ui.printTaskDescriptionEmptyMessage(); } catch (EmptyDateFieldException e) { System.out.println("\tError: Date field(s) cannot be empty"); + } catch (DateTimeException e) { + System.out.println("\tInvalid date format: yyyy-mm-dd HH:mm"); } } @@ -63,4 +70,22 @@ public static void markListItemAsUnDone(ArrayList<Task> itemArrayList, int itemN public static void deleteListItem(ArrayList<Task> itemArrayList, int itemNum) { itemArrayList.remove(itemNum - 1); } + + public static LocalDateTime convertDeadlineDateAsLocalDateTime(String deadlineDate) { + DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + return LocalDateTime.parse(deadlineDate, inputFormatter); + } + + + public static LocalDateTime getDeadlineDateAsLocalDateTimeFromFile(String deadlineDate) { + DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("MMM dd yyyy, h:mm a"); + return LocalDateTime.parse(deadlineDate, inputFormatter); + } + + public static String convertDeadlineDateAsString(LocalDateTime dateTime) { + DateTimeFormatter outputformatter = DateTimeFormatter.ofPattern("MMM dd yyyy, h:mm a"); + String formattedDateTime = dateTime.format(outputformatter); // "1986-04-08 12:30" + + return formattedDateTime; + } } diff --git a/src/main/java/Ui.java b/src/main/java/main/Ui.java similarity index 99% rename from src/main/java/Ui.java rename to src/main/java/main/Ui.java index bd58eb792..3de4d14e6 100644 --- a/src/main/java/Ui.java +++ b/src/main/java/main/Ui.java @@ -1,3 +1,5 @@ +package main; + import task.Task; import java.util.ArrayList; diff --git a/src/main/java/task/Deadline.java b/src/main/java/task/Deadline.java index 2e024b3d4..8f33a10f9 100644 --- a/src/main/java/task/Deadline.java +++ b/src/main/java/task/Deadline.java @@ -1,22 +1,25 @@ package task; +import java.time.LocalDateTime; +import main.TaskList; + public class Deadline extends Task { - protected String by; + protected LocalDateTime by; - public Deadline(String description, String by) { + public Deadline(String description, LocalDateTime by) { super(description); this.by = by; } @Override public String toString() { - return ("[D][" + getDoneStatusIcon() + "] " + description + " (by: " + by + ")"); + return ("[D][" + getDoneStatusIcon() + "] " + description + " (by: " + TaskList.convertDeadlineDateAsString(by) + ")"); } @Override public String formattedTask() { - return ("D | " + getDoneStatusIcon() + " | " + description + " | " + by); + return ("D | " + getDoneStatusIcon() + " | " + description + " | " + TaskList.convertDeadlineDateAsString(by)); } } From dd88dd5b5c1495fc902953986598fe837a56fb5c Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Sat, 28 Sep 2024 22:47:31 +0800 Subject: [PATCH 53/76] Add find task function --- src/main/java/List.java | 27 +++++++++++++++++++++++++++ src/main/java/Parser.java | 14 ++++++++++++++ src/main/java/TaskList.java | 1 + src/main/java/Ui.java | 4 ++++ 4 files changed, 46 insertions(+) diff --git a/src/main/java/List.java b/src/main/java/List.java index e9d1935db..23f988185 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -99,4 +99,31 @@ public String getFormattedTasks() { } return outputString; } + + public void findItem(String line) { + try { + String findDescription = Parser.extractFindDescription(line); + ArrayList<Task> matchedArrayList = new ArrayList<>(itemArrayList); // Safe copy of the original list + + int i = 0; + while (i < matchedArrayList.size()) { + Task t = matchedArrayList.get(i); + + if (!t.getDescription().contains(findDescription)) { + matchedArrayList.remove(t); + } else { + i += 1; + } + } + + System.out.println("\tHere are the matching tasks in your list:"); + int j = 0; + for (Task a: matchedArrayList) { + System.out.println("\t" + (j + 1) + "." + a); + j += 1; + } + } catch (EmptyDescriptionException e) { + Ui.printFindDescriptionEmptyMessage(); + } + } } diff --git a/src/main/java/Parser.java b/src/main/java/Parser.java index e08674158..12293b235 100644 --- a/src/main/java/Parser.java +++ b/src/main/java/Parser.java @@ -41,6 +41,9 @@ public static void getUserInput(Scanner in, String listFilePath, List userList) Ui.printHorizontalLine(); Storage.saveListToFile(listFilePath, userList); + } else if (isFind(line)) { + userList.findItem(line); + Ui.printHorizontalLine(); } else { userList.addItem(line); Ui.printHorizontalLine(); @@ -76,6 +79,8 @@ private static boolean isUnmark(String line) { private static boolean isDelete(String line) { return line.length() >= (DELETE_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 6).equals("delete"); + public static boolean isFind(String line) { + return line.startsWith("find "); } public static boolean isValidEvent(String line) { @@ -101,6 +106,15 @@ public static String extractTodoDescription(String line) throws EmptyDescription return todoDescription; } + public static String extractFindDescription(String line) throws EmptyDescriptionException { + String findDescription; + findDescription = line.replaceFirst("find", "").trim(); + + taskDescriptionNotEmpty(findDescription); + + return findDescription; + } + public static String extractDeadlineDescription(String line) throws EmptyDescriptionException { String deadlineDescription; final int indexOfDeadlinePrefix = line.indexOf("/by"); diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index 455c264ef..82ba647f0 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -63,4 +63,5 @@ public static void markListItemAsUnDone(ArrayList<Task> itemArrayList, int itemN public static void deleteListItem(ArrayList<Task> itemArrayList, int itemNum) { itemArrayList.remove(itemNum - 1); } + } diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java index bd58eb792..31c72a7b9 100644 --- a/src/main/java/Ui.java +++ b/src/main/java/Ui.java @@ -46,6 +46,10 @@ public static void printTaskDescriptionEmptyMessage() { System.out.println("\tError: The task description cannot be empty."); } + public static void printFindDescriptionEmptyMessage() { + System.out.println("\tError: The find description cannot be empty."); + } + public static void printAddedMessage(ArrayList<Task> itemArrayList, Task task) { System.out.println("\tGot it. I've added this task:"); System.out.println("\t " + task); From e243b9d08bb8d94dfcbe47a41c6db2073a6b7426 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Sat, 28 Sep 2024 22:50:19 +0800 Subject: [PATCH 54/76] Fix task description extraction --- src/main/java/Parser.java | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/main/java/Parser.java b/src/main/java/Parser.java index 12293b235..a7fd240d9 100644 --- a/src/main/java/Parser.java +++ b/src/main/java/Parser.java @@ -69,32 +69,34 @@ private static boolean isBye(String line) { return line.equals("bye"); } - private static boolean isMark(String line) { - return line.length() >= (MARK_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 4).equals("mark"); + public static boolean isMark(String line) { + return line.startsWith("mark "); } - private static boolean isUnmark(String line) { - return line.length() >= (UNMARK_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 6).equals("unmark"); + public static boolean isUnmark(String line) { + return line.startsWith("unmark "); + } + + public static boolean isDelete(String line) { + return line.startsWith("delete "); } - private static boolean isDelete(String line) { - return line.length() >= (DELETE_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 6).equals("delete"); public static boolean isFind(String line) { return line.startsWith("find "); } public static boolean isValidEvent(String line) { - return line.startsWith("event") && + return line.startsWith("event ") && line.contains(EVENT_FROM_KEYWORD) && line.contains(EVENT_TO_KEYWORD); } public static boolean isValidDeadline(String line) { - return line.startsWith("deadline") && line.contains(DEADLINE_BY_KEYWORD); + return line.startsWith("deadline ") && line.contains(DEADLINE_BY_KEYWORD); } public static boolean isTodo(String line) { - return line.startsWith("todo"); + return line.startsWith("todo "); } public static String extractTodoDescription(String line) throws EmptyDescriptionException { From 3640c38e65af19cbafd7c0a8deb311310795a142 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Sat, 28 Sep 2024 22:57:23 +0800 Subject: [PATCH 55/76] Update test case --- text-ui-test/EXPECTED.TXT | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 4f32b246a..dab84dfd8 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -103,7 +103,13 @@ ________________________________________ ________________________________________ - Error: The task description cannot be empty. + Invalid command format: + todo <task name> + deadline <deadline name> /by <deadline> + event <event name> /from <start date/time> /end <end date/time> + mark <task index> + unmark <task index> + delete <task index> ________________________________________ ________________________________________ From 19929244509a7841561284776a985e65a443b945 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Sat, 28 Sep 2024 23:39:20 +0800 Subject: [PATCH 56/76] Add JavaDoc comments to the code --- src/main/java/List.java | 52 +++++++++++++++++-- src/main/java/Parser.java | 101 ++++++++++++++++++++++++++++++++++++ src/main/java/Storage.java | 32 +++++++++++- src/main/java/TaskList.java | 53 +++++++++++++++++-- src/main/java/Ui.java | 52 +++++++++++++++++++ 5 files changed, 283 insertions(+), 7 deletions(-) diff --git a/src/main/java/List.java b/src/main/java/List.java index e9d1935db..09b7b795b 100644 --- a/src/main/java/List.java +++ b/src/main/java/List.java @@ -5,20 +5,39 @@ import java.util.ArrayList; import java.util.Arrays; +/** + * Manages the list of tasks. Provides functionality to add, mark, unmark, delete, + * and print tasks. Also provides formatted task output. + */ public class List { private int numItems; private Task[] itemList = new Task[0]; ArrayList<Task> itemArrayList = new ArrayList<>(Arrays.asList(itemList)); + /** + * Constructs an empty task list with no items. + */ public List() { this.numItems = 0; } + /** + * Returns the number of tasks in the list. + * + * @return The number of tasks in the list. + */ public int getNumItems() { return itemArrayList.size(); } + /** + * Adds a new task to the list based on the user input. + * It checks whether the task is an event, deadline, or todo, + * and adds it accordingly. If the task is invalid, an error message is printed. + * + * @param line The user input containing task information. + */ public void addItem(String line) { if (Parser.isValidEvent(line)) { TaskList.addEvent(itemArrayList, line); @@ -31,6 +50,12 @@ public void addItem(String line) { } } + /** + * Marks a task in the list as done based on the user input. + * If the task number is invalid or out of range, an error message is printed. + * + * @param line The user input containing the task number to mark. + */ public void markItem(String line) { try { int itemNum = Integer.parseInt(line.substring(5)); @@ -41,13 +66,19 @@ public void markItem(String line) { TaskList.markListItemAsDone(itemArrayList, itemNum); Ui.printTaskMarkedMessage(itemArrayList, itemNum); } - } catch (NumberFormatException e) { + } catch (NumberFormatException e) { Ui.printInputIndexNotAnIntegerMessage(); } catch (Exception e) { Ui.printUnknownErrorMessage(); } } + /** + * Unmarks a task in the list as not done based on the user input. + * If the task number is invalid or out of range, an error message is printed. + * + * @param line The user input containing the task number to unmark. + */ public void unmarkItem(String line) { try { int itemNum = Integer.parseInt(line.substring(7)); @@ -58,13 +89,19 @@ public void unmarkItem(String line) { TaskList.markListItemAsUnDone(itemArrayList, itemNum); Ui.printTaskUnmarkedMessage(itemArrayList, itemNum); } - } catch (NumberFormatException e) { + } catch (NumberFormatException e) { Ui.printInputIndexNotAnIntegerMessage(); } catch (Exception e) { Ui.printUnknownErrorMessage(); } } + /** + * Deletes a task from the list based on the user input. + * If the task number is invalid or out of range, an error message is printed. + * + * @param line The user input containing the task number to delete. + */ public void deleteItem(String line) { try { int itemNum = Integer.parseInt(line.substring(7)); @@ -76,13 +113,16 @@ public void deleteItem(String line) { TaskList.deleteListItem(itemArrayList, itemNum); Ui.printTaskDeletedMessage(itemArrayList, deletedTask); } - } catch (NumberFormatException e) { + } catch (NumberFormatException e) { Ui.printInputIndexNotAnIntegerMessage(); } catch (Exception e) { Ui.printUnknownErrorMessage(); } } + /** + * Prints the current list of tasks to the console. + */ public void printList() { System.out.println("\tHere are the tasks in your list:"); int i = 0; @@ -92,6 +132,12 @@ public void printList() { } } + /** + * Returns the formatted string representation of all tasks in the list. + * Each task is formatted based on its type and details. + * + * @return A string representing the formatted tasks. + */ public String getFormattedTasks() { String outputString = ""; for (Task a: itemArrayList) { diff --git a/src/main/java/Parser.java b/src/main/java/Parser.java index e08674158..d0786c27d 100644 --- a/src/main/java/Parser.java +++ b/src/main/java/Parser.java @@ -3,6 +3,10 @@ import java.util.Scanner; +/** + * The Parser class is responsible for interpreting user inputs and extracting the relevant information + * to perform the appropriate actions on the task list. + */ public class Parser { private static final int MARK_WORD_LEN = 4; private static final int UNMARK_WORD_LEN = 6; @@ -12,6 +16,12 @@ public class Parser { public static final String EVENT_FROM_KEYWORD = "/from"; public static final String EVENT_TO_KEYWORD = "/to"; + /** + * Continuously reads user input and interprets the commands to modify the task list. + * @param in Scanner to read user input. + * @param listFilePath Path to the file where the list is stored. + * @param userList The current task list. + */ public static void getUserInput(Scanner in, String listFilePath, List userList) { String line; while (true) { @@ -50,6 +60,11 @@ public static void getUserInput(Scanner in, String listFilePath, List userList) } } + /** + * Reads a line of input from the user and prints a horizontal line after the input. + * @param in Scanner to read user input. + * @return The user input line as a string. + */ private static String getLine(Scanner in) { String line; System.out.print(System.lineSeparator()); @@ -58,40 +73,86 @@ private static String getLine(Scanner in) { return line; } + /** + * Checks if the input command is to list all tasks. + * @param line The input string. + * @return True if the command is "list", false otherwise. + */ private static boolean isList(String line) { return line.equals("list"); } + /** + * Checks if the input command is to exit the program. + * @param line The input string. + * @return True if the command is "bye", false otherwise. + */ private static boolean isBye(String line) { return line.equals("bye"); } + /** + * Checks if the input command is to mark a task as done. + * @param line The input string. + * @return True if the command starts with "mark", false otherwise. + */ private static boolean isMark(String line) { return line.length() >= (MARK_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 4).equals("mark"); } + /** + * Checks if the input command is to unmark a task (mark it as not done). + * @param line The input string. + * @return True if the command starts with "unmark", false otherwise. + */ private static boolean isUnmark(String line) { return line.length() >= (UNMARK_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 6).equals("unmark"); } + /** + * Checks if the input command is to delete a task. + * @param line The input string. + * @return True if the command starts with "delete", false otherwise. + */ private static boolean isDelete(String line) { return line.length() >= (DELETE_WORD_LEN + INPUT_SPACE_BUFFER) && line.substring(0, 6).equals("delete"); } + /** + * Checks if the input string is a valid event format. + * @param line The input string. + * @return True if the command contains an event with the proper format. + */ public static boolean isValidEvent(String line) { return line.startsWith("event") && line.contains(EVENT_FROM_KEYWORD) && line.contains(EVENT_TO_KEYWORD); } + /** + * Checks if the input string is a valid deadline format. + * @param line The input string. + * @return True if the command contains a deadline with the "/by" keyword. + */ public static boolean isValidDeadline(String line) { return line.startsWith("deadline") && line.contains(DEADLINE_BY_KEYWORD); } + /** + * Checks if the input string is a valid todo task. + * @param line The input string. + * @return True if the command starts with "todo". + */ public static boolean isTodo(String line) { return line.startsWith("todo"); } + /** + * Extracts the description from a todo command. + * @param line The input string. + * @return The description of the todo task. + * @throws EmptyDescriptionException if the description is empty. + */ public static String extractTodoDescription(String line) throws EmptyDescriptionException { String todoDescription; todoDescription = line.replaceFirst("todo", "").trim(); @@ -101,6 +162,12 @@ public static String extractTodoDescription(String line) throws EmptyDescription return todoDescription; } + /** + * Extracts the description from a deadline command. + * @param line The input string. + * @return The description of the deadline task. + * @throws EmptyDescriptionException if the description is empty. + */ public static String extractDeadlineDescription(String line) throws EmptyDescriptionException { String deadlineDescription; final int indexOfDeadlinePrefix = line.indexOf("/by"); @@ -111,12 +178,23 @@ public static String extractDeadlineDescription(String line) throws EmptyDescrip return deadlineDescription; } + /** + * Checks if a task description is not empty. + * @param taskDescription The task description to be checked. + * @throws EmptyDescriptionException if the description is empty. + */ private static void taskDescriptionNotEmpty(String taskDescription) throws EmptyDescriptionException { if (taskDescription.isEmpty()) { throw new EmptyDescriptionException(); } } + /** + * Extracts the date from a deadline command. + * @param line The input string. + * @return The date of the deadline. + * @throws EmptyDateFieldException if the date field is empty. + */ public static String extractDeadlineDate(String line) { String deadlineDate; final int indexOfDeadlinePrefix = line.indexOf("/by"); @@ -127,12 +205,23 @@ public static String extractDeadlineDate(String line) { return deadlineDate; } + /** + * Checks if a date field is not empty. + * @param dateField The date field to be checked. + * @throws EmptyDateFieldException if the date field is empty. + */ private static void dateFieldNotEmpty(String dateField) throws EmptyDateFieldException { if (dateField.isEmpty()) { throw new EmptyDateFieldException(); } } + /** + * Extracts the description from an event command. + * @param line The input string. + * @return The description of the event. + * @throws EmptyDescriptionException if the description is empty. + */ public static String extractEventDescription(String line) throws EmptyDescriptionException { String eventDescription; final int indexOfStartDatePrefix = line.indexOf("/from"); @@ -148,6 +237,12 @@ public static String extractEventDescription(String line) throws EmptyDescriptio return eventDescription; } + /** + * Extracts the end date from an event command. + * @param line The input string. + * @return The end date of the event. + * @throws EmptyDateFieldException if the date field is empty. + */ public static String extractEventEndDate(String line) { String eventEndDate; final int indexOfStartDatePrefix = line.indexOf("/from"); @@ -164,6 +259,12 @@ public static String extractEventEndDate(String line) { } public static String extractEventStartDate(String line) { + /** + * Extracts the start date from an event command. + * @param line The input string. + * @return The start date of the event. + * @throws EmptyDateFieldException if the date field is empty. + */ String eventStartDate; final int indexOfStartDatePrefix = line.indexOf("/from"); final int indexOfEndDatePrefix = line.indexOf("/to"); diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java index 132d85f63..6a40d711f 100644 --- a/src/main/java/Storage.java +++ b/src/main/java/Storage.java @@ -8,13 +8,29 @@ import java.io.IOException; import java.util.Scanner; +/** + * The Storage class handles loading and saving task data to and from a file. + */ public class Storage { + + /** + * Writes the given text to a specified file. + * @param filePath The path of the file to write to. + * @param textToAdd The text to add to the file. + * @throws IOException If an I/O error occurs while writing to the file. + */ private static void writeToFile(String filePath, String textToAdd) throws IOException { FileWriter fw = new FileWriter(filePath); fw.write(textToAdd); fw.close(); } + /** + * Sets up the file by creating a new file if it does not exist. + * Also creates the parent directory if it doesn't exist. + * @param filePath The path of the file to set up. + * @throws IOException If an I/O error occurs while setting up the file. + */ public static void writerSetUp(String filePath) throws IOException { File listFile = new File(filePath); if (!listFile.exists()) { @@ -26,6 +42,11 @@ public static void writerSetUp(String filePath) throws IOException { } } + /** + * Loads task data from a file and adds it to the provided user list. + * @param filePath The path of the file to load data from. + * @param userList The list where the tasks will be added. + */ public static void loadDataFromFile(String filePath, List userList) { File file = new File(filePath); try { @@ -40,13 +61,17 @@ public static void loadDataFromFile(String filePath, List userList) { } } + /** + * Parses a line from the file and adds the corresponding task to the user list. + * @param line The line to parse. + * @param userList The list where the task will be added. + */ private static void parseAndAddItem(String line, List userList) { String[] parts = line.split(" \\| "); String taskType = parts[0]; // T, D, E boolean isDone = parts[1].equals("X"); String taskDescription = parts[2]; - switch (taskType) { case "T": Todo todoTask = new Todo(taskDescription); @@ -81,6 +106,11 @@ private static void parseAndAddItem(String line, List userList) { } } + /** + * Saves the current task list to the specified file. + * @param listFilePath The path of the file to save the list to. + * @param userList The list containing tasks to save. + */ public static void saveListToFile(String listFilePath, List userList) { try { writeToFile(listFilePath, userList.getFormattedTasks()); // getFormattedTasks returns a formatted String diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java index 455c264ef..d7328646d 100644 --- a/src/main/java/TaskList.java +++ b/src/main/java/TaskList.java @@ -7,8 +7,22 @@ import java.util.ArrayList; +/** + * Manages the list of tasks. This class provides functionality to + * add tasks (events, todos, deadlines) and mark or delete tasks + * in the task list. + */ public class TaskList { + /** + * Adds an event task to the provided task list. + * The event contains a description, start date, and end date. + * + * @param itemArrayList The list of tasks to add the event to. + * @param line The user input containing the event description, start date, and end date. + * @throws EmptyDescriptionException If the event description is missing. + * @throws EmptyDateFieldException If the event start or end date is missing. + */ public static void addEvent(ArrayList<Task> itemArrayList, String line) { try { String eventDescription = Parser.extractEventDescription(line); @@ -17,7 +31,6 @@ public static void addEvent(ArrayList<Task> itemArrayList, String line) { Event newEvent = new Event(eventDescription, eventStartDate, eventEndDate); itemArrayList.add(newEvent); Ui.printAddedMessage(itemArrayList, newEvent); - //numItems += 1; } catch (EmptyDescriptionException e) { Ui.printTaskDescriptionEmptyMessage(); } catch (EmptyDateFieldException e) { @@ -25,18 +38,34 @@ public static void addEvent(ArrayList<Task> itemArrayList, String line) { } } + /** + * Adds a todo task to the provided task list. + * The todo contains only a description. + * + * @param itemArrayList The list of tasks to add the todo to. + * @param line The user input containing the todo description. + * @throws EmptyDescriptionException If the todo description is missing. + */ public static void addTodo(ArrayList<Task> itemArrayList, String line) { try { String todoDescription = Parser.extractTodoDescription(line); Todo newTodo = new Todo(todoDescription); itemArrayList.add(newTodo); Ui.printAddedMessage(itemArrayList, newTodo); - //numItems += 1; } catch (EmptyDescriptionException e) { Ui.printTaskDescriptionEmptyMessage(); } } + /** + * Adds a deadline task to the provided task list. + * The deadline contains a description and a due date. + * + * @param itemArrayList The list of tasks to add the deadline to. + * @param line The user input containing the deadline description and date. + * @throws EmptyDescriptionException If the deadline description is missing. + * @throws EmptyDateFieldException If the deadline date is missing. + */ public static void addDeadline(ArrayList<Task> itemArrayList, String line) { try { String deadlineDescription = Parser.extractDeadlineDescription(line); @@ -44,7 +73,6 @@ public static void addDeadline(ArrayList<Task> itemArrayList, String line) { Deadline newDeadline = new Deadline(deadlineDescription, deadlineDate); itemArrayList.add(newDeadline); Ui.printAddedMessage(itemArrayList, newDeadline); - //numItems += 1; } catch (EmptyDescriptionException e) { Ui.printTaskDescriptionEmptyMessage(); } catch (EmptyDateFieldException e) { @@ -52,15 +80,34 @@ public static void addDeadline(ArrayList<Task> itemArrayList, String line) { } } + /** + * Marks a task in the task list as done. + * + * @param itemArrayList The list of tasks. + * @param itemNum The task number to be marked as done. + */ public static void markListItemAsDone(ArrayList<Task> itemArrayList, int itemNum) { itemArrayList.get(itemNum - 1).markAsDone(); } + /** + * Marks a task in the task list as not done. + * + * @param itemArrayList The list of tasks. + * @param itemNum The task number to be marked as not done. + */ public static void markListItemAsUnDone(ArrayList<Task> itemArrayList, int itemNum) { itemArrayList.get(itemNum - 1).markAsUnDone(); } + /** + * Deletes a task from the task list. + * + * @param itemArrayList The list of tasks. + * @param itemNum The task number to be deleted. + */ public static void deleteListItem(ArrayList<Task> itemArrayList, int itemNum) { itemArrayList.remove(itemNum - 1); } } + diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java index bd58eb792..7ffb601fc 100644 --- a/src/main/java/Ui.java +++ b/src/main/java/Ui.java @@ -2,7 +2,12 @@ import java.util.ArrayList; +/** + * The Ui class handles all the user interface interactions by displaying messages to the user. + * It provides methods to print responses, error messages, and updates about the tasks list. + */ public class Ui { + public static final String DRAW_HORIZONTAL_LINE = "\t________________________________________"; public static final String INVALID_EVENT_INPUT_MESSAGE = "event <event name> /from <start date/time> /end <end date/time>"; public static final String INVALID_DEADLINE_INPUT_MESSAGE = "deadline <deadline name> /by <deadline>"; @@ -11,10 +16,16 @@ public class Ui { private static final String INVALID_UNMARK_MESSAGE = "unmark <task index>"; private static final String INVALID_DELETE_MESSAGE = "delete <task index>"; + /** + * Prints a horizontal line for separating sections in the user interface. + */ public static void printHorizontalLine() { System.out.println(DRAW_HORIZONTAL_LINE); } + /** + * Prints the introduction message when the program starts, including the bot's name and greeting. + */ public static void printIntroMessage() { printHorizontalLine(); System.out.println("\tHello! I'm"); @@ -29,10 +40,17 @@ public static void printIntroMessage() { printHorizontalLine(); } + /** + * Prints the goodbye message when the user exits the program. + */ public static void printByeMessage() { System.out.println("\tBye. Hope to see you again soon!"); } + /** + * Prints an error message indicating an invalid task format input from the user, + * along with the correct formats for each type of task. + */ public static void printInvalidTaskMessage() { System.out.println("\tInvalid command format:" + System.lineSeparator() + "\t\t" + INVALID_TODO_INPUT_MESSAGE + System.lineSeparator() + "\t\t" + INVALID_DEADLINE_INPUT_MESSAGE + System.lineSeparator() + "\t\t" @@ -42,41 +60,75 @@ public static void printInvalidTaskMessage() { + INVALID_DELETE_MESSAGE); } + /** + * Prints an error message when a task description is empty. + */ public static void printTaskDescriptionEmptyMessage() { System.out.println("\tError: The task description cannot be empty."); } + /** + * Prints a message confirming that a task has been added to the list. + * @param itemArrayList The current list of tasks. + * @param task The task that was added. + */ public static void printAddedMessage(ArrayList<Task> itemArrayList, Task task) { System.out.println("\tGot it. I've added this task:"); System.out.println("\t " + task); System.out.println("\tNow you have " + (itemArrayList.size()) + " tasks in the list."); } + /** + * Prints a generic error message for unknown issues. + */ public static void printUnknownErrorMessage() { System.out.println("Unknown error experienced."); } + /** + * Prints a message confirming that a task has been marked as done. + * @param itemArrayList The current list of tasks. + * @param itemNum The task index that was marked as done. + */ public static void printTaskMarkedMessage(ArrayList<Task> itemArrayList, int itemNum) { System.out.println("\tNice! I've marked this task as done:"); System.out.println("\t " + itemArrayList.get(itemNum - 1)); } + /** + * Prints a message confirming that a task has been unmarked (marked as not done). + * @param itemArrayList The current list of tasks. + * @param itemNum The task index that was unmarked. + */ public static void printTaskUnmarkedMessage(ArrayList<Task> itemArrayList, int itemNum) { System.out.println("\tOK, I've marked this task as not done yet:"); System.out.println("\t " + itemArrayList.get(itemNum - 1)); } + /** + * Prints an error message when the user provides an index that is out of range + * for marking, unmarking, or deleting tasks. + */ public static void printInputIndexOutOfRangeMessage() { System.out.println("\tInput index number out of range."); } + /** + * Prints an error message when the user provides a non-integer index for task operations. + */ public static void printInputIndexNotAnIntegerMessage() { System.out.println("\tInput index was not a integer."); } + /** + * Prints a message confirming that a task has been deleted from the list. + * @param itemArrayList The current list of tasks. + * @param task The task that was deleted. + */ public static void printTaskDeletedMessage(ArrayList<Task> itemArrayList, Task task) { System.out.println("\tNoted. I've removed this task:"); System.out.println("\t " + task); System.out.println("\tNow you have " + itemArrayList.size() + " tasks in the list."); } } + From 22c7af48b265d39df4e5aa92e34f6248a1467ae9 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Sat, 28 Sep 2024 23:51:47 +0800 Subject: [PATCH 57/76] Add JavaDoc comments to the code --- src/main/java/task/Deadline.java | 20 ++++++++++++++++++++ src/main/java/task/Event.java | 22 ++++++++++++++++++++++ src/main/java/task/Task.java | 31 +++++++++++++++++++++++++++++++ src/main/java/task/Todo.java | 21 +++++++++++++++++++++ 4 files changed, 94 insertions(+) diff --git a/src/main/java/task/Deadline.java b/src/main/java/task/Deadline.java index 2e024b3d4..230f49d09 100644 --- a/src/main/java/task/Deadline.java +++ b/src/main/java/task/Deadline.java @@ -1,19 +1,39 @@ package task; +/** + * Represents a deadline task with a description and a due date. + */ public class Deadline extends Task { protected String by; + /** + * Constructs a Deadline with the specified description and due date. + * + * @param description The description of the deadline task. + * @param by The due date of the deadline task. + */ public Deadline(String description, String by) { super(description); this.by = by; } + /** + * Returns a string representation of the deadline task, including its completion status + * and description with the due date. + * + * @return A formatted string representation of the deadline task. + */ @Override public String toString() { return ("[D][" + getDoneStatusIcon() + "] " + description + " (by: " + by + ")"); } + /** + * Returns a formatted string representation of the deadline task for storage. + * + * @return A formatted string representing the deadline task suitable for saving to a file. + */ @Override public String formattedTask() { return ("D | " + getDoneStatusIcon() + " | " + description + " | " + by); diff --git a/src/main/java/task/Event.java b/src/main/java/task/Event.java index 65eb24ae8..f0ecb7a44 100644 --- a/src/main/java/task/Event.java +++ b/src/main/java/task/Event.java @@ -1,22 +1,44 @@ package task; +/** + * Represents an event task with a description, start date, and end date. + */ public class Event extends Task { protected String startDate; protected String endDate; + /** + * Constructs an Event with the specified description, start date, and end date. + * + * @param description The description of the event. + * @param startDate The starting date/time of the event. + * @param endDate The ending date/time of the event. + */ public Event(String description, String startDate, String endDate) { super(description); this.startDate = startDate; this.endDate = endDate; } + /** + * Returns a string representation of the event task, including its completion status, + * description, start date, and end date. + * + * @return A formatted string representation of the event task. + */ @Override public String toString() { return ("[E][" + getDoneStatusIcon() + "] " + description + " (from: " + startDate + " to: " + endDate + ")"); } + /** + * Returns a formatted string representation of the event task for storage. + * + * @return A formatted string representing the event task suitable for saving to a file. + */ @Override public String formattedTask() { return ("E | " + getDoneStatusIcon() + " | " + description + " | " + startDate + " | " + endDate); } } + diff --git a/src/main/java/task/Task.java b/src/main/java/task/Task.java index d9019ea72..5039fc577 100644 --- a/src/main/java/task/Task.java +++ b/src/main/java/task/Task.java @@ -1,30 +1,61 @@ package task; +/** + * Represents a task with a description and a completion status. + */ public class Task { protected String description; protected boolean isDone; + /** + * Constructs a Task with the specified description. + * The task is initially marked as not done. + * + * @param description The description of the task. + */ public Task(String description) { this.description = description; this.isDone = false; } + /** + * Returns the description of the task. + * + * @return The description of the task. + */ public String getDescription() { return description; } + /** + * Returns a string representation of the task's completion status. + * An "X" indicates that the task is done; a space indicates it is not done. + * + * @return A string icon representing the task's done status. + */ public String getDoneStatusIcon() { return (isDone ? "X" : " "); // mark done task with X } + /** + * Marks the task as done. + */ public void markAsDone() { isDone = true; } + /** + * Marks the task as not done. + */ public void markAsUnDone() { isDone = false; } + /** + * Returns a formatted string representation of the task. + * + * @return A formatted string representing the task. By default, it returns "NULL". + */ public String formattedTask() { return "NULL"; } diff --git a/src/main/java/task/Todo.java b/src/main/java/task/Todo.java index 0b1e64c5d..574f5d61c 100644 --- a/src/main/java/task/Todo.java +++ b/src/main/java/task/Todo.java @@ -1,17 +1,38 @@ package task; +/** + * Represents a todo task with a description. + */ public class Todo extends Task { + + /** + * Constructs a Todo with the specified description. + * + * @param description The description of the todo task. + */ public Todo(String description) { super(description); } + /** + * Returns a string representation of the todo task, including its completion status + * and description. + * + * @return A formatted string representation of the todo task. + */ @Override public String toString() { return ("[T][" + getDoneStatusIcon() + "] " + description); } + /** + * Returns a formatted string representation of the todo task for storage. + * + * @return A formatted string representing the todo task suitable for saving to a file. + */ @Override public String formattedTask() { return ("T | " + getDoneStatusIcon() + " | " + description); } } + From ba46c30e5c74e3bdc9596792123ed5c2f45edeb8 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 1 Oct 2024 00:05:42 +0800 Subject: [PATCH 58/76] Update expected result of test cases --- text-ui-test/EXPECTED.TXT | 93 +++++++++++++-------------------------- 1 file changed, 31 insertions(+), 62 deletions(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index dab84dfd8..375148cc8 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -22,28 +22,24 @@ ________________________________________ ________________________________________ - Got it. I've added this task: - [D][ ] return book (by: Sunday) - Now you have 2 tasks in the list. + Invalid date format: yyyy-mm-dd HH:mm ________________________________________ ________________________________________ Here are the tasks in your list: 1.[T][ ] borrow book - 2.[D][ ] return book (by: Sunday) ________________________________________ ________________________________________ Got it. I've added this task: [E][ ] project meeting (from: Mon 2pm to: 4pm) - Now you have 3 tasks in the list. + Now you have 2 tasks in the list. ________________________________________ ________________________________________ Here are the tasks in your list: 1.[T][ ] borrow book - 2.[D][ ] return book (by: Sunday) - 3.[E][ ] project meeting (from: Mon 2pm to: 4pm) + 2.[E][ ] project meeting (from: Mon 2pm to: 4pm) ________________________________________ ________________________________________ @@ -54,8 +50,7 @@ ________________________________________ Here are the tasks in your list: 1.[T][X] borrow book - 2.[D][ ] return book (by: Sunday) - 3.[E][ ] project meeting (from: Mon 2pm to: 4pm) + 2.[E][ ] project meeting (from: Mon 2pm to: 4pm) ________________________________________ ________________________________________ @@ -66,8 +61,7 @@ ________________________________________ Here are the tasks in your list: 1.[T][ ] borrow book - 2.[D][ ] return book (by: Sunday) - 3.[E][ ] project meeting (from: Mon 2pm to: 4pm) + 2.[E][ ] project meeting (from: Mon 2pm to: 4pm) ________________________________________ ________________________________________ @@ -77,8 +71,7 @@ ________________________________________ Here are the tasks in your list: 1.[T][ ] borrow book - 2.[D][ ] return book (by: Sunday) - 3.[E][ ] project meeting (from: Mon 2pm to: 4pm) + 2.[E][ ] project meeting (from: Mon 2pm to: 4pm) ________________________________________ ________________________________________ @@ -88,8 +81,7 @@ ________________________________________ Here are the tasks in your list: 1.[T][ ] borrow book - 2.[D][ ] return book (by: Sunday) - 3.[E][ ] project meeting (from: Mon 2pm to: 4pm) + 2.[E][ ] project meeting (from: Mon 2pm to: 4pm) ________________________________________ ________________________________________ @@ -149,59 +141,51 @@ ________________________________________ Got it. I've added this task: [T][ ] todo todo - Now you have 4 tasks in the list. + Now you have 3 tasks in the list. ________________________________________ ________________________________________ - Got it. I've added this task: - [D][ ] deadline deadline (by: /by /by) - Now you have 5 tasks in the list. + Invalid date format: yyyy-mm-dd HH:mm ________________________________________ ________________________________________ Got it. I've added this task: [E][ ] event event (from: /from /from to: /to /to) - Now you have 6 tasks in the list. + Now you have 4 tasks in the list. ________________________________________ ________________________________________ Here are the tasks in your list: 1.[T][ ] borrow book - 2.[D][ ] return book (by: Sunday) - 3.[E][ ] project meeting (from: Mon 2pm to: 4pm) - 4.[T][ ] todo todo - 5.[D][ ] deadline deadline (by: /by /by) - 6.[E][ ] event event (from: /from /from to: /to /to) + 2.[E][ ] project meeting (from: Mon 2pm to: 4pm) + 3.[T][ ] todo todo + 4.[E][ ] event event (from: /from /from to: /to /to) ________________________________________ ________________________________________ Nice! I've marked this task as done: - [E][X] project meeting (from: Mon 2pm to: 4pm) + [T][X] todo todo ________________________________________ ________________________________________ Here are the tasks in your list: 1.[T][ ] borrow book - 2.[D][ ] return book (by: Sunday) - 3.[E][X] project meeting (from: Mon 2pm to: 4pm) - 4.[T][ ] todo todo - 5.[D][ ] deadline deadline (by: /by /by) - 6.[E][ ] event event (from: /from /from to: /to /to) + 2.[E][ ] project meeting (from: Mon 2pm to: 4pm) + 3.[T][X] todo todo + 4.[E][ ] event event (from: /from /from to: /to /to) ________________________________________ ________________________________________ Noted. I've removed this task: - [T][ ] todo todo - Now you have 5 tasks in the list. + [E][ ] event event (from: /from /from to: /to /to) + Now you have 3 tasks in the list. ________________________________________ ________________________________________ Here are the tasks in your list: 1.[T][ ] borrow book - 2.[D][ ] return book (by: Sunday) - 3.[E][X] project meeting (from: Mon 2pm to: 4pm) - 4.[D][ ] deadline deadline (by: /by /by) - 5.[E][ ] event event (from: /from /from to: /to /to) + 2.[E][ ] project meeting (from: Mon 2pm to: 4pm) + 3.[T][X] todo todo ________________________________________ ________________________________________ @@ -211,49 +195,41 @@ ________________________________________ Here are the tasks in your list: 1.[T][ ] borrow book - 2.[D][ ] return book (by: Sunday) - 3.[E][X] project meeting (from: Mon 2pm to: 4pm) - 4.[D][ ] deadline deadline (by: /by /by) - 5.[E][ ] event event (from: /from /from to: /to /to) + 2.[E][ ] project meeting (from: Mon 2pm to: 4pm) + 3.[T][X] todo todo ________________________________________ ________________________________________ Noted. I've removed this task: - [E][X] project meeting (from: Mon 2pm to: 4pm) - Now you have 4 tasks in the list. + [T][X] todo todo + Now you have 2 tasks in the list. ________________________________________ ________________________________________ Here are the tasks in your list: 1.[T][ ] borrow book - 2.[D][ ] return book (by: Sunday) - 3.[D][ ] deadline deadline (by: /by /by) - 4.[E][ ] event event (from: /from /from to: /to /to) + 2.[E][ ] project meeting (from: Mon 2pm to: 4pm) ________________________________________ ________________________________________ Noted. I've removed this task: - [D][ ] return book (by: Sunday) - Now you have 3 tasks in the list. + [E][ ] project meeting (from: Mon 2pm to: 4pm) + Now you have 1 tasks in the list. ________________________________________ ________________________________________ Here are the tasks in your list: 1.[T][ ] borrow book - 2.[D][ ] deadline deadline (by: /by /by) - 3.[E][ ] event event (from: /from /from to: /to /to) ________________________________________ ________________________________________ Noted. I've removed this task: [T][ ] borrow book - Now you have 2 tasks in the list. + Now you have 0 tasks in the list. ________________________________________ ________________________________________ Here are the tasks in your list: - 1.[D][ ] deadline deadline (by: /by /by) - 2.[E][ ] event event (from: /from /from to: /to /to) ________________________________________ ________________________________________ @@ -262,25 +238,18 @@ ________________________________________ Here are the tasks in your list: - 1.[D][ ] deadline deadline (by: /by /by) - 2.[E][ ] event event (from: /from /from to: /to /to) ________________________________________ ________________________________________ - Noted. I've removed this task: - [D][ ] deadline deadline (by: /by /by) - Now you have 1 tasks in the list. + Input index number out of range. ________________________________________ ________________________________________ Here are the tasks in your list: - 1.[E][ ] event event (from: /from /from to: /to /to) ________________________________________ ________________________________________ - Noted. I've removed this task: - [E][ ] event event (from: /from /from to: /to /to) - Now you have 0 tasks in the list. + Input index number out of range. ________________________________________ ________________________________________ From efcc5d87f22a463e89e891ed5052144206c8b034 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 1 Oct 2024 00:12:35 +0800 Subject: [PATCH 59/76] Modify code to use storage object instead of static --- src/main/java/Mel.java | 29 ++++++++++++++++++++++++----- src/main/java/main/Parser.java | 16 +++++++++------- src/main/java/main/Storage.java | 20 +++++++++++--------- 3 files changed, 44 insertions(+), 21 deletions(-) diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index 75256f712..177e35fa2 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -10,20 +10,39 @@ public class Mel { private static final String LIST_FILE_PATH = ".\\data\\Mel.txt"; - public static void main(String[] args) throws IOException { + private Storage storage; +// private TaskList tasks; + private Ui ui; + + public Mel(String filePath) { +// ui = new Ui(); + storage = new Storage(filePath); +// try { +// tasks = new TaskList(storage.load()); +// } catch (DukeException e) { +// ui.showLoadingError(); +// tasks = new TaskList(); +// } + } + + public void run() { Ui.printIntroMessage(); - + // Set up scanner for user input Scanner in = new Scanner(System.in); List userList = new List(); try { - Storage.writerSetUp(LIST_FILE_PATH); - Storage.loadDataFromFile(LIST_FILE_PATH, userList); // Load saved tasks + storage.writerSetUp(); + storage.loadDataFromFile(userList); // Load saved tasks } catch (IOException e) { System.out.println("An error occurred when setting up writer."); } - Parser.getUserInput(in, LIST_FILE_PATH, userList); + Parser.getUserInput(in, storage, userList); + } + + public static void main(String[] args) throws IOException { + new Mel(LIST_FILE_PATH).run(); } } diff --git a/src/main/java/main/Parser.java b/src/main/java/main/Parser.java index 65267a7a9..7f9c61c88 100644 --- a/src/main/java/main/Parser.java +++ b/src/main/java/main/Parser.java @@ -21,11 +21,13 @@ public class Parser { /** * Continuously reads user input and interprets the commands to modify the task list. - * @param in Scanner to read user input. + * * @param listFilePath Path to the file where the list is stored. - * @param userList The current task list. + * @param in Scanner to read user input. + * @param storage + * @param userList The current task list. */ - public static void getUserInput(Scanner in, String listFilePath, List userList) { + public static void getUserInput(Scanner in, Storage storage, List userList) { String line; while (true) { line = getLine(in); @@ -42,17 +44,17 @@ public static void getUserInput(Scanner in, String listFilePath, List userList) } else if (isMark(line)) { userList.markItem(line); Ui.printHorizontalLine(); - Storage.saveListToFile(listFilePath, userList); + storage.saveListToFile(userList); } else if (isUnmark(line)) { userList.unmarkItem(line); Ui.printHorizontalLine(); - Storage.saveListToFile(listFilePath, userList); + storage.saveListToFile(userList); } else if (isDelete(line)) { userList.deleteItem(line); Ui.printHorizontalLine(); - Storage.saveListToFile(listFilePath, userList); + storage.saveListToFile(userList); } else if (isFind(line)) { userList.findItem(line); @@ -60,7 +62,7 @@ public static void getUserInput(Scanner in, String listFilePath, List userList) } else { userList.addItem(line); Ui.printHorizontalLine(); - Storage.saveListToFile(listFilePath, userList); + storage.saveListToFile(userList); } } diff --git a/src/main/java/main/Storage.java b/src/main/java/main/Storage.java index ca3d6cad5..7ed9b21ba 100644 --- a/src/main/java/main/Storage.java +++ b/src/main/java/main/Storage.java @@ -17,13 +17,18 @@ */ public class Storage { + protected String filePath; + + public Storage(String filePath) { + this.filePath = filePath; + } + /** * Writes the given text to a specified file. - * @param filePath The path of the file to write to. * @param textToAdd The text to add to the file. * @throws IOException If an I/O error occurs while writing to the file. */ - private static void writeToFile(String filePath, String textToAdd) throws IOException { + public void writeToFile(String textToAdd) throws IOException { FileWriter fw = new FileWriter(filePath); fw.write(textToAdd); fw.close(); @@ -32,10 +37,9 @@ private static void writeToFile(String filePath, String textToAdd) throws IOExce /** * Sets up the file by creating a new file if it does not exist. * Also creates the parent directory if it doesn't exist. - * @param filePath The path of the file to set up. * @throws IOException If an I/O error occurs while setting up the file. */ - public static void writerSetUp(String filePath) throws IOException { + public void writerSetUp() throws IOException { File listFile = new File(filePath); if (!listFile.exists()) { File directory = listFile.getParentFile(); @@ -48,10 +52,9 @@ public static void writerSetUp(String filePath) throws IOException { /** * Loads task data from a file and adds it to the provided user list. - * @param filePath The path of the file to load data from. * @param userList The list where the tasks will be added. */ - public static void loadDataFromFile(String filePath, List userList) { + public void loadDataFromFile(List userList) { File file = new File(filePath); try { Scanner scanner = new Scanner(file); @@ -116,12 +119,11 @@ private static void parseAndAddItem(String line, List userList) { /** * Saves the current task list to the specified file. - * @param listFilePath The path of the file to save the list to. * @param userList The list containing tasks to save. */ - public static void saveListToFile(String listFilePath, List userList) { + public void saveListToFile(List userList) { try { - writeToFile(listFilePath, userList.getFormattedTasks()); // getFormattedTasks returns a formatted String + writeToFile(userList.getFormattedTasks()); // getFormattedTasks returns a formatted String } catch (IOException e) { System.out.println("\tAn error occurred while saving the list."); } From d3d44022bfd7cfdfd64da377f0749c9aeeffc758 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 1 Oct 2024 00:59:19 +0800 Subject: [PATCH 60/76] Modify code to use Ui as object instead of static --- src/main/java/Mel.java | 9 ++++---- src/main/java/main/List.java | 39 +++++++++++++++++--------------- src/main/java/main/Parser.java | 27 +++++++++++----------- src/main/java/main/TaskList.java | 31 +++++++++++++------------ src/main/java/main/Ui.java | 26 ++++++++++----------- 5 files changed, 70 insertions(+), 62 deletions(-) diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index 177e35fa2..3db3790b0 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -15,7 +15,7 @@ public class Mel { private Ui ui; public Mel(String filePath) { -// ui = new Ui(); + ui = new Ui(); storage = new Storage(filePath); // try { // tasks = new TaskList(storage.load()); @@ -26,11 +26,11 @@ public Mel(String filePath) { } public void run() { - Ui.printIntroMessage(); + ui.printIntroMessage(); // Set up scanner for user input Scanner in = new Scanner(System.in); - List userList = new List(); + List userList = new List(ui); try { storage.writerSetUp(); @@ -39,7 +39,8 @@ public void run() { System.out.println("An error occurred when setting up writer."); } - Parser.getUserInput(in, storage, userList); + Parser.getUserInput(in, storage, ui, userList); + } public static void main(String[] args) throws IOException { diff --git a/src/main/java/main/List.java b/src/main/java/main/List.java index 1d392b3b4..b06ec155b 100644 --- a/src/main/java/main/List.java +++ b/src/main/java/main/List.java @@ -13,16 +13,19 @@ public class List { private int numItems; + private Ui ui; private Task[] itemList = new Task[0]; ArrayList<Task> itemArrayList = new ArrayList<>(Arrays.asList(itemList)); /** * Constructs an empty task list with no items. */ - public List() { + public List(Ui ui) { this.numItems = 0; + this.ui = ui; } + /** * Returns the number of tasks in the list. * @@ -41,13 +44,13 @@ public int getNumItems() { */ public void addItem(String line) { if (Parser.isValidEvent(line)) { - TaskList.addEvent(itemArrayList, line); + TaskList.addEvent(itemArrayList, ui, line); } else if (Parser.isValidDeadline(line)) { - TaskList.addDeadline(itemArrayList, line); + TaskList.addDeadline(itemArrayList, ui, line); } else if (Parser.isTodo(line)) { - TaskList.addTodo(itemArrayList, line); + TaskList.addTodo(itemArrayList, ui, line); } else { - Ui.printInvalidTaskMessage(); + ui.printInvalidTaskMessage(); } } @@ -62,15 +65,15 @@ public void markItem(String line) { int itemNum = Integer.parseInt(line.substring(5)); if (itemNum > this.getNumItems() || itemNum <= 0) { - Ui.printInputIndexOutOfRangeMessage(); + ui.printInputIndexOutOfRangeMessage(); } else { TaskList.markListItemAsDone(itemArrayList, itemNum); - Ui.printTaskMarkedMessage(itemArrayList, itemNum); + ui.printTaskMarkedMessage(itemArrayList, itemNum); } } catch (NumberFormatException e) { - Ui.printInputIndexNotAnIntegerMessage(); + ui.printInputIndexNotAnIntegerMessage(); } catch (Exception e) { - Ui.printUnknownErrorMessage(); + ui.printUnknownErrorMessage(); } } @@ -85,15 +88,15 @@ public void unmarkItem(String line) { int itemNum = Integer.parseInt(line.substring(7)); if (itemNum > this.getNumItems() || itemNum <= 0) { - Ui.printInputIndexOutOfRangeMessage(); + ui.printInputIndexOutOfRangeMessage(); } else { TaskList.markListItemAsUnDone(itemArrayList, itemNum); - Ui.printTaskUnmarkedMessage(itemArrayList, itemNum); + ui.printTaskUnmarkedMessage(itemArrayList, itemNum); } } catch (NumberFormatException e) { - Ui.printInputIndexNotAnIntegerMessage(); + ui.printInputIndexNotAnIntegerMessage(); } catch (Exception e) { - Ui.printUnknownErrorMessage(); + ui.printUnknownErrorMessage(); } } @@ -108,16 +111,16 @@ public void deleteItem(String line) { int itemNum = Integer.parseInt(line.substring(7)); if (itemNum > this.getNumItems() || itemNum <= 0) { - Ui.printInputIndexOutOfRangeMessage(); + ui.printInputIndexOutOfRangeMessage(); } else { Task deletedTask = itemArrayList.get(itemNum - 1); TaskList.deleteListItem(itemArrayList, itemNum); - Ui.printTaskDeletedMessage(itemArrayList, deletedTask); + ui.printTaskDeletedMessage(itemArrayList, deletedTask); } } catch (NumberFormatException e) { - Ui.printInputIndexNotAnIntegerMessage(); + ui.printInputIndexNotAnIntegerMessage(); } catch (Exception e) { - Ui.printUnknownErrorMessage(); + ui.printUnknownErrorMessage(); } } @@ -170,7 +173,7 @@ public void findItem(String line) { j += 1; } } catch (EmptyDescriptionException e) { - Ui.printFindDescriptionEmptyMessage(); + ui.printFindDescriptionEmptyMessage(); } } } diff --git a/src/main/java/main/Parser.java b/src/main/java/main/Parser.java index 7f9c61c88..b76e087f7 100644 --- a/src/main/java/main/Parser.java +++ b/src/main/java/main/Parser.java @@ -22,46 +22,46 @@ public class Parser { /** * Continuously reads user input and interprets the commands to modify the task list. * - * @param listFilePath Path to the file where the list is stored. * @param in Scanner to read user input. * @param storage + * @param ui * @param userList The current task list. */ - public static void getUserInput(Scanner in, Storage storage, List userList) { + public static void getUserInput(Scanner in, Storage storage, Ui ui, List userList) { String line; while (true) { - line = getLine(in); + line = getLine(ui, in); if (isBye(line)) { - Ui.printByeMessage(); - Ui.printHorizontalLine(); + ui.printByeMessage(); + ui.printHorizontalLine(); break; } else if (isList(line)) { userList.printList(); - Ui.printHorizontalLine(); + ui.printHorizontalLine(); } else if (isMark(line)) { userList.markItem(line); - Ui.printHorizontalLine(); + ui.printHorizontalLine(); storage.saveListToFile(userList); } else if (isUnmark(line)) { userList.unmarkItem(line); - Ui.printHorizontalLine(); + ui.printHorizontalLine(); storage.saveListToFile(userList); } else if (isDelete(line)) { userList.deleteItem(line); - Ui.printHorizontalLine(); + ui.printHorizontalLine(); storage.saveListToFile(userList); } else if (isFind(line)) { userList.findItem(line); - Ui.printHorizontalLine(); + ui.printHorizontalLine(); } else { userList.addItem(line); - Ui.printHorizontalLine(); + ui.printHorizontalLine(); storage.saveListToFile(userList); } @@ -71,13 +71,14 @@ public static void getUserInput(Scanner in, Storage storage, List userList) { /** * Reads a line of input from the user and prints a horizontal line after the input. * @param in Scanner to read user input. + * @param ui * @return The user input line as a string. */ - private static String getLine(Scanner in) { + private static String getLine(Ui ui, Scanner in) { String line; System.out.print(System.lineSeparator()); line = in.nextLine(); - Ui.printHorizontalLine(); + ui.printHorizontalLine(); return line; } diff --git a/src/main/java/main/TaskList.java b/src/main/java/main/TaskList.java index 392d56a6e..fd849f021 100644 --- a/src/main/java/main/TaskList.java +++ b/src/main/java/main/TaskList.java @@ -24,20 +24,21 @@ public class TaskList { * The event contains a description, start date, and end date. * * @param itemArrayList The list of tasks to add the event to. - * @param line The user input containing the event description, start date, and end date. + * @param ui + * @param line The user input containing the event description, start date, and end date. * @throws EmptyDescriptionException If the event description is missing. - * @throws EmptyDateFieldException If the event start or end date is missing. + * @throws EmptyDateFieldException If the event start or end date is missing. */ - public static void addEvent(ArrayList<Task> itemArrayList, String line) { + public static void addEvent(ArrayList<Task> itemArrayList, Ui ui, String line) { try { String eventDescription = Parser.extractEventDescription(line); String eventStartDate = Parser.extractEventStartDate(line); String eventEndDate = Parser.extractEventEndDate(line); Event newEvent = new Event(eventDescription, eventStartDate, eventEndDate); itemArrayList.add(newEvent); - Ui.printAddedMessage(itemArrayList, newEvent); + ui.printAddedMessage(itemArrayList, newEvent); } catch (EmptyDescriptionException e) { - Ui.printTaskDescriptionEmptyMessage(); + ui.printTaskDescriptionEmptyMessage(); } catch (EmptyDateFieldException e) { System.out.println("\tError: Date field(s) cannot be empty"); } @@ -48,17 +49,18 @@ public static void addEvent(ArrayList<Task> itemArrayList, String line) { * The todo contains only a description. * * @param itemArrayList The list of tasks to add the todo to. - * @param line The user input containing the todo description. + * @param ui + * @param line The user input containing the todo description. * @throws EmptyDescriptionException If the todo description is missing. */ - public static void addTodo(ArrayList<Task> itemArrayList, String line) { + public static void addTodo(ArrayList<Task> itemArrayList, Ui ui, String line) { try { String todoDescription = Parser.extractTodoDescription(line); Todo newTodo = new Todo(todoDescription); itemArrayList.add(newTodo); - Ui.printAddedMessage(itemArrayList, newTodo); + ui.printAddedMessage(itemArrayList, newTodo); } catch (EmptyDescriptionException e) { - Ui.printTaskDescriptionEmptyMessage(); + ui.printTaskDescriptionEmptyMessage(); } } @@ -67,19 +69,20 @@ public static void addTodo(ArrayList<Task> itemArrayList, String line) { * The deadline contains a description and a due date. * * @param itemArrayList The list of tasks to add the deadline to. - * @param line The user input containing the deadline description and date. + * @param ui + * @param line The user input containing the deadline description and date. * @throws EmptyDescriptionException If the deadline description is missing. - * @throws EmptyDateFieldException If the deadline date is missing. + * @throws EmptyDateFieldException If the deadline date is missing. */ - public static void addDeadline(ArrayList<Task> itemArrayList, String line) { + public static void addDeadline(ArrayList<Task> itemArrayList, Ui ui, String line) { try { String deadlineDescription = Parser.extractDeadlineDescription(line); LocalDateTime deadlineDate = Parser.extractDeadlineDate(line); Deadline newDeadline = new Deadline(deadlineDescription, deadlineDate); itemArrayList.add(newDeadline); - Ui.printAddedMessage(itemArrayList, newDeadline); + ui.printAddedMessage(itemArrayList, newDeadline); } catch (EmptyDescriptionException e) { - Ui.printTaskDescriptionEmptyMessage(); + ui.printTaskDescriptionEmptyMessage(); } catch (EmptyDateFieldException e) { System.out.println("\tError: Date field(s) cannot be empty"); } catch (DateTimeException e) { diff --git a/src/main/java/main/Ui.java b/src/main/java/main/Ui.java index c6032dab5..0c7c65628 100644 --- a/src/main/java/main/Ui.java +++ b/src/main/java/main/Ui.java @@ -21,14 +21,14 @@ public class Ui { /** * Prints a horizontal line for separating sections in the user interface. */ - public static void printHorizontalLine() { + public void printHorizontalLine() { System.out.println(DRAW_HORIZONTAL_LINE); } /** * Prints the introduction message when the program starts, including the bot's name and greeting. */ - public static void printIntroMessage() { + public void printIntroMessage() { printHorizontalLine(); System.out.println("\tHello! I'm"); System.out.println("\t.___ ___. _______ __ \n" + @@ -45,7 +45,7 @@ public static void printIntroMessage() { /** * Prints the goodbye message when the user exits the program. */ - public static void printByeMessage() { + public void printByeMessage() { System.out.println("\tBye. Hope to see you again soon!"); } @@ -53,7 +53,7 @@ public static void printByeMessage() { * Prints an error message indicating an invalid task format input from the user, * along with the correct formats for each type of task. */ - public static void printInvalidTaskMessage() { + public void printInvalidTaskMessage() { System.out.println("\tInvalid command format:" + System.lineSeparator() + "\t\t" + INVALID_TODO_INPUT_MESSAGE + System.lineSeparator() + "\t\t" + INVALID_DEADLINE_INPUT_MESSAGE + System.lineSeparator() + "\t\t" + INVALID_EVENT_INPUT_MESSAGE + System.lineSeparator() + "\t\t" @@ -65,11 +65,11 @@ public static void printInvalidTaskMessage() { /** * Prints an error message when a task description is empty. */ - public static void printTaskDescriptionEmptyMessage() { + public void printTaskDescriptionEmptyMessage() { System.out.println("\tError: The task description cannot be empty."); } - public static void printFindDescriptionEmptyMessage() { + public void printFindDescriptionEmptyMessage() { System.out.println("\tError: The find description cannot be empty."); } @@ -78,7 +78,7 @@ public static void printFindDescriptionEmptyMessage() { * @param itemArrayList The current list of tasks. * @param task The task that was added. */ - public static void printAddedMessage(ArrayList<Task> itemArrayList, Task task) { + public void printAddedMessage(ArrayList<Task> itemArrayList, Task task) { System.out.println("\tGot it. I've added this task:"); System.out.println("\t " + task); System.out.println("\tNow you have " + (itemArrayList.size()) + " tasks in the list."); @@ -87,7 +87,7 @@ public static void printAddedMessage(ArrayList<Task> itemArrayList, Task task) { /** * Prints a generic error message for unknown issues. */ - public static void printUnknownErrorMessage() { + public void printUnknownErrorMessage() { System.out.println("Unknown error experienced."); } @@ -96,7 +96,7 @@ public static void printUnknownErrorMessage() { * @param itemArrayList The current list of tasks. * @param itemNum The task index that was marked as done. */ - public static void printTaskMarkedMessage(ArrayList<Task> itemArrayList, int itemNum) { + public void printTaskMarkedMessage(ArrayList<Task> itemArrayList, int itemNum) { System.out.println("\tNice! I've marked this task as done:"); System.out.println("\t " + itemArrayList.get(itemNum - 1)); } @@ -106,7 +106,7 @@ public static void printTaskMarkedMessage(ArrayList<Task> itemArrayList, int ite * @param itemArrayList The current list of tasks. * @param itemNum The task index that was unmarked. */ - public static void printTaskUnmarkedMessage(ArrayList<Task> itemArrayList, int itemNum) { + public void printTaskUnmarkedMessage(ArrayList<Task> itemArrayList, int itemNum) { System.out.println("\tOK, I've marked this task as not done yet:"); System.out.println("\t " + itemArrayList.get(itemNum - 1)); } @@ -115,14 +115,14 @@ public static void printTaskUnmarkedMessage(ArrayList<Task> itemArrayList, int i * Prints an error message when the user provides an index that is out of range * for marking, unmarking, or deleting tasks. */ - public static void printInputIndexOutOfRangeMessage() { + public void printInputIndexOutOfRangeMessage() { System.out.println("\tInput index number out of range."); } /** * Prints an error message when the user provides a non-integer index for task operations. */ - public static void printInputIndexNotAnIntegerMessage() { + public void printInputIndexNotAnIntegerMessage() { System.out.println("\tInput index was not a integer."); } @@ -131,7 +131,7 @@ public static void printInputIndexNotAnIntegerMessage() { * @param itemArrayList The current list of tasks. * @param task The task that was deleted. */ - public static void printTaskDeletedMessage(ArrayList<Task> itemArrayList, Task task) { + public void printTaskDeletedMessage(ArrayList<Task> itemArrayList, Task task) { System.out.println("\tNoted. I've removed this task:"); System.out.println("\t " + task); System.out.println("\tNow you have " + itemArrayList.size() + " tasks in the list."); From 53604638c0ccf584196969b387748fd85ebfb075 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 1 Oct 2024 01:18:51 +0800 Subject: [PATCH 61/76] Refactor code to incorporate TaskList class --- src/main/java/Mel.java | 20 +-- src/main/java/main/List.java | 221 +++++++++++++------------------ src/main/java/main/Parser.java | 4 +- src/main/java/main/Storage.java | 8 +- src/main/java/main/TaskList.java | 221 ++++++++++++++++++------------- src/main/java/task/Deadline.java | 6 +- 6 files changed, 237 insertions(+), 243 deletions(-) diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index 3db3790b0..22a54405f 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -1,4 +1,4 @@ -import main.List; +import main.TaskList; import main.Parser; import main.Storage; import main.Ui; @@ -11,27 +11,22 @@ public class Mel { private static final String LIST_FILE_PATH = ".\\data\\Mel.txt"; private Storage storage; -// private TaskList tasks; + private TaskList userList; private Ui ui; + private Scanner in; public Mel(String filePath) { ui = new Ui(); storage = new Storage(filePath); -// try { -// tasks = new TaskList(storage.load()); -// } catch (DukeException e) { -// ui.showLoadingError(); -// tasks = new TaskList(); -// } + + // Set up scanner for user input + in = new Scanner(System.in); + userList = new TaskList(ui); } public void run() { ui.printIntroMessage(); - // Set up scanner for user input - Scanner in = new Scanner(System.in); - List userList = new List(ui); - try { storage.writerSetUp(); storage.loadDataFromFile(userList); // Load saved tasks @@ -40,7 +35,6 @@ public void run() { } Parser.getUserInput(in, storage, ui, userList); - } public static void main(String[] args) throws IOException { diff --git a/src/main/java/main/List.java b/src/main/java/main/List.java index b06ec155b..2a0567db7 100644 --- a/src/main/java/main/List.java +++ b/src/main/java/main/List.java @@ -1,179 +1,140 @@ package main; +import exception.EmptyDateFieldException; import exception.EmptyDescriptionException; -import task.*; +import task.Deadline; +import task.Event; +import task.Task; +import task.Todo; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; -import java.util.Arrays; +import java.time.DateTimeException; /** - * Manages the list of tasks. Provides functionality to add, mark, unmark, delete, - * and print tasks. Also provides formatted task output. + * Manages the list of tasks. This class provides functionality to + * add tasks (events, todos, deadlines) and mark or delete tasks + * in the task list. */ public class List { - private int numItems; - private Ui ui; - private Task[] itemList = new Task[0]; - ArrayList<Task> itemArrayList = new ArrayList<>(Arrays.asList(itemList)); - - /** - * Constructs an empty task list with no items. - */ - public List(Ui ui) { - this.numItems = 0; - this.ui = ui; - } - - /** - * Returns the number of tasks in the list. + * Adds an event task to the provided task list. + * The event contains a description, start date, and end date. * - * @return The number of tasks in the list. + * @param itemArrayList The list of tasks to add the event to. + * @param ui + * @param line The user input containing the event description, start date, and end date. + * @throws EmptyDescriptionException If the event description is missing. + * @throws EmptyDateFieldException If the event start or end date is missing. */ - public int getNumItems() { - return itemArrayList.size(); - } - - /** - * Adds a new task to the list based on the user input. - * It checks whether the task is an event, deadline, or todo, - * and adds it accordingly. If the task is invalid, an error message is printed. - * - * @param line The user input containing task information. - */ - public void addItem(String line) { - if (Parser.isValidEvent(line)) { - TaskList.addEvent(itemArrayList, ui, line); - } else if (Parser.isValidDeadline(line)) { - TaskList.addDeadline(itemArrayList, ui, line); - } else if (Parser.isTodo(line)) { - TaskList.addTodo(itemArrayList, ui, line); - } else { - ui.printInvalidTaskMessage(); + public static void addEvent(ArrayList<Task> itemArrayList, Ui ui, String line) { + try { + String eventDescription = Parser.extractEventDescription(line); + String eventStartDate = Parser.extractEventStartDate(line); + String eventEndDate = Parser.extractEventEndDate(line); + Event newEvent = new Event(eventDescription, eventStartDate, eventEndDate); + itemArrayList.add(newEvent); + ui.printAddedMessage(itemArrayList, newEvent); + } catch (EmptyDescriptionException e) { + ui.printTaskDescriptionEmptyMessage(); + } catch (EmptyDateFieldException e) { + System.out.println("\tError: Date field(s) cannot be empty"); } } /** - * Marks a task in the list as done based on the user input. - * If the task number is invalid or out of range, an error message is printed. + * Adds a todo task to the provided task list. + * The todo contains only a description. * - * @param line The user input containing the task number to mark. + * @param itemArrayList The list of tasks to add the todo to. + * @param ui + * @param line The user input containing the todo description. + * @throws EmptyDescriptionException If the todo description is missing. */ - public void markItem(String line) { + public static void addTodo(ArrayList<Task> itemArrayList, Ui ui, String line) { try { - int itemNum = Integer.parseInt(line.substring(5)); - - if (itemNum > this.getNumItems() || itemNum <= 0) { - ui.printInputIndexOutOfRangeMessage(); - } else { - TaskList.markListItemAsDone(itemArrayList, itemNum); - ui.printTaskMarkedMessage(itemArrayList, itemNum); - } - } catch (NumberFormatException e) { - ui.printInputIndexNotAnIntegerMessage(); - } catch (Exception e) { - ui.printUnknownErrorMessage(); + String todoDescription = Parser.extractTodoDescription(line); + Todo newTodo = new Todo(todoDescription); + itemArrayList.add(newTodo); + ui.printAddedMessage(itemArrayList, newTodo); + } catch (EmptyDescriptionException e) { + ui.printTaskDescriptionEmptyMessage(); } } /** - * Unmarks a task in the list as not done based on the user input. - * If the task number is invalid or out of range, an error message is printed. + * Adds a deadline task to the provided task list. + * The deadline contains a description and a due date. * - * @param line The user input containing the task number to unmark. + * @param itemArrayList The list of tasks to add the deadline to. + * @param ui + * @param line The user input containing the deadline description and date. + * @throws EmptyDescriptionException If the deadline description is missing. + * @throws EmptyDateFieldException If the deadline date is missing. */ - public void unmarkItem(String line) { + public static void addDeadline(ArrayList<Task> itemArrayList, Ui ui, String line) { try { - int itemNum = Integer.parseInt(line.substring(7)); - - if (itemNum > this.getNumItems() || itemNum <= 0) { - ui.printInputIndexOutOfRangeMessage(); - } else { - TaskList.markListItemAsUnDone(itemArrayList, itemNum); - ui.printTaskUnmarkedMessage(itemArrayList, itemNum); - } - } catch (NumberFormatException e) { - ui.printInputIndexNotAnIntegerMessage(); - } catch (Exception e) { - ui.printUnknownErrorMessage(); + String deadlineDescription = Parser.extractDeadlineDescription(line); + LocalDateTime deadlineDate = Parser.extractDeadlineDate(line); + Deadline newDeadline = new Deadline(deadlineDescription, deadlineDate); + itemArrayList.add(newDeadline); + ui.printAddedMessage(itemArrayList, newDeadline); + } catch (EmptyDescriptionException e) { + ui.printTaskDescriptionEmptyMessage(); + } catch (EmptyDateFieldException e) { + System.out.println("\tError: Date field(s) cannot be empty"); + } catch (DateTimeException e) { + System.out.println("\tInvalid date format: yyyy-mm-dd HH:mm"); } } /** - * Deletes a task from the list based on the user input. - * If the task number is invalid or out of range, an error message is printed. + * Marks a task in the task list as done. * - * @param line The user input containing the task number to delete. + * @param itemArrayList The list of tasks. + * @param itemNum The task number to be marked as done. */ - public void deleteItem(String line) { - try { - int itemNum = Integer.parseInt(line.substring(7)); - - if (itemNum > this.getNumItems() || itemNum <= 0) { - ui.printInputIndexOutOfRangeMessage(); - } else { - Task deletedTask = itemArrayList.get(itemNum - 1); - TaskList.deleteListItem(itemArrayList, itemNum); - ui.printTaskDeletedMessage(itemArrayList, deletedTask); - } - } catch (NumberFormatException e) { - ui.printInputIndexNotAnIntegerMessage(); - } catch (Exception e) { - ui.printUnknownErrorMessage(); - } + public static void markListItemAsDone(ArrayList<Task> itemArrayList, int itemNum) { + itemArrayList.get(itemNum - 1).markAsDone(); } /** - * Prints the current list of tasks to the console. + * Marks a task in the task list as not done. + * + * @param itemArrayList The list of tasks. + * @param itemNum The task number to be marked as not done. */ - public void printList() { - System.out.println("\tHere are the tasks in your list:"); - int i = 0; - for (Task a: itemArrayList) { - System.out.println("\t" + (i + 1) + "." + a); - i += 1; - } + public static void markListItemAsUnDone(ArrayList<Task> itemArrayList, int itemNum) { + itemArrayList.get(itemNum - 1).markAsUnDone(); } /** - * Returns the formatted string representation of all tasks in the list. - * Each task is formatted based on its type and details. + * Deletes a task from the task list. * - * @return A string representing the formatted tasks. + * @param itemArrayList The list of tasks. + * @param itemNum The task number to be deleted. */ - public String getFormattedTasks() { - String outputString = ""; - for (Task a: itemArrayList) { - outputString += a.formattedTask() + System.lineSeparator(); - } - return outputString; + public static void deleteListItem(ArrayList<Task> itemArrayList, int itemNum) { + itemArrayList.remove(itemNum - 1); } - public void findItem(String line) { - try { - String findDescription = Parser.extractFindDescription(line); - ArrayList<Task> matchedArrayList = new ArrayList<>(itemArrayList); // Safe copy of the original list + public static LocalDateTime convertDeadlineDateAsLocalDateTime(String deadlineDate) { + DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + return LocalDateTime.parse(deadlineDate, inputFormatter); + } - int i = 0; - while (i < matchedArrayList.size()) { - Task t = matchedArrayList.get(i); + public static LocalDateTime getDeadlineDateAsLocalDateTimeFromFile(String deadlineDate) { + DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("MMM dd yyyy, h:mm a"); + return LocalDateTime.parse(deadlineDate, inputFormatter); + } - if (!t.getDescription().contains(findDescription)) { - matchedArrayList.remove(t); - } else { - i += 1; - } - } + public static String convertDeadlineDateAsString(LocalDateTime dateTime) { + DateTimeFormatter outputformatter = DateTimeFormatter.ofPattern("MMM dd yyyy, h:mm a"); + String formattedDateTime = dateTime.format(outputformatter); // "1986-04-08 12:30" - System.out.println("\tHere are the matching tasks in your list:"); - int j = 0; - for (Task a: matchedArrayList) { - System.out.println("\t" + (j + 1) + "." + a); - j += 1; - } - } catch (EmptyDescriptionException e) { - ui.printFindDescriptionEmptyMessage(); - } + return formattedDateTime; } } + diff --git a/src/main/java/main/Parser.java b/src/main/java/main/Parser.java index b76e087f7..aef869826 100644 --- a/src/main/java/main/Parser.java +++ b/src/main/java/main/Parser.java @@ -27,7 +27,7 @@ public class Parser { * @param ui * @param userList The current task list. */ - public static void getUserInput(Scanner in, Storage storage, Ui ui, List userList) { + public static void getUserInput(Scanner in, Storage storage, Ui ui, TaskList userList) { String line; while (true) { line = getLine(ui, in); @@ -223,7 +223,7 @@ public static LocalDateTime extractDeadlineDate(String line) { String deadlineDateString = line.substring(indexOfDeadlinePrefix).replaceFirst("/by", "").trim(); dateFieldNotEmpty(deadlineDateString); - deadlineDate = TaskList.convertDeadlineDateAsLocalDateTime(deadlineDateString); + deadlineDate = List.convertDeadlineDateAsLocalDateTime(deadlineDateString); return deadlineDate; } diff --git a/src/main/java/main/Storage.java b/src/main/java/main/Storage.java index 7ed9b21ba..3cb507739 100644 --- a/src/main/java/main/Storage.java +++ b/src/main/java/main/Storage.java @@ -54,7 +54,7 @@ public void writerSetUp() throws IOException { * Loads task data from a file and adds it to the provided user list. * @param userList The list where the tasks will be added. */ - public void loadDataFromFile(List userList) { + public void loadDataFromFile(TaskList userList) { File file = new File(filePath); try { Scanner scanner = new Scanner(file); @@ -73,7 +73,7 @@ public void loadDataFromFile(List userList) { * @param line The line to parse. * @param userList The list where the task will be added. */ - private static void parseAndAddItem(String line, List userList) { + private static void parseAndAddItem(String line, TaskList userList) { String[] parts = line.split(" \\| "); String taskType = parts[0]; // T, D, E boolean isDone = parts[1].equals("X"); @@ -90,7 +90,7 @@ private static void parseAndAddItem(String line, List userList) { case "D": try { - LocalDateTime deadlineDate = TaskList.getDeadlineDateAsLocalDateTimeFromFile(parts[3]); // Ignore remaining parts + LocalDateTime deadlineDate = List.getDeadlineDateAsLocalDateTimeFromFile(parts[3]); // Ignore remaining parts Deadline deadlineTask = new Deadline(taskDescription, deadlineDate); if (isDone) { deadlineTask.markAsDone(); @@ -121,7 +121,7 @@ private static void parseAndAddItem(String line, List userList) { * Saves the current task list to the specified file. * @param userList The list containing tasks to save. */ - public void saveListToFile(List userList) { + public void saveListToFile(TaskList userList) { try { writeToFile(userList.getFormattedTasks()); // getFormattedTasks returns a formatted String } catch (IOException e) { diff --git a/src/main/java/main/TaskList.java b/src/main/java/main/TaskList.java index fd849f021..adab7738d 100644 --- a/src/main/java/main/TaskList.java +++ b/src/main/java/main/TaskList.java @@ -1,140 +1,179 @@ package main; -import exception.EmptyDateFieldException; import exception.EmptyDescriptionException; -import task.Deadline; -import task.Event; -import task.Task; -import task.Todo; +import task.*; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; import java.util.ArrayList; -import java.time.DateTimeException; +import java.util.Arrays; /** - * Manages the list of tasks. This class provides functionality to - * add tasks (events, todos, deadlines) and mark or delete tasks - * in the task list. + * Manages the list of tasks. Provides functionality to add, mark, unmark, delete, + * and print tasks. Also provides formatted task output. */ public class TaskList { + private int numItems; + private Ui ui; + private Task[] itemList = new Task[0]; + ArrayList<Task> itemArrayList = new ArrayList<>(Arrays.asList(itemList)); + + /** + * Constructs an empty task list with no items. + */ + public TaskList(Ui ui) { + this.numItems = 0; + this.ui = ui; + } + + /** - * Adds an event task to the provided task list. - * The event contains a description, start date, and end date. + * Returns the number of tasks in the list. * - * @param itemArrayList The list of tasks to add the event to. - * @param ui - * @param line The user input containing the event description, start date, and end date. - * @throws EmptyDescriptionException If the event description is missing. - * @throws EmptyDateFieldException If the event start or end date is missing. + * @return The number of tasks in the list. */ - public static void addEvent(ArrayList<Task> itemArrayList, Ui ui, String line) { - try { - String eventDescription = Parser.extractEventDescription(line); - String eventStartDate = Parser.extractEventStartDate(line); - String eventEndDate = Parser.extractEventEndDate(line); - Event newEvent = new Event(eventDescription, eventStartDate, eventEndDate); - itemArrayList.add(newEvent); - ui.printAddedMessage(itemArrayList, newEvent); - } catch (EmptyDescriptionException e) { - ui.printTaskDescriptionEmptyMessage(); - } catch (EmptyDateFieldException e) { - System.out.println("\tError: Date field(s) cannot be empty"); + public int getNumItems() { + return itemArrayList.size(); + } + + /** + * Adds a new task to the list based on the user input. + * It checks whether the task is an event, deadline, or todo, + * and adds it accordingly. If the task is invalid, an error message is printed. + * + * @param line The user input containing task information. + */ + public void addItem(String line) { + if (Parser.isValidEvent(line)) { + List.addEvent(itemArrayList, ui, line); + } else if (Parser.isValidDeadline(line)) { + List.addDeadline(itemArrayList, ui, line); + } else if (Parser.isTodo(line)) { + List.addTodo(itemArrayList, ui, line); + } else { + ui.printInvalidTaskMessage(); } } /** - * Adds a todo task to the provided task list. - * The todo contains only a description. + * Marks a task in the list as done based on the user input. + * If the task number is invalid or out of range, an error message is printed. * - * @param itemArrayList The list of tasks to add the todo to. - * @param ui - * @param line The user input containing the todo description. - * @throws EmptyDescriptionException If the todo description is missing. + * @param line The user input containing the task number to mark. */ - public static void addTodo(ArrayList<Task> itemArrayList, Ui ui, String line) { + public void markItem(String line) { try { - String todoDescription = Parser.extractTodoDescription(line); - Todo newTodo = new Todo(todoDescription); - itemArrayList.add(newTodo); - ui.printAddedMessage(itemArrayList, newTodo); - } catch (EmptyDescriptionException e) { - ui.printTaskDescriptionEmptyMessage(); + int itemNum = Integer.parseInt(line.substring(5)); + + if (itemNum > this.getNumItems() || itemNum <= 0) { + ui.printInputIndexOutOfRangeMessage(); + } else { + List.markListItemAsDone(itemArrayList, itemNum); + ui.printTaskMarkedMessage(itemArrayList, itemNum); + } + } catch (NumberFormatException e) { + ui.printInputIndexNotAnIntegerMessage(); + } catch (Exception e) { + ui.printUnknownErrorMessage(); } } /** - * Adds a deadline task to the provided task list. - * The deadline contains a description and a due date. + * Unmarks a task in the list as not done based on the user input. + * If the task number is invalid or out of range, an error message is printed. * - * @param itemArrayList The list of tasks to add the deadline to. - * @param ui - * @param line The user input containing the deadline description and date. - * @throws EmptyDescriptionException If the deadline description is missing. - * @throws EmptyDateFieldException If the deadline date is missing. + * @param line The user input containing the task number to unmark. */ - public static void addDeadline(ArrayList<Task> itemArrayList, Ui ui, String line) { + public void unmarkItem(String line) { try { - String deadlineDescription = Parser.extractDeadlineDescription(line); - LocalDateTime deadlineDate = Parser.extractDeadlineDate(line); - Deadline newDeadline = new Deadline(deadlineDescription, deadlineDate); - itemArrayList.add(newDeadline); - ui.printAddedMessage(itemArrayList, newDeadline); - } catch (EmptyDescriptionException e) { - ui.printTaskDescriptionEmptyMessage(); - } catch (EmptyDateFieldException e) { - System.out.println("\tError: Date field(s) cannot be empty"); - } catch (DateTimeException e) { - System.out.println("\tInvalid date format: yyyy-mm-dd HH:mm"); + int itemNum = Integer.parseInt(line.substring(7)); + + if (itemNum > this.getNumItems() || itemNum <= 0) { + ui.printInputIndexOutOfRangeMessage(); + } else { + List.markListItemAsUnDone(itemArrayList, itemNum); + ui.printTaskUnmarkedMessage(itemArrayList, itemNum); + } + } catch (NumberFormatException e) { + ui.printInputIndexNotAnIntegerMessage(); + } catch (Exception e) { + ui.printUnknownErrorMessage(); } } /** - * Marks a task in the task list as done. + * Deletes a task from the list based on the user input. + * If the task number is invalid or out of range, an error message is printed. * - * @param itemArrayList The list of tasks. - * @param itemNum The task number to be marked as done. + * @param line The user input containing the task number to delete. */ - public static void markListItemAsDone(ArrayList<Task> itemArrayList, int itemNum) { - itemArrayList.get(itemNum - 1).markAsDone(); + public void deleteItem(String line) { + try { + int itemNum = Integer.parseInt(line.substring(7)); + + if (itemNum > this.getNumItems() || itemNum <= 0) { + ui.printInputIndexOutOfRangeMessage(); + } else { + Task deletedTask = itemArrayList.get(itemNum - 1); + List.deleteListItem(itemArrayList, itemNum); + ui.printTaskDeletedMessage(itemArrayList, deletedTask); + } + } catch (NumberFormatException e) { + ui.printInputIndexNotAnIntegerMessage(); + } catch (Exception e) { + ui.printUnknownErrorMessage(); + } } /** - * Marks a task in the task list as not done. - * - * @param itemArrayList The list of tasks. - * @param itemNum The task number to be marked as not done. + * Prints the current list of tasks to the console. */ - public static void markListItemAsUnDone(ArrayList<Task> itemArrayList, int itemNum) { - itemArrayList.get(itemNum - 1).markAsUnDone(); + public void printList() { + System.out.println("\tHere are the tasks in your list:"); + int i = 0; + for (Task a: itemArrayList) { + System.out.println("\t" + (i + 1) + "." + a); + i += 1; + } } /** - * Deletes a task from the task list. + * Returns the formatted string representation of all tasks in the list. + * Each task is formatted based on its type and details. * - * @param itemArrayList The list of tasks. - * @param itemNum The task number to be deleted. + * @return A string representing the formatted tasks. */ - public static void deleteListItem(ArrayList<Task> itemArrayList, int itemNum) { - itemArrayList.remove(itemNum - 1); + public String getFormattedTasks() { + String outputString = ""; + for (Task a: itemArrayList) { + outputString += a.formattedTask() + System.lineSeparator(); + } + return outputString; } - public static LocalDateTime convertDeadlineDateAsLocalDateTime(String deadlineDate) { - DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); - return LocalDateTime.parse(deadlineDate, inputFormatter); - } + public void findItem(String line) { + try { + String findDescription = Parser.extractFindDescription(line); + ArrayList<Task> matchedArrayList = new ArrayList<>(itemArrayList); // Safe copy of the original list - public static LocalDateTime getDeadlineDateAsLocalDateTimeFromFile(String deadlineDate) { - DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("MMM dd yyyy, h:mm a"); - return LocalDateTime.parse(deadlineDate, inputFormatter); - } + int i = 0; + while (i < matchedArrayList.size()) { + Task t = matchedArrayList.get(i); - public static String convertDeadlineDateAsString(LocalDateTime dateTime) { - DateTimeFormatter outputformatter = DateTimeFormatter.ofPattern("MMM dd yyyy, h:mm a"); - String formattedDateTime = dateTime.format(outputformatter); // "1986-04-08 12:30" + if (!t.getDescription().contains(findDescription)) { + matchedArrayList.remove(t); + } else { + i += 1; + } + } - return formattedDateTime; + System.out.println("\tHere are the matching tasks in your list:"); + int j = 0; + for (Task a: matchedArrayList) { + System.out.println("\t" + (j + 1) + "." + a); + j += 1; + } + } catch (EmptyDescriptionException e) { + ui.printFindDescriptionEmptyMessage(); + } } } - diff --git a/src/main/java/task/Deadline.java b/src/main/java/task/Deadline.java index 14d20945d..0f69fe212 100644 --- a/src/main/java/task/Deadline.java +++ b/src/main/java/task/Deadline.java @@ -2,7 +2,7 @@ import java.time.LocalDateTime; -import main.TaskList; +import main.List; /** * Represents a deadline task with a description and a due date. @@ -30,7 +30,7 @@ public Deadline(String description, LocalDateTime by) { */ @Override public String toString() { - return ("[D][" + getDoneStatusIcon() + "] " + description + " (by: " + TaskList.convertDeadlineDateAsString(by) + ")"); + return ("[D][" + getDoneStatusIcon() + "] " + description + " (by: " + List.convertDeadlineDateAsString(by) + ")"); } /** @@ -40,7 +40,7 @@ public String toString() { */ @Override public String formattedTask() { - return ("D | " + getDoneStatusIcon() + " | " + description + " | " + TaskList.convertDeadlineDateAsString(by)); + return ("D | " + getDoneStatusIcon() + " | " + description + " | " + List.convertDeadlineDateAsString(by)); } } From 48370849ece6ff3c7f331f002087163134066ce5 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 8 Oct 2024 00:31:33 +0800 Subject: [PATCH 62/76] Allow different deadline date inputs with optional time --- src/main/java/main/List.java | 40 ++++++++++++++++++++++++++++++--- src/main/java/main/Storage.java | 3 ++- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/main/java/main/List.java b/src/main/java/main/List.java index 2a0567db7..1512624f5 100644 --- a/src/main/java/main/List.java +++ b/src/main/java/main/List.java @@ -7,6 +7,7 @@ import task.Task; import task.Todo; +import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; @@ -86,7 +87,7 @@ public static void addDeadline(ArrayList<Task> itemArrayList, Ui ui, String line } catch (EmptyDateFieldException e) { System.out.println("\tError: Date field(s) cannot be empty"); } catch (DateTimeException e) { - System.out.println("\tInvalid date format: yyyy-mm-dd HH:mm"); + System.out.println("\tInvalid date format, try: \n\t yyyy-mm-dd HH:mm \n\t yyyy-MM-dd \n\t dd/MM/yyyy HH:mm \n\t dd/MM/yyyy"); } } @@ -120,11 +121,44 @@ public static void deleteListItem(ArrayList<Task> itemArrayList, int itemNum) { itemArrayList.remove(itemNum - 1); } +// public static LocalDateTime convertDeadlineDateAsLocalDateTime(String deadlineDate) { +// DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); +// return LocalDateTime.parse(deadlineDate, inputFormatter); +// } + public static LocalDateTime convertDeadlineDateAsLocalDateTime(String deadlineDate) { - DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); - return LocalDateTime.parse(deadlineDate, inputFormatter); + // Define multiple format patterns to support different date and date-time formats + DateTimeFormatter[] formatters = { + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"), // With time + DateTimeFormatter.ofPattern("yyyy-MM-dd"), // Date only + DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"), // With time, different format + DateTimeFormatter.ofPattern("dd/MM/yyyy"), // Date only, different format + }; + + // Try to parse as LocalDateTime (with time) + for (DateTimeFormatter formatter : formatters) { + try { + return LocalDateTime.parse(deadlineDate, formatter); + } catch (DateTimeException ignored) { + // Ignore and try the next formatter + } + } + + // Try to parse as LocalDate (without time) and convert to LocalDateTime + for (DateTimeFormatter formatter : formatters) { + try { + LocalDate date = LocalDate.parse(deadlineDate, formatter); + return date.atTime(23, 59, 59); // Return LocalDateTime with time set to 23:59 + } catch (DateTimeException ignored) { + // Ignore and try the next formatter + } + } + + // If parsing fails for all formats, throw an exception or handle it as needed + throw new DateTimeException("Invalid date format: " + deadlineDate); } + public static LocalDateTime getDeadlineDateAsLocalDateTimeFromFile(String deadlineDate) { DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("MMM dd yyyy, h:mm a"); return LocalDateTime.parse(deadlineDate, inputFormatter); diff --git a/src/main/java/main/Storage.java b/src/main/java/main/Storage.java index 3cb507739..0a6c6183a 100644 --- a/src/main/java/main/Storage.java +++ b/src/main/java/main/Storage.java @@ -10,6 +10,7 @@ import java.io.IOException; import java.time.DateTimeException; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.Scanner; /** @@ -97,7 +98,7 @@ private static void parseAndAddItem(String line, TaskList userList) { } userList.itemArrayList.add(deadlineTask); } catch (DateTimeException e) { - System.out.println("\tInvalid date format: yyyy-mm-dd HH:mm"); + System.out.println("\tInvalid date format, try: \n\t yyyy-mm-dd HH:mm \n\t yyyy-MM-dd \n\t dd/MM/yyyy HH:mm \n\t dd/MM/yyyy"); } break; From 8151868b22434ea3513d6e6520c058f1a99e8fe2 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 8 Oct 2024 01:36:15 +0800 Subject: [PATCH 63/76] Refactor code to coding standards --- src/main/java/main/List.java | 15 +++++---------- src/main/java/main/Parser.java | 4 ---- src/main/java/main/Storage.java | 1 - src/main/java/main/TaskList.java | 16 +++++++--------- src/main/java/main/Ui.java | 12 ++++++++++-- src/main/java/task/Deadline.java | 13 ++++++------- 6 files changed, 28 insertions(+), 33 deletions(-) diff --git a/src/main/java/main/List.java b/src/main/java/main/List.java index 1512624f5..4caeeccf5 100644 --- a/src/main/java/main/List.java +++ b/src/main/java/main/List.java @@ -41,7 +41,7 @@ public static void addEvent(ArrayList<Task> itemArrayList, Ui ui, String line) { } catch (EmptyDescriptionException e) { ui.printTaskDescriptionEmptyMessage(); } catch (EmptyDateFieldException e) { - System.out.println("\tError: Date field(s) cannot be empty"); + ui.printDateFieldEmptyMessage(); } } @@ -85,9 +85,9 @@ public static void addDeadline(ArrayList<Task> itemArrayList, Ui ui, String line } catch (EmptyDescriptionException e) { ui.printTaskDescriptionEmptyMessage(); } catch (EmptyDateFieldException e) { - System.out.println("\tError: Date field(s) cannot be empty"); + ui.printDateFieldEmptyMessage(); } catch (DateTimeException e) { - System.out.println("\tInvalid date format, try: \n\t yyyy-mm-dd HH:mm \n\t yyyy-MM-dd \n\t dd/MM/yyyy HH:mm \n\t dd/MM/yyyy"); + ui.printInvalidDateFormatMessage(); } } @@ -121,11 +121,6 @@ public static void deleteListItem(ArrayList<Task> itemArrayList, int itemNum) { itemArrayList.remove(itemNum - 1); } -// public static LocalDateTime convertDeadlineDateAsLocalDateTime(String deadlineDate) { -// DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); -// return LocalDateTime.parse(deadlineDate, inputFormatter); -// } - public static LocalDateTime convertDeadlineDateAsLocalDateTime(String deadlineDate) { // Define multiple format patterns to support different date and date-time formats DateTimeFormatter[] formatters = { @@ -154,7 +149,7 @@ public static LocalDateTime convertDeadlineDateAsLocalDateTime(String deadlineDa } } - // If parsing fails for all formats, throw an exception or handle it as needed + // If parsing fails for all formats, throw an exception throw new DateTimeException("Invalid date format: " + deadlineDate); } @@ -166,7 +161,7 @@ public static LocalDateTime getDeadlineDateAsLocalDateTimeFromFile(String deadli public static String convertDeadlineDateAsString(LocalDateTime dateTime) { DateTimeFormatter outputformatter = DateTimeFormatter.ofPattern("MMM dd yyyy, h:mm a"); - String formattedDateTime = dateTime.format(outputformatter); // "1986-04-08 12:30" + String formattedDateTime = dateTime.format(outputformatter); return formattedDateTime; } diff --git a/src/main/java/main/Parser.java b/src/main/java/main/Parser.java index aef869826..3a8dd0247 100644 --- a/src/main/java/main/Parser.java +++ b/src/main/java/main/Parser.java @@ -11,10 +11,6 @@ * to perform the appropriate actions on the task list. */ public class Parser { - private static final int MARK_WORD_LEN = 4; - private static final int UNMARK_WORD_LEN = 6; - private static final int INPUT_SPACE_BUFFER = 2; - private static final int DELETE_WORD_LEN = 6; public static final String DEADLINE_BY_KEYWORD = "/by"; public static final String EVENT_FROM_KEYWORD = "/from"; public static final String EVENT_TO_KEYWORD = "/to"; diff --git a/src/main/java/main/Storage.java b/src/main/java/main/Storage.java index 0a6c6183a..b24053876 100644 --- a/src/main/java/main/Storage.java +++ b/src/main/java/main/Storage.java @@ -10,7 +10,6 @@ import java.io.IOException; import java.time.DateTimeException; import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; import java.util.Scanner; /** diff --git a/src/main/java/main/TaskList.java b/src/main/java/main/TaskList.java index adab7738d..9d0492815 100644 --- a/src/main/java/main/TaskList.java +++ b/src/main/java/main/TaskList.java @@ -1,7 +1,7 @@ package main; import exception.EmptyDescriptionException; -import task.*; +import task.Task; import java.util.ArrayList; import java.util.Arrays; @@ -12,7 +12,6 @@ */ public class TaskList { - private int numItems; private Ui ui; private Task[] itemList = new Task[0]; ArrayList<Task> itemArrayList = new ArrayList<>(Arrays.asList(itemList)); @@ -21,7 +20,6 @@ public class TaskList { * Constructs an empty task list with no items. */ public TaskList(Ui ui) { - this.numItems = 0; this.ui = ui; } @@ -72,8 +70,8 @@ public void markItem(String line) { } } catch (NumberFormatException e) { ui.printInputIndexNotAnIntegerMessage(); - } catch (Exception e) { - ui.printUnknownErrorMessage(); + } catch (ArrayIndexOutOfBoundsException e) { + ui.printIndexOutOfBoundsMessage(); } } @@ -95,8 +93,8 @@ public void unmarkItem(String line) { } } catch (NumberFormatException e) { ui.printInputIndexNotAnIntegerMessage(); - } catch (Exception e) { - ui.printUnknownErrorMessage(); + } catch (ArrayIndexOutOfBoundsException e) { + ui.printIndexOutOfBoundsMessage(); } } @@ -119,8 +117,8 @@ public void deleteItem(String line) { } } catch (NumberFormatException e) { ui.printInputIndexNotAnIntegerMessage(); - } catch (Exception e) { - ui.printUnknownErrorMessage(); + } catch (ArrayIndexOutOfBoundsException e) { + ui.printIndexOutOfBoundsMessage(); } } diff --git a/src/main/java/main/Ui.java b/src/main/java/main/Ui.java index 0c7c65628..c8de8b871 100644 --- a/src/main/java/main/Ui.java +++ b/src/main/java/main/Ui.java @@ -87,8 +87,8 @@ public void printAddedMessage(ArrayList<Task> itemArrayList, Task task) { /** * Prints a generic error message for unknown issues. */ - public void printUnknownErrorMessage() { - System.out.println("Unknown error experienced."); + public void printIndexOutOfBoundsMessage() { + System.out.println("Index given was ouf of bounds of the list"); } /** @@ -136,5 +136,13 @@ public void printTaskDeletedMessage(ArrayList<Task> itemArrayList, Task task) { System.out.println("\t " + task); System.out.println("\tNow you have " + itemArrayList.size() + " tasks in the list."); } + + public void printInvalidDateFormatMessage() { + System.out.println("\tInvalid date format, expected: \n\t\tyyyy-mm-dd HH:mm \n\t\tyyyy-MM-dd \n\t\tdd/MM/yyyy HH:mm \n\t\tdd/MM/yyyy"); + } + + public void printDateFieldEmptyMessage() { + System.out.println("\tError: Date field(s) cannot be empty"); + } } diff --git a/src/main/java/task/Deadline.java b/src/main/java/task/Deadline.java index 0f69fe212..ebf6ba72e 100644 --- a/src/main/java/task/Deadline.java +++ b/src/main/java/task/Deadline.java @@ -1,6 +1,5 @@ package task; - import java.time.LocalDateTime; import main.List; @@ -9,17 +8,17 @@ */ public class Deadline extends Task { - protected LocalDateTime by; + protected LocalDateTime byDate; /** * Constructs a Deadline with the specified description and due date. * * @param description The description of the deadline task. - * @param by The due date of the deadline task. + * @param byDate The due date of the deadline task. */ - public Deadline(String description, LocalDateTime by) { + public Deadline(String description, LocalDateTime byDate) { super(description); - this.by = by; + this.byDate = byDate; } /** @@ -30,7 +29,7 @@ public Deadline(String description, LocalDateTime by) { */ @Override public String toString() { - return ("[D][" + getDoneStatusIcon() + "] " + description + " (by: " + List.convertDeadlineDateAsString(by) + ")"); + return ("[D][" + getDoneStatusIcon() + "] " + description + " (by: " + List.convertDeadlineDateAsString(byDate) + ")"); } /** @@ -40,7 +39,7 @@ public String toString() { */ @Override public String formattedTask() { - return ("D | " + getDoneStatusIcon() + " | " + description + " | " + List.convertDeadlineDateAsString(by)); + return ("D | " + getDoneStatusIcon() + " | " + description + " | " + List.convertDeadlineDateAsString(byDate)); } } From 2b55f75251f034d9201139c8a8f60d5ed1914ae0 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 8 Oct 2024 01:37:52 +0800 Subject: [PATCH 64/76] Handle error from list file --- src/main/java/main/Storage.java | 90 ++++++++++++++++++++------------- 1 file changed, 55 insertions(+), 35 deletions(-) diff --git a/src/main/java/main/Storage.java b/src/main/java/main/Storage.java index b24053876..f5ca1254c 100644 --- a/src/main/java/main/Storage.java +++ b/src/main/java/main/Storage.java @@ -75,48 +75,68 @@ public void loadDataFromFile(TaskList userList) { */ private static void parseAndAddItem(String line, TaskList userList) { String[] parts = line.split(" \\| "); - String taskType = parts[0]; // T, D, E - boolean isDone = parts[1].equals("X"); - String taskDescription = parts[2]; - - switch (taskType) { - case "T": - Todo todoTask = new Todo(taskDescription); - if (isDone) { - todoTask.markAsDone(); - } - userList.itemArrayList.add(todoTask); - break; - case "D": - try { - LocalDateTime deadlineDate = List.getDeadlineDateAsLocalDateTimeFromFile(parts[3]); // Ignore remaining parts - Deadline deadlineTask = new Deadline(taskDescription, deadlineDate); + try { + String taskType = parts[0]; // T, D, E + boolean isDone = parts[1].equals("X"); + String taskDescription = parts[2]; + + // Check for valid task types and number of fields + switch (taskType) { + case "T": + if (parts.length != 3) { + System.out.println("\tInvalid format for Todo task: " + line); + return; // Skip this line + } + Todo todoTask = new Todo(taskDescription); if (isDone) { - deadlineTask.markAsDone(); + todoTask.markAsDone(); } - userList.itemArrayList.add(deadlineTask); - } catch (DateTimeException e) { - System.out.println("\tInvalid date format, try: \n\t yyyy-mm-dd HH:mm \n\t yyyy-MM-dd \n\t dd/MM/yyyy HH:mm \n\t dd/MM/yyyy"); - } - break; - - case "E": - String eventStart = parts[3]; // Start date/time - String eventEnd = parts[4]; // End date/time - Event eventTask = new Event(taskDescription, eventStart, eventEnd); - if (isDone) { - eventTask.markAsDone(); - } - userList.itemArrayList.add(eventTask); - break; + userList.itemArrayList.add(todoTask); + break; - default: - System.out.println("\tInvalid task type in file: " + taskType); - break; + case "D": + if (parts.length != 4) { + System.out.println("\tSkipping line as invalid format for Deadline task: " + line); + return; // Skip this line + } + try { + LocalDateTime deadlineDate = List.getDeadlineDateAsLocalDateTimeFromFile(parts[3]); + Deadline deadlineTask = new Deadline(taskDescription, deadlineDate); + if (isDone) { + deadlineTask.markAsDone(); + } + userList.itemArrayList.add(deadlineTask); + } catch (DateTimeException e) { + System.out.println("\tSkipping line as invalid date format in Deadline task: " + parts[3]); + System.out.println("\t\tInvalid date format, expected: \n\t\t\tyyyy-mm-dd HH:mm \n\t\t\tyyyy-MM-dd \n\t\t\tdd/MM/yyyy HH:mm \n\t\t\tdd/MM/yyyy"); + } + break; + + case "E": + if (parts.length != 5) { + System.out.println("\tSkipping line as invalid format for Event task: " + line); + return; // Skip this line + } + String eventStart = parts[3]; // Start date/time + String eventEnd = parts[4]; // End date/time + Event eventTask = new Event(taskDescription, eventStart, eventEnd); + if (isDone) { + eventTask.markAsDone(); + } + userList.itemArrayList.add(eventTask); + break; + + default: + System.out.println("\tSkipping line as invalid task type in file: " + line); + break; + } + } catch (ArrayIndexOutOfBoundsException e) { + System.out.println("\tSkipping line as error detected in line: " + line); } } + /** * Saves the current task list to the specified file. * @param userList The list containing tasks to save. From 90e95e46fb94a787e78fb3a14ca8ed84dbea608c Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 8 Oct 2024 01:38:16 +0800 Subject: [PATCH 65/76] Update expected output from test --- text-ui-test/EXPECTED.TXT | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 375148cc8..9009c6ccb 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -22,7 +22,11 @@ ________________________________________ ________________________________________ - Invalid date format: yyyy-mm-dd HH:mm + Invalid date format, expected: + yyyy-mm-dd HH:mm + yyyy-MM-dd + dd/MM/yyyy HH:mm + dd/MM/yyyy ________________________________________ ________________________________________ @@ -145,7 +149,11 @@ ________________________________________ ________________________________________ - Invalid date format: yyyy-mm-dd HH:mm + Invalid date format, expected: + yyyy-mm-dd HH:mm + yyyy-MM-dd + dd/MM/yyyy HH:mm + dd/MM/yyyy ________________________________________ ________________________________________ From 680751252078d7d60281201bb997b0a04fc79634 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 8 Oct 2024 01:54:08 +0800 Subject: [PATCH 66/76] Use switch-case instead of if-else --- src/main/java/main/Parser.java | 106 +++++++++++++++---------------- src/main/java/main/Storage.java | 3 +- src/main/java/main/TaskList.java | 15 +++-- src/main/java/main/Ui.java | 2 +- 4 files changed, 64 insertions(+), 62 deletions(-) diff --git a/src/main/java/main/Parser.java b/src/main/java/main/Parser.java index 3a8dd0247..067f2fd81 100644 --- a/src/main/java/main/Parser.java +++ b/src/main/java/main/Parser.java @@ -15,55 +15,56 @@ public class Parser { public static final String EVENT_FROM_KEYWORD = "/from"; public static final String EVENT_TO_KEYWORD = "/to"; - /** - * Continuously reads user input and interprets the commands to modify the task list. - * - * @param in Scanner to read user input. - * @param storage - * @param ui - * @param userList The current task list. - */ public static void getUserInput(Scanner in, Storage storage, Ui ui, TaskList userList) { String line; while (true) { line = getLine(ui, in); + String commandType = getCommandType(line); // Get command type using the new method - if (isBye(line)) { + switch (commandType) { + case "bye": ui.printByeMessage(); ui.printHorizontalLine(); - break; + return; - } else if (isList(line)) { + case "list": userList.printList(); ui.printHorizontalLine(); + break; - } else if (isMark(line)) { + case "mark": userList.markItem(line); ui.printHorizontalLine(); storage.saveListToFile(userList); + break; - } else if (isUnmark(line)) { + case "unmark": userList.unmarkItem(line); ui.printHorizontalLine(); storage.saveListToFile(userList); + break; - } else if (isDelete(line)) { + case "delete": userList.deleteItem(line); ui.printHorizontalLine(); storage.saveListToFile(userList); + break; - } else if (isFind(line)) { + case "find": userList.findItem(line); ui.printHorizontalLine(); - } else { + break; + + default: userList.addItem(line); ui.printHorizontalLine(); storage.saveListToFile(userList); - + break; } } } + /** * Reads a line of input from the user and prints a horizontal line after the input. * @param in Scanner to read user input. @@ -79,53 +80,46 @@ private static String getLine(Ui ui, Scanner in) { } /** - * Checks if the input command is to list all tasks. - * @param line The input string. - * @return True if the command is "list", false otherwise. - */ - private static boolean isList(String line) { - return line.equals("list"); - } - - /** - * Checks if the input command is to exit the program. - * @param line The input string. - * @return True if the command is "bye", false otherwise. - */ - private static boolean isBye(String line) { - return line.equals("bye"); - } - - /** - * Checks if the input command is to mark a task as done. - * @param line The input string. - * @return True if the command starts with "mark", false otherwise. - */ - public static boolean isMark(String line) { - return line.startsWith("mark "); - } - - /** - * Checks if the input command is to unmark a task (mark it as not done). + * Checks if the input command matches any of the predefined commands. * @param line The input string. - * @return True if the command starts with "unmark", false otherwise. + * @return The command type if it matches, or "unknown" if not recognized. */ - public static boolean isUnmark(String line) { - return line.startsWith("unmark "); + private static String getCommandType(String line) { + if (line.equals("list")) { + return "list"; + } else if (line.equals("bye")) { + return "bye"; + } else if (line.startsWith("mark ")) { + return "mark"; + } else if (line.startsWith("unmark ")) { + return "unmark"; + } else if (line.startsWith("delete ")) { + return "delete"; + } else if (line.startsWith("find ")) { + return "find"; + } else { + return "unknown"; // Return "unknown" for commands that do not match + } } /** - * Checks if the input command is to delete a task. - * @param line The input string. - * @return True if the command starts with "delete", false otherwise. + * Determines the type of task based on the input line. + * + * @param line The user input containing task information. + * @return The task type as a string ("event", "deadline", "todo", or "unknown"). */ - public static boolean isDelete(String line) { - return line.startsWith("delete "); + public static String getTaskType(String line) { + if (isValidEvent(line)) { + return "event"; + } else if (isValidDeadline(line)) { + return "deadline"; + } else if (isTodo(line)) { + return "todo"; + } else { + return "unknown"; // Return "unknown" for unrecognized task types + } } - public static boolean isFind(String line) { - return line.startsWith("find "); - } /** * Checks if the input string is a valid event format. diff --git a/src/main/java/main/Storage.java b/src/main/java/main/Storage.java index f5ca1254c..71ca52880 100644 --- a/src/main/java/main/Storage.java +++ b/src/main/java/main/Storage.java @@ -64,8 +64,9 @@ public void loadDataFromFile(TaskList userList) { } scanner.close(); } catch (FileNotFoundException e) { - System.out.println("File not found: " + filePath); + System.out.println("\tFile not found: " + filePath); } + Ui.printHorizontalLine(); } /** diff --git a/src/main/java/main/TaskList.java b/src/main/java/main/TaskList.java index 9d0492815..849c3ff4f 100644 --- a/src/main/java/main/TaskList.java +++ b/src/main/java/main/TaskList.java @@ -41,14 +41,21 @@ public int getNumItems() { * @param line The user input containing task information. */ public void addItem(String line) { - if (Parser.isValidEvent(line)) { + String commandType = Parser.getTaskType(line); // Assuming a method to determine task type + + switch (commandType) { + case "event": List.addEvent(itemArrayList, ui, line); - } else if (Parser.isValidDeadline(line)) { + break; + case "deadline": List.addDeadline(itemArrayList, ui, line); - } else if (Parser.isTodo(line)) { + break; + case "todo": List.addTodo(itemArrayList, ui, line); - } else { + break; + default: ui.printInvalidTaskMessage(); + break; } } diff --git a/src/main/java/main/Ui.java b/src/main/java/main/Ui.java index c8de8b871..127497707 100644 --- a/src/main/java/main/Ui.java +++ b/src/main/java/main/Ui.java @@ -21,7 +21,7 @@ public class Ui { /** * Prints a horizontal line for separating sections in the user interface. */ - public void printHorizontalLine() { + public static void printHorizontalLine() { System.out.println(DRAW_HORIZONTAL_LINE); } From 43a012a46c9f72c216edaaebef1b59c1d24646c0 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 8 Oct 2024 18:32:38 +0800 Subject: [PATCH 67/76] Update expected output for test cases --- text-ui-test/EXPECTED.TXT | 1 + 1 file changed, 1 insertion(+) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 9009c6ccb..24ef3e221 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -9,6 +9,7 @@ What can I do for you? ________________________________________ + ________________________________________ ________________________________________ Got it. I've added this task: From 3ff8f25a754134a2f2761a08be15cedf8de21117 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 8 Oct 2024 20:48:41 +0800 Subject: [PATCH 68/76] Add user guide --- docs/README.md | 119 +++++++++++++++++++++++++++++++++++++++++++------ docs/img.png | Bin 0 -> 11661 bytes 2 files changed, 105 insertions(+), 14 deletions(-) create mode 100644 docs/img.png diff --git a/docs/README.md b/docs/README.md index d35be9c22..d4e92e251 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,30 +1,121 @@ # Mel User Guide -// Update the title above to match the actual product name // Product screenshot goes here + -// Product intro goes here +Mel is a console-based chatbot designed to help you manage tasks efficiently, including todos, deadlines, and events. The chatbot understands a variety of commands to add, remove, and track your tasks, as well as search and manage them interactively. With Mel, you can keep track of your schedule, deadlines, and daily tasks seamlessly. -## Adding deadlines +## Key Features: -// Describe the action and its outcome. +- Supports **todo** tasks for general items. +- Adds **deadline** tasks with a specified date and optional time. +- Manages **event** tasks with both start and end dates/times. +- Allows marking/unmarking of task completion, and finding tasks by description. +- Keeps a running list of your tasks and saves them automatically. -// Give examples of usage +## List tasks: list -Example: `keyword (optional arguments)` +Displays the current list of tasks, showing their index, type, description, and whether they are completed or not. -// A description of the expected outcome goes here +Format: list -``` -expected output -``` +## Adding a todo task: todo -## Feature ABC +Adds tasks without any date/time attached to it e.g., explore the new garden -// Feature details +Format: todo DESCRIPTION +- Adds the todo task with the specified DESCRIPTION. The DESCRIPTION refers to the name of the task that will be shown in the task list. +- The DESCRIPTION is a string and must not be empty. +Examples: -## Feature XYZ + todo read book -// Feature details \ No newline at end of file + +## Adding a deadline task: deadline + +Adds tasks that need to be done before a specific date/time e.g., return book by 04/11/2024 8pm + +Format: deadline DESCRIPTION /by DATE +- Adds the deadline task with the specified DESCRIPTION. The DESCRIPTION refers to the name of the task that will be shown in the task list. +- The DESCRIPTION is a string and must not be empty. +- Adds deadline date and/or time to the task with the specified DATE. The DATE is input as a string and must not be empty. +- The DATE has to be specified in one of the following formats: + - yyyy-MM-dd HH:mm + - yyyy-MM-dd + - dd/MM/yyyy HH:mm + - dd/MM/yyyy +- Adding deadline time to DATE is optional, if not given, it will be automatically filled with 23:59 + + +Examples: + + deadline return book /by 2024-11-04 20:00 Adds a deadline task with a description and deadline of return book and Nov 04 2024, 08:00 pm, respectively. + deadline submit quiz /by 2024-11-05 Adds a deadline task with a description and deadline of submit quiz and Nov 05 2024, 11:59 pm, respectively. + deadline order cake /by 07/11/2024 21:00 Adds a deadline task with a description and deadline of return book and Nov 07 2024, 09:00 pm, respectively. + deadline submit form /by 09/11/2024 Adds a deadline task with a description and deadline of submit form and Nov 09 2024, 11:59 pm, respectively. + +## Adding a event task: event + +Adds tasks that start at a specific date/time and ends at a specific date/time e.g., (a) team project meeting 2/10/2019 2-4pm (b) orientation week 4/10/2019 to 11/10/2019 + +Format: event DESCRIPTION /from START_TIME /to END_TIME +- Adds the event task with the specified DESCRIPTION. The DESCRIPTION refers to the name of the task that will be shown in the task list. +- The DESCRIPTION is a string and must not be empty. +- Adds event start and end date/time to the task with the specified START_TIME and END_TIME, respectively. The START_TIME and END_TIME are input as strings and must not be empty. +- The START_TIME and END_TIME can be specified in any string format. + + +Examples: + + event dinner with friends /from 5pm /to 6pm Adds an event task with a description, start time and end time of dinner with friends, 5pm and 6pm, respectively. + +## Deleting a task: delete + +Deletes the specified task from the task list. + +Format: delete INDEX +- Deletes the task at the specified INDEX. +- The index refers to the index number shown in the displayed task list. +- The index **must be a positive integer** 1, 2, 3, ... + +Examples: + + delete 2 deletes the 2nd task in the task list. + +## Mark/Unmark Task Completion: mark/ unmark + +Marks/unmarks the specified task from the task list. + +Format: mark/unmark INDEX +- Marks/unmarks the task at the specified INDEX to completed/uncompleted. +- The index refers to the index number shown in the displayed task list. +- The index **must be a positive integer** 1, 2, 3, ... + +Examples: + + mark 2 marks the 2nd task in the task list as completed. + unmark 2 unmarks the 2nd task in the task list so that is becomes uncompleted. + +## Finding tasks by description keywords: find + +Finds persons whose names contain any of the given keywords. + +Format: find KEYWORD [MORE_KEYWORDS] +- The search is case-insensitive. e.g book will match Book +- The order of the keywords matter. e.g. Pencil Case will not match Case Pencil +- Only the task description is searched. +- Parts of words will be matched e.g. Pen will match Pencil +- Tasks matching at least one keyword will be returned (i.e. OR search). e.g. Pencil Case will return Pencil Box, Pencil Case + +Examples: + + find submit returns submit quiz and submit form + find read book returns read magazine, book reservation + +## End Chatbot: bye + +Exits the program. + +Format: bye \ No newline at end of file diff --git a/docs/img.png b/docs/img.png new file mode 100644 index 0000000000000000000000000000000000000000..b1fe8dcc9542f4951dd5fa0ef0d4ec2d496af565 GIT binary patch literal 11661 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 DgV^7V literal 0 HcmV?d00001 From 0d6e9fcc6aa66d19dc05f1b271b471aa1704a5c6 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 8 Oct 2024 21:40:34 +0800 Subject: [PATCH 69/76] Allow find to be case-insensitive --- src/main/java/main/Parser.java | 23 ++++++++++++++--------- src/main/java/main/TaskList.java | 2 +- src/main/java/main/Ui.java | 11 +++++++++-- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/main/java/main/Parser.java b/src/main/java/main/Parser.java index 067f2fd81..33477e1b8 100644 --- a/src/main/java/main/Parser.java +++ b/src/main/java/main/Parser.java @@ -80,25 +80,30 @@ private static String getLine(Ui ui, Scanner in) { } /** - * Checks if the input command matches any of the predefined commands. + * Checks if the input command matches any of the predefined commands, ignoring extraneous parameters + * for commands that do not take parameters (e.g., list, bye, help). + * * @param line The input string. * @return The command type if it matches, or "unknown" if not recognized. */ private static String getCommandType(String line) { - if (line.equals("list")) { + String trimmedLine = line.split(" ")[0]; // Extract the first word (command) only + + switch (trimmedLine) { + case "list": return "list"; - } else if (line.equals("bye")) { + case "bye": return "bye"; - } else if (line.startsWith("mark ")) { + case "mark": return "mark"; - } else if (line.startsWith("unmark ")) { + case "unmark": return "unmark"; - } else if (line.startsWith("delete ")) { + case "delete": return "delete"; - } else if (line.startsWith("find ")) { + case "find": return "find"; - } else { - return "unknown"; // Return "unknown" for commands that do not match + default: + return "unknown"; // Return "unknown" for unrecognized commands } } diff --git a/src/main/java/main/TaskList.java b/src/main/java/main/TaskList.java index 849c3ff4f..fc9e6da6a 100644 --- a/src/main/java/main/TaskList.java +++ b/src/main/java/main/TaskList.java @@ -164,7 +164,7 @@ public void findItem(String line) { while (i < matchedArrayList.size()) { Task t = matchedArrayList.get(i); - if (!t.getDescription().contains(findDescription)) { + if (!t.getDescription().toLowerCase().contains(findDescription.toLowerCase())) { matchedArrayList.remove(t); } else { i += 1; diff --git a/src/main/java/main/Ui.java b/src/main/java/main/Ui.java index 127497707..773de0113 100644 --- a/src/main/java/main/Ui.java +++ b/src/main/java/main/Ui.java @@ -12,11 +12,15 @@ public class Ui { public static final String DRAW_HORIZONTAL_LINE = "\t________________________________________"; public static final String INVALID_EVENT_INPUT_MESSAGE = "event <event name> /from <start date/time> /end <end date/time>"; - public static final String INVALID_DEADLINE_INPUT_MESSAGE = "deadline <deadline name> /by <deadline>"; + public static final String INVALID_DEADLINE_INPUT_MESSAGE = "deadline <deadline name> /by <yyyy-MM-dd HH:mm>"; public static final String INVALID_TODO_INPUT_MESSAGE = "todo <task name>"; private static final String INVALID_MARK_MESSAGE = "mark <task index>"; private static final String INVALID_UNMARK_MESSAGE = "unmark <task index>"; private static final String INVALID_DELETE_MESSAGE = "delete <task index>"; + private static final String INVALID_FIND_MESSAGE = "find <task keyword string>"; + private static final String INVALID_LIST_MESSAGE = "list"; + private static final String INVALID_BYE_MESSAGE = "bye"; + /** * Prints a horizontal line for separating sections in the user interface. @@ -59,7 +63,10 @@ public void printInvalidTaskMessage() { + INVALID_EVENT_INPUT_MESSAGE + System.lineSeparator() + "\t\t" + INVALID_MARK_MESSAGE + System.lineSeparator() + "\t\t" + INVALID_UNMARK_MESSAGE + System.lineSeparator() + "\t\t" - + INVALID_DELETE_MESSAGE); + + INVALID_DELETE_MESSAGE + System.lineSeparator() + "\t\t" + + INVALID_FIND_MESSAGE + System.lineSeparator() + "\t\t" + + INVALID_LIST_MESSAGE + System.lineSeparator() + "\t\t" + + INVALID_BYE_MESSAGE); } /** From 1090e23ae7997572216489a48e1f47b6a64bfd54 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 8 Oct 2024 21:41:14 +0800 Subject: [PATCH 70/76] Update README --- docs/README.md | 46 ++++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/docs/README.md b/docs/README.md index d4e92e251..2991c5b6c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,7 +1,6 @@ # Mel User Guide -// Product screenshot goes here  Mel is a console-based chatbot designed to help you manage tasks efficiently, including todos, deadlines, and events. The chatbot understands a variety of commands to add, remove, and track your tasks, as well as search and manage them interactively. With Mel, you can keep track of your schedule, deadlines, and daily tasks seamlessly. @@ -51,10 +50,17 @@ Format: deadline DESCRIPTION /by DATE Examples: - deadline return book /by 2024-11-04 20:00 Adds a deadline task with a description and deadline of return book and Nov 04 2024, 08:00 pm, respectively. - deadline submit quiz /by 2024-11-05 Adds a deadline task with a description and deadline of submit quiz and Nov 05 2024, 11:59 pm, respectively. - deadline order cake /by 07/11/2024 21:00 Adds a deadline task with a description and deadline of return book and Nov 07 2024, 09:00 pm, respectively. - deadline submit form /by 09/11/2024 Adds a deadline task with a description and deadline of submit form and Nov 09 2024, 11:59 pm, respectively. + //Add a deadline task with a description and deadline of return book and Nov 04 2024, 08:00 pm, respectively + deadline return book /by 2024-11-04 20:00 + + //Add a deadline task with a description and deadline of submit quiz and Nov 05 2024, 11:59 pm, respectively + deadline submit quiz /by 2024-11-05 + + //Add a deadline task with a description and deadline of return book and Nov 07 2024, 09:00 pm, respectively + deadline order cake /by 07/11/2024 21:00 + + //Add a deadline task with a description and deadline of submit form and Nov 09 2024, 11:59 pm, respectively + deadline submit form /by 09/11/2024 ## Adding a event task: event @@ -68,8 +74,9 @@ Format: event DESCRIPTION /from START_TIME /to END_TIME Examples: - - event dinner with friends /from 5pm /to 6pm Adds an event task with a description, start time and end time of dinner with friends, 5pm and 6pm, respectively. + + //Add an event task with a description, start time and end time of dinner with friends, 5pm and 6pm, respectively + event dinner with friends /from 5pm /to 6pm ## Deleting a task: delete @@ -82,7 +89,8 @@ Format: delete INDEX Examples: - delete 2 deletes the 2nd task in the task list. + //Delete the 2nd task in the task list + delete 2 ## Mark/Unmark Task Completion: mark/ unmark @@ -95,24 +103,30 @@ Format: mark/unmark INDEX Examples: - mark 2 marks the 2nd task in the task list as completed. - unmark 2 unmarks the 2nd task in the task list so that is becomes uncompleted. + //Mark the 2nd task in the task list as completed + mark 2 + + //Unmark the 2nd task in the task list so that is becomes uncompleted + unmark 2 ## Finding tasks by description keywords: find Finds persons whose names contain any of the given keywords. -Format: find KEYWORD [MORE_KEYWORDS] -- The search is case-insensitive. e.g book will match Book -- The order of the keywords matter. e.g. Pencil Case will not match Case Pencil +Format: find KEYWORD_STRING +- The search is case-insensitive. e.g. book will match Book +- The entire keyword string has to fully match at least part of the task description. e.g. read a large book will not match with read a small book +- The KEYWORD_STRING order matters. e.g. Pencil Case will not match Case Pencil - Only the task description is searched. - Parts of words will be matched e.g. Pen will match Pencil -- Tasks matching at least one keyword will be returned (i.e. OR search). e.g. Pencil Case will return Pencil Box, Pencil Case Examples: - find submit returns submit quiz and submit form - find read book returns read magazine, book reservation + //Return submit quiz and submit form + find submit + + //Return read magazine, book reservation + find read book ## End Chatbot: bye From 66e0871bd0630481584bf2e463a3033cc16c6b16 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 8 Oct 2024 21:41:32 +0800 Subject: [PATCH 71/76] Update expected test case output --- text-ui-test/EXPECTED.TXT | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 24ef3e221..7c828317e 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -92,21 +92,27 @@ ________________________________________ Invalid command format: todo <task name> - deadline <deadline name> /by <deadline> + deadline <deadline name> /by <yyyy-MM-dd HH:mm> event <event name> /from <start date/time> /end <end date/time> mark <task index> unmark <task index> delete <task index> + find <task keyword string> + list + bye ________________________________________ ________________________________________ Invalid command format: todo <task name> - deadline <deadline name> /by <deadline> + deadline <deadline name> /by <yyyy-MM-dd HH:mm> event <event name> /from <start date/time> /end <end date/time> mark <task index> unmark <task index> delete <task index> + find <task keyword string> + list + bye ________________________________________ ________________________________________ @@ -120,11 +126,14 @@ ________________________________________ Invalid command format: todo <task name> - deadline <deadline name> /by <deadline> + deadline <deadline name> /by <yyyy-MM-dd HH:mm> event <event name> /from <start date/time> /end <end date/time> mark <task index> unmark <task index> delete <task index> + find <task keyword string> + list + bye ________________________________________ ________________________________________ From cc6885ad16be4845646befdd5c814ef389cba061 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 8 Oct 2024 21:59:01 +0800 Subject: [PATCH 72/76] Add command summary in README --- docs/README.md | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/docs/README.md b/docs/README.md index 2991c5b6c..27a51db29 100644 --- a/docs/README.md +++ b/docs/README.md @@ -64,13 +64,13 @@ Examples: ## Adding a event task: event -Adds tasks that start at a specific date/time and ends at a specific date/time e.g., (a) team project meeting 2/10/2019 2-4pm (b) orientation week 4/10/2019 to 11/10/2019 +Adds tasks that start at a specific date/time and ends at a specific date/time e.g., team project meeting on 2/10/2019 from 2pm to 4pm Format: event DESCRIPTION /from START_TIME /to END_TIME - Adds the event task with the specified DESCRIPTION. The DESCRIPTION refers to the name of the task that will be shown in the task list. - The DESCRIPTION is a string and must not be empty. - Adds event start and end date/time to the task with the specified START_TIME and END_TIME, respectively. The START_TIME and END_TIME are input as strings and must not be empty. -- The START_TIME and END_TIME can be specified in any string format. +- The START_TIME and END_TIME can be specified as a string in any format. Examples: @@ -115,10 +115,9 @@ Finds persons whose names contain any of the given keywords. Format: find KEYWORD_STRING - The search is case-insensitive. e.g. book will match Book -- The entire keyword string has to fully match at least part of the task description. e.g. read a large book will not match with read a small book -- The KEYWORD_STRING order matters. e.g. Pencil Case will not match Case Pencil -- Only the task description is searched. +- The entire keyword string must be found within the task description. e.g. read a large book will not match with read a small book - Parts of words will be matched e.g. Pen will match Pencil +- Only the task description is searched. Examples: @@ -132,4 +131,32 @@ Examples: Exits the program. -Format: bye \ No newline at end of file +Format: bye + +## Saving the data + +The task list data are saved in the hard disk automatically after any command that changes the data. There is no need to save manually. + +## Command Summary + +| Action | Format, Examples | +|--------------------------------|-----------------------------------------------------| +| **Add a todo task** | `todo DESCRIPTION` | +| | e.g., `todo read book` | +| **Add a deadline task** | `deadline DESCRIPTION /by DATE` | +| | e.g., `deadline return book /by 2024-11-04 20:00` | +| | e.g., `deadline submit form /by 2024-11-05` | +| **Add an event task** | `event DESCRIPTION /from START_TIME /to END_TIME` | +| | e.g., `event dinner with friends /from 5pm /to 6pm` | +| **Delete a task** | `delete INDEX` | +| | e.g., `delete 2` | +| **Mark task as completed** | `mark INDEX` | +| | e.g., `mark 2` | +| **Unmark task as uncompleted** | `unmark INDEX` | +| | e.g., `unmark 2` | +| **Find tasks** | `find KEYWORD_STRING` | +| | e.g., `find read book` | +| **List tasks** | `list` | +| | e.g., `list` | +| **End the chatbot** | `bye` | +| | e.g., `bye` | From 13b4d16196978d63d2ead1ba420c3ac560719868 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 8 Oct 2024 22:06:14 +0800 Subject: [PATCH 73/76] Update README --- docs/README.md | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/docs/README.md b/docs/README.md index 27a51db29..417d6040f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -139,24 +139,18 @@ The task list data are saved in the hard disk automatically after any command th ## Command Summary -| Action | Format, Examples | -|--------------------------------|-----------------------------------------------------| -| **Add a todo task** | `todo DESCRIPTION` | -| | e.g., `todo read book` | -| **Add a deadline task** | `deadline DESCRIPTION /by DATE` | -| | e.g., `deadline return book /by 2024-11-04 20:00` | -| | e.g., `deadline submit form /by 2024-11-05` | -| **Add an event task** | `event DESCRIPTION /from START_TIME /to END_TIME` | -| | e.g., `event dinner with friends /from 5pm /to 6pm` | -| **Delete a task** | `delete INDEX` | -| | e.g., `delete 2` | -| **Mark task as completed** | `mark INDEX` | -| | e.g., `mark 2` | -| **Unmark task as uncompleted** | `unmark INDEX` | -| | e.g., `unmark 2` | -| **Find tasks** | `find KEYWORD_STRING` | -| | e.g., `find read book` | -| **List tasks** | `list` | -| | e.g., `list` | -| **End the chatbot** | `bye` | -| | e.g., `bye` | +| Action | Format, Examples | +|--------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------| +| **List tasks** | `list` | +| **Add a todo task** | `todo DESCRIPTION` <br/>e.g., `todo read book` | +| **Add a deadline task** | `deadline DESCRIPTION /by DATE` <br/>e.g., `deadline return book /by 2024-11-04 20:00` <br/>e.g., `deadline submit form /by 2024-11-05` | +| **Add an event task** | `event DESCRIPTION /from START_TIME /to END_TIME` <br/>e.g., `event dinner with friends /from 5pm /to 6pm` | +| | | +| **Delete a task** | `delete INDEX` <br/>e.g., `delete 2` | +| | | +| **Mark task as completed** | `mark INDEX` <br/>e.g., `mark 2` | +| | | +| **Unmark task as uncompleted** | `unmark INDEX` <br/>e.g., `unmark 2` | +| | | +| **Find tasks** | `find KEYWORD_STRING` <br/>e.g., `find read book` | +| **End the chatbot** | `bye` | From 2e6938da197d8ffb26ccc6ba208d0473a0353457 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 8 Oct 2024 22:23:00 +0800 Subject: [PATCH 74/76] Add quick start guide to UserGuide --- docs/README.md | 64 ++++++++++++++++++++++++++++--------------------- docs/img_1.png | Bin 0 -> 4873 bytes 2 files changed, 37 insertions(+), 27 deletions(-) create mode 100644 docs/img_1.png diff --git a/docs/README.md b/docs/README.md index 417d6040f..bd50fb6b0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -13,17 +13,27 @@ Mel is a console-based chatbot designed to help you manage tasks efficiently, in - Allows marking/unmarking of task completion, and finding tasks by description. - Keeps a running list of your tasks and saves them automatically. -## List tasks: list +## Quick Start: + +1. Ensure you have Java `17` or above installed in your Computer. +2. Download the latest `.jar` file from [here](https://github.com/yeekian/ip/releases/tag/A-Release). +3. Copy the file to the folder you want to use as the home folder for your Task Tracker. +4. Open a command terminal, `cd` into the folder you put the jar file in, and use the `java -jar Mel.jar` command to run the application. + +Your command terminal similar to below should appear in a few seconds. +<br> + +## List tasks: `list` Displays the current list of tasks, showing their index, type, description, and whether they are completed or not. -Format: list +Format: `list` -## Adding a todo task: todo +## Adding a todo task: `todo` Adds tasks without any date/time attached to it e.g., explore the new garden -Format: todo DESCRIPTION +Format: `todo DESCRIPTION` - Adds the todo task with the specified DESCRIPTION. The DESCRIPTION refers to the name of the task that will be shown in the task list. - The DESCRIPTION is a string and must not be empty. @@ -32,20 +42,20 @@ Examples: todo read book -## Adding a deadline task: deadline +## Adding a deadline task: `deadline` Adds tasks that need to be done before a specific date/time e.g., return book by 04/11/2024 8pm -Format: deadline DESCRIPTION /by DATE -- Adds the deadline task with the specified DESCRIPTION. The DESCRIPTION refers to the name of the task that will be shown in the task list. -- The DESCRIPTION is a string and must not be empty. -- Adds deadline date and/or time to the task with the specified DATE. The DATE is input as a string and must not be empty. -- The DATE has to be specified in one of the following formats: +Format: `deadline DESCRIPTION /by DATE` +- Adds the deadline task with the specified `DESCRIPTION`. The `DESCRIPTION` refers to the name of the task that will be shown in the task list. +- The `DESCRIPTION` is a string and must not be empty. +- Adds deadline date and/or time to the task with the specified `DATE`. The `DATE` is input as a string and must not be empty. +- The `DATE` has to be specified in one of the following formats: - yyyy-MM-dd HH:mm - yyyy-MM-dd - dd/MM/yyyy HH:mm - dd/MM/yyyy -- Adding deadline time to DATE is optional, if not given, it will be automatically filled with 23:59 +- Adding deadline time to `DATE` is optional, if not given, it will be automatically filled with 23:59 Examples: @@ -62,15 +72,15 @@ Examples: //Add a deadline task with a description and deadline of submit form and Nov 09 2024, 11:59 pm, respectively deadline submit form /by 09/11/2024 -## Adding a event task: event +## Adding a event task: `event` Adds tasks that start at a specific date/time and ends at a specific date/time e.g., team project meeting on 2/10/2019 from 2pm to 4pm -Format: event DESCRIPTION /from START_TIME /to END_TIME -- Adds the event task with the specified DESCRIPTION. The DESCRIPTION refers to the name of the task that will be shown in the task list. -- The DESCRIPTION is a string and must not be empty. -- Adds event start and end date/time to the task with the specified START_TIME and END_TIME, respectively. The START_TIME and END_TIME are input as strings and must not be empty. -- The START_TIME and END_TIME can be specified as a string in any format. +Format: `event DESCRIPTION /from START_TIME /to END_TIME` +- Adds the event task with the specified `DESCRIPTION`. The `DESCRIPTION` refers to the name of the task that will be shown in the task list. +- The `DESCRIPTION` is a string and must not be empty. +- Adds event start and end date/time to the task with the specified `START_TIME` and `END_TIME`, respectively. The `START_TIME` and `END_TIME` are input as strings and must not be empty. +- The `START_TIME` and `END_TIME` can be specified as a string in any format. Examples: @@ -78,12 +88,12 @@ Examples: //Add an event task with a description, start time and end time of dinner with friends, 5pm and 6pm, respectively event dinner with friends /from 5pm /to 6pm -## Deleting a task: delete +## Deleting a task: `delete` Deletes the specified task from the task list. -Format: delete INDEX -- Deletes the task at the specified INDEX. +Format: `delete INDEX` +- Deletes the task at the specified `INDEX`. - The index refers to the index number shown in the displayed task list. - The index **must be a positive integer** 1, 2, 3, ... @@ -92,12 +102,12 @@ Examples: //Delete the 2nd task in the task list delete 2 -## Mark/Unmark Task Completion: mark/ unmark +## Mark/Unmark Task Completion: `mark`/ `unmark` Marks/unmarks the specified task from the task list. -Format: mark/unmark INDEX -- Marks/unmarks the task at the specified INDEX to completed/uncompleted. +Format: `mark INDEX`/ `unmark INDEX` +- Marks/unmarks the task at the specified `INDEX` to completed/uncompleted. - The index refers to the index number shown in the displayed task list. - The index **must be a positive integer** 1, 2, 3, ... @@ -109,11 +119,11 @@ Examples: //Unmark the 2nd task in the task list so that is becomes uncompleted unmark 2 -## Finding tasks by description keywords: find +## Finding tasks by description keywords: `find` Finds persons whose names contain any of the given keywords. -Format: find KEYWORD_STRING +Format: `find KEYWORD_STRING` - The search is case-insensitive. e.g. book will match Book - The entire keyword string must be found within the task description. e.g. read a large book will not match with read a small book - Parts of words will be matched e.g. Pen will match Pencil @@ -127,11 +137,11 @@ Examples: //Return read magazine, book reservation find read book -## End Chatbot: bye +## End Chatbot: `bye` Exits the program. -Format: bye +Format: `bye` ## Saving the data diff --git a/docs/img_1.png b/docs/img_1.png new file mode 100644 index 0000000000000000000000000000000000000000..c034ff0613648cd19978002690e32697b84ea08c GIT binary patch literal 4873 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 literal 0 HcmV?d00001 From fac5ac256c325aa226851e85d056ec63f908d815 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Tue, 8 Oct 2024 22:28:39 +0800 Subject: [PATCH 75/76] Refactor UserGuide --- docs/README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/README.md b/docs/README.md index bd50fb6b0..975474d52 100644 --- a/docs/README.md +++ b/docs/README.md @@ -155,12 +155,8 @@ The task list data are saved in the hard disk automatically after any command th | **Add a todo task** | `todo DESCRIPTION` <br/>e.g., `todo read book` | | **Add a deadline task** | `deadline DESCRIPTION /by DATE` <br/>e.g., `deadline return book /by 2024-11-04 20:00` <br/>e.g., `deadline submit form /by 2024-11-05` | | **Add an event task** | `event DESCRIPTION /from START_TIME /to END_TIME` <br/>e.g., `event dinner with friends /from 5pm /to 6pm` | -| | | | **Delete a task** | `delete INDEX` <br/>e.g., `delete 2` | -| | | | **Mark task as completed** | `mark INDEX` <br/>e.g., `mark 2` | -| | | | **Unmark task as uncompleted** | `unmark INDEX` <br/>e.g., `unmark 2` | -| | | | **Find tasks** | `find KEYWORD_STRING` <br/>e.g., `find read book` | | **End the chatbot** | `bye` | From b8ecc8c4500b7d319b428d9be30dd3946719c060 Mon Sep 17 00:00:00 2001 From: yeekian <53704991+yeekian@users.noreply.github.com> Date: Sun, 13 Oct 2024 11:34:59 +0800 Subject: [PATCH 76/76] Modify Storage class to pass smoke test --- src/main/java/Mel.java | 3 ++- src/main/java/main/Storage.java | 2 +- src/main/java/main/TaskList.java | 6 ++++++ src/main/java/main/Ui.java | 2 +- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/java/Mel.java b/src/main/java/Mel.java index 22a54405f..e718d8220 100644 --- a/src/main/java/Mel.java +++ b/src/main/java/Mel.java @@ -5,10 +5,11 @@ import java.util.Scanner; import java.io.IOException; +import java.io.File; public class Mel { - private static final String LIST_FILE_PATH = ".\\data\\Mel.txt"; + private static final String LIST_FILE_PATH = "data" + File.separator + "Mel.txt"; // Use File.separator for cross-platform compatibility private Storage storage; private TaskList userList; diff --git a/src/main/java/main/Storage.java b/src/main/java/main/Storage.java index 71ca52880..d9b20097c 100644 --- a/src/main/java/main/Storage.java +++ b/src/main/java/main/Storage.java @@ -43,7 +43,7 @@ public void writerSetUp() throws IOException { File listFile = new File(filePath); if (!listFile.exists()) { File directory = listFile.getParentFile(); - if (!directory.exists()) { + if (directory != null && !directory.exists()) { // Null check for directory directory.mkdirs(); // Create directory if it doesn't exist } listFile.createNewFile(); // Create file if it doesn't exist diff --git a/src/main/java/main/TaskList.java b/src/main/java/main/TaskList.java index fc9e6da6a..8b1b46332 100644 --- a/src/main/java/main/TaskList.java +++ b/src/main/java/main/TaskList.java @@ -79,6 +79,8 @@ public void markItem(String line) { ui.printInputIndexNotAnIntegerMessage(); } catch (ArrayIndexOutOfBoundsException e) { ui.printIndexOutOfBoundsMessage(); + } catch (Exception e) { + ui.printInvalidTaskMessage(); } } @@ -102,6 +104,8 @@ public void unmarkItem(String line) { ui.printInputIndexNotAnIntegerMessage(); } catch (ArrayIndexOutOfBoundsException e) { ui.printIndexOutOfBoundsMessage(); + } catch (Exception e) { + ui.printInvalidTaskMessage(); } } @@ -126,6 +130,8 @@ public void deleteItem(String line) { ui.printInputIndexNotAnIntegerMessage(); } catch (ArrayIndexOutOfBoundsException e) { ui.printIndexOutOfBoundsMessage(); + } catch (Exception e) { + ui.printInvalidTaskMessage(); } } diff --git a/src/main/java/main/Ui.java b/src/main/java/main/Ui.java index 773de0113..9949956c7 100644 --- a/src/main/java/main/Ui.java +++ b/src/main/java/main/Ui.java @@ -95,7 +95,7 @@ public void printAddedMessage(ArrayList<Task> itemArrayList, Task task) { * Prints a generic error message for unknown issues. */ public void printIndexOutOfBoundsMessage() { - System.out.println("Index given was ouf of bounds of the list"); + System.out.println("Index given was out of bounds of the list"); } /**