Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: nus-cs2103-AY2324S1/ip
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: master
Choose a base ref
...
head repository: ChangruHenryQian/ip
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
Able to merge. These branches can be automatically merged.

Commits on Aug 8, 2023

  1. Add Gradle support

    damithc authored and damithc committed Aug 8, 2023
    Copy the full SHA
    28ad2b8 View commit details
  2. Bump gradle and lib version

    Eclipse-Dominator authored and damithc committed Aug 8, 2023
    Copy the full SHA
    ed6d4d2 View commit details

Commits on Aug 24, 2023

  1. Finish Level 0. Rename, Greet, Exit.

    QianChangru committed Aug 24, 2023
    Copy the full SHA
    5080e17 View commit details
  2. Finish Level-1: Echo

    QianChangru committed Aug 24, 2023
    Copy the full SHA
    3d4a50f View commit details

Commits on Aug 26, 2023

  1. Finish Level 2. Add, List

    QianChangru committed Aug 26, 2023
    Copy the full SHA
    fe29b0f View commit details

Commits on Aug 27, 2023

  1. Finish Level 3. Mark as Done

    QianChangru committed Aug 27, 2023
    Copy the full SHA
    02481a9 View commit details
  2. Finish Level 4. ToDos, Events, Deadlines

    QianChangru committed Aug 27, 2023
    Copy the full SHA
    91639a8 View commit details
  3. Finish A-TextUiTesting

    QianChangru committed Aug 27, 2023
    Copy the full SHA
    cab0141 View commit details
  4. Finish Level 5. Handle Errors

    QianChangru committed Aug 27, 2023
    Copy the full SHA
    28266b3 View commit details
  5. Finish Level 6. Delete

    QianChangru committed Aug 27, 2023
    Copy the full SHA
    611f1ef View commit details

Commits on Sep 5, 2023

  1. Finish Level 7. Save

    QianChangru committed Sep 5, 2023
    Copy the full SHA
    4197612 View commit details
  2. Update data/duke.txt

    QianChangru committed Sep 5, 2023
    Copy the full SHA
    c0ea8a2 View commit details
  3. Merge branch 'branch-Level-7'

    QianChangru committed Sep 5, 2023
    Copy the full SHA
    bf86dc1 View commit details

Commits on Sep 9, 2023

  1. Finish Level 8. Dates and Times

    QianChangru committed Sep 9, 2023
    Copy the full SHA
    992ec01 View commit details
  2. Merge branch 'branch-Level-8'

    QianChangru committed Sep 9, 2023
    Copy the full SHA
    113e1d3 View commit details
  3. Finish A-MoreOOP: Use More OOP

    QianChangru committed Sep 9, 2023
    Copy the full SHA
    1f284c9 View commit details
  4. Fix bug on delete command

    QianChangru committed Sep 9, 2023
    Copy the full SHA
    92e988c View commit details
  5. Finish A-Packages: Organize into Packages

    QianChangru committed Sep 9, 2023
    Copy the full SHA
    5c4a3ba View commit details
  6. Merge branch 'add-gradle-support'

    QianChangru committed Sep 9, 2023
    Copy the full SHA
    d197fc2 View commit details
  7. Finish A-Gradle: Use Gradle

    QianChangru committed Sep 9, 2023
    Copy the full SHA
    e450bed View commit details
  8. Finish A-JUnit: Add JUnit Tests

    QianChangru committed Sep 9, 2023
    Copy the full SHA
    2a0dedd View commit details
  9. Finish A-Jar: Create a JAR File

    QianChangru committed Sep 9, 2023
    Copy the full SHA
    8ac5391 View commit details

Commits on Sep 10, 2023

  1. Add part of Java Doc.

    QianChangru committed Sep 10, 2023
    Copy the full SHA
    dcc4829 View commit details
  2. Merge branch 'branch-A-JavaDoc'

    QianChangru committed Sep 10, 2023
    Copy the full SHA
    98baa49 View commit details
  3. Merge branch 'master' into branch-A-CodingStandard

    QianChangru committed Sep 10, 2023
    Copy the full SHA
    cb8b5d6 View commit details
  4. Implement coding standard.

    QianChangru committed Sep 10, 2023
    Copy the full SHA
    a011a9e View commit details
  5. Merge branch 'branch-A-CodingStandard'

    QianChangru committed Sep 10, 2023
    Copy the full SHA
    af45b36 View commit details
  6. Update JavaDoc

    QianChangru committed Sep 10, 2023
    Copy the full SHA
    b0af1ec View commit details
  7. Merge branch 'branch-A-JavaDoc'

    QianChangru committed Sep 10, 2023
    Copy the full SHA
    1d67ccf View commit details
  8. Update JavaDoc

    QianChangru committed Sep 10, 2023
    Copy the full SHA
    b47f650 View commit details
  9. Merge branch 'branch-A-JavaDoc'

    QianChangru committed Sep 10, 2023
    Copy the full SHA
    8e4c58e View commit details
  10. Start Level 9. Find

    QianChangru committed Sep 10, 2023
    Copy the full SHA
    c529dc9 View commit details
  11. Merge branch 'master' into branch-Level-9

    QianChangru committed Sep 10, 2023
    Copy the full SHA
    b88d605 View commit details
  12. Implement Level 9. Find

    QianChangru committed Sep 10, 2023
    Copy the full SHA
    cfc25a9 View commit details
  13. Merge branch 'branch-Level-9'

    QianChangru committed Sep 10, 2023
    Copy the full SHA
    2a192a3 View commit details
  14. Start Level 10. GUI

    QianChangru committed Sep 10, 2023
    Copy the full SHA
    9ff4bbc View commit details
  15. Implement Level 10. GUI

    QianChangru committed Sep 10, 2023
    Copy the full SHA
    76ab079 View commit details
  16. Merge branch 'branch-Level-10'

    QianChangru committed Sep 10, 2023
    Copy the full SHA
    d1c94f8 View commit details

Commits on Sep 15, 2023

  1. Update build.gradle

    After implementing GUI, the entry point was changed.
    
    Let's change mainClass into duke.Launcher.
    QianChangru committed Sep 15, 2023
    Copy the full SHA
    3b3712a View commit details
  2. Implement A-Assertions

    The functional code is not capable of checking assumptions.
    
    Assumptions may not be true in some cases and checking is required.
    
    Let's add assert feature to document important assumptions.
    QianChangru committed Sep 15, 2023
    Copy the full SHA
    b76decc View commit details
  3. Improve code quality

    Some parts of the code have bad code quality.
    
    Improvements on code quality increase readability.
    
    Let's improve code quality through methods such as refactoring.
    QianChangru committed Sep 15, 2023
    Copy the full SHA
    59658eb View commit details
  4. Copy the full SHA
    e20422e View commit details
  5. Merge branch 'master' into branch-A-Assertions

    # Conflicts:
    #	src/main/java/duke/Storage.java
    QianChangru committed Sep 15, 2023
    Copy the full SHA
    f1c1337 View commit details
  6. Copy the full SHA
    ed26f34 View commit details

Commits on Sep 16, 2023

  1. Implement B-FixedDurationTasks

    QianChangru committed Sep 16, 2023
    Copy the full SHA
    a146f5a View commit details

Commits on Sep 18, 2023

  1. Add welcome message into GUI

    QianChangru committed Sep 18, 2023
    Copy the full SHA
    fe210a3 View commit details
  2. Add a representative screenshot

    QianChangru committed Sep 18, 2023
    Copy the full SHA
    b761c70 View commit details
  3. Implement A-UserGuide: User Guide

    QianChangru committed Sep 18, 2023
    Copy the full SHA
    3f8b8db View commit details

Commits on Sep 19, 2023

  1. Update user guide

    QianChangru committed Sep 19, 2023
    Copy the full SHA
    9e2ec38 View commit details

Commits on Sep 21, 2023

  1. Implement CheckStyle

    QianChangru committed Sep 21, 2023
    Copy the full SHA
    925e859 View commit details
64 changes: 64 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
plugins {
id 'java'
id 'application'
id 'com.github.johnrengelman.shadow' version '7.1.2'
id 'checkstyle'
}

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'

String javaFxVersion = '17.0.7'

implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'win'
implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'mac'
implementation group: 'org.openjfx', name: 'javafx-base', version: javaFxVersion, classifier: 'linux'
implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'win'
implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'mac'
implementation group: 'org.openjfx', name: 'javafx-controls', version: javaFxVersion, classifier: 'linux'
implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'win'
implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'mac'
implementation group: 'org.openjfx', name: 'javafx-fxml', version: javaFxVersion, classifier: 'linux'
implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'win'
implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'mac'
implementation group: 'org.openjfx', name: 'javafx-graphics', version: javaFxVersion, classifier: 'linux'
}

test {
useJUnitPlatform()

testLogging {
events "passed", "skipped", "failed"

showExceptions true
exceptionFormat "full"
showCauses true
showStackTraces true
showStandardStreams = false
}
}

application {
mainClass.set("duke.Launcher")
}

shadowJar {
archiveFileName = 'duke.jar'
}

run{
standardInput = System.in

enableAssertions = true
}

mainClassName = "duke.Launcher"

checkstyle {
toolVersion = '10.2'
}
434 changes: 434 additions & 0 deletions config/checkstyle/checkstyle.xml

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions config/checkstyle/suppressions.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0"?>

<!DOCTYPE suppressions PUBLIC
"-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN"
"https://checkstyle.org/dtds/suppressions_1_2.dtd">

<suppressions>
<suppress checks="JavadocType" files=".*Test\.java"/>
<suppress checks="MissingJavadocMethodCheck" files=".*Test\.java"/>
</suppressions>
Empty file added data/tasks.txt
Empty file.
83 changes: 68 additions & 15 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,82 @@
# User Guide
Jarvis is a chat bot for maintaining tasks.

## Features
## Features

### Feature-ABC
### `list` - Listing all tasks

Description of the feature.
Shows a list of all tasks.

### Feature-XYZ
### `todo` - Adding a to-do task

Description of the feature.
Adds a to-do task.

## Usage
`todo DESCRIPTION`

Example of usage:

`todo homework` Adds homework as a to-do task.

### `deadline` - Adding a task with a deadline

Adds a task with a deadline.

`deadline DESCRIPTION /by DATE`

+ Date is in the format of yyyy-mm-dd.

Example of usage:

`deadline homework /by 2023-10-01`

### `event` - Adding an event with a start and an end

Adds an event with a start and an end.

`event DESCRIPTION /from DATE /to DATE`

### `fixedduration` - Adding a task with a fixed duration

Adds a task with a fixed duration.

`fixedduration DESCRIPTION /for TIME`

### `Keyword` - Describe action
### `mark` - Marking a task

Describe the action and its outcome.
Marks a task in the list.

Example of usage:
`mark INDEX`

`keyword (optional arguments)`
+ The index starts with 1.

Expected outcome:
Example of usage:

`mark 2` Marks the second task in the list.


### `delete` - Deleting a task

Deletes a task in the list.

`delete INDEX`

Example of usage:

`delete 3` Deletes the third task in the list.


### `find` - Searching for tasks

Finds the tasks in the list with a specific keyword.

`find KEYWORD`

### `bye` - Exiting

Exits the chat bot.

## Usage

Description of the outcome.
### Auto saving and loading

```
expected output
```
Automatically saves your tasks and loads them next time.
Binary file added docs/Ui.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
7 changes: 7 additions & 0 deletions gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
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
248 changes: 248 additions & 0 deletions gradlew
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
#!/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" "$@"
92 changes: 92 additions & 0 deletions gradlew.bat
Original file line number Diff line number Diff line change
@@ -0,0 +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=.
@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
10 changes: 0 additions & 10 deletions src/main/java/Duke.java

This file was deleted.

50 changes: 50 additions & 0 deletions src/main/java/duke/Deadline.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package duke;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;


/**
* Encapsulates deadline which are Tasks with start and end.
*/
public class Deadline extends Task {
private LocalDate by;

/**
* Constructs a Deadline with specified description and deadline.
*/
public Deadline(String description, LocalDate by) {
super(description);
this.by = by;
}

/**
* Constructs a Deadline with specified description, deadline, and
* whether it is done.
*/
public Deadline(String description, boolean isDone, LocalDate by) {
super(description, isDone);
this.by = by;
}

/**
* Returns a String representation for the task for output.
*/
@Override
public String toString() {
return "[D]" + super.toString() + " (by: "
+ this.by.format(DateTimeFormatter.ofPattern("MMM dd yyyy", Locale.ENGLISH))
+ ")";
}

/**
* Returns a String representation of the task for storage.
*/
@Override
public String toTxt() {
return "D | " + super.toTxt()
+ " | "
+ this.by.format(DateTimeFormatter.ofPattern("MMM dd yyyy", Locale.ENGLISH));
}
}
72 changes: 72 additions & 0 deletions src/main/java/duke/DialogBox.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package duke;

import java.io.IOException;
import java.util.Collections;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;

/**
* This control represents a dialog box consisting of an ImageView to represent the speaker's face and a label
* containing text from the speaker.
*/
public class DialogBox extends HBox {
@FXML
private Label dialog;
@FXML
private ImageView displayPicture;

private DialogBox(String text, Image img) {
try {
FXMLLoader fxmlLoader = new FXMLLoader(MainWindow.class.getResource("/view/DialogBox.fxml"));
fxmlLoader.setController(this);
fxmlLoader.setRoot(this);
fxmlLoader.load();
} catch (IOException e) {
e.printStackTrace();
}

dialog.setText(text);
displayPicture.setImage(img);
}

/**
* Flips the dialog box such that the ImageView is on the left and text on the right.
*/
private void flip() {
ObservableList<Node> tmp = FXCollections.observableArrayList(this.getChildren());
Collections.reverse(tmp);
getChildren().setAll(tmp);
setAlignment(Pos.TOP_LEFT);
}

/**
* Returns user dialog.
*
* @param text The text of the user.
* @param img The image of the user.
*/
public static DialogBox getUserDialog(String text, Image img) {
return new DialogBox(text, img);
}
/**
* Returns chat bot dialog.
*
* @param text The text of the chat bot.
* @param img The image of the chat bot.
*/
public static DialogBox getDukeDialog(String text, Image img) {
var db = new DialogBox(text, img);
db.flip();
return db;
}
}

68 changes: 68 additions & 0 deletions src/main/java/duke/Duke.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package duke;

import java.io.IOException;
import java.util.Scanner;

/**
* Encapsulates the chat bot.
*/
public class Duke {

private Storage storage;
private TaskList tasks;
private Ui ui;

public Duke() {
this("data/tasks.txt");
}

/**
* Constructs the chat bot with storage using the file path.
*
* @param filePath The path for the storage file.
*/
public Duke(String filePath) {
ui = new Ui();
storage = new Storage(filePath);
try {
tasks = new TaskList(storage.load(), storage);
} catch (DukeException e) {
ui.printException(e);
tasks = new TaskList(storage);
} catch (IOException e) {
ui.printException(new DukeException("Unable to find storage file."));
tasks = new TaskList(storage);
}
}

/**
* Runs the program.
*/
public void run() {
Ui.welcomeMessage();
Scanner userInput = new Scanner(System.in);
while (true) {
String command = userInput.nextLine();
Parser p = new Parser(command, this.tasks);
p.parse();
if (p.isEnd()) {
break;
}
}
}

public static void main(String[] args) {
new Duke("data/tasks.txt").run();
}


/**
* Returns the response String given the input.
*/
protected String getResponse(String input) {
Parser parser = new Parser(input, this.tasks);
String response = parser.parse();
return response;
}

}
10 changes: 10 additions & 0 deletions src/main/java/duke/DukeException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package duke;

/**
* Encapsulates exception for the chat bot.
*/
public class DukeException extends RuntimeException {
public DukeException(String message) {
super(message);
}
}
53 changes: 53 additions & 0 deletions src/main/java/duke/Event.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package duke;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

/**
* Encapsulates events which are Tasks with start and end.
*/
public class Event extends Task {
private LocalDate startTime;
private LocalDate endTime;

/**
* Constructs an Event with specified description, start time, end time,
* and whether it is done.
*/
public Event(String description, LocalDate startTime, LocalDate endTime) {
super(description);
this.startTime = startTime;
this.endTime = endTime;
}

/**
* Constructs an Event with specified description, start time and end time.
*/
public Event(String description, boolean isDone, LocalDate startTime, LocalDate endTime) {
super(description, isDone);
this.startTime = startTime;
this.endTime = endTime;
}

/**
* Returns a String representation for the task for output.
*/
@Override
public String toString() {
return "[E]" + super.toString() + " (from: "
+ startTime.format(DateTimeFormatter.ofPattern("MMM dd yyyy", Locale.ENGLISH))
+ " to: "
+ endTime.format(DateTimeFormatter.ofPattern("MMM dd yyyy", Locale.ENGLISH)) + ")";
}

/**
* Returns a String representation of the task for storage.
*/
@Override
public String toTxt() {
return "E | " + super.toTxt() + " | "
+ this.startTime.format(DateTimeFormatter.ofPattern("MMM dd yyyy", Locale.ENGLISH))
+ " | " + this.endTime.format(DateTimeFormatter.ofPattern("MMM dd yyyy", Locale.ENGLISH));
}
}
44 changes: 44 additions & 0 deletions src/main/java/duke/FixedDurationTask.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package duke;

/**
* Encapsulates FixedDurationTask which are Tasks with a fixed duration.
*/
public class FixedDurationTask extends Task {
private String duration;

/**
* Constructs a FixedDurationTask with specified description and duration.
*/
public FixedDurationTask(String description, String duration) {
super(description);
this.duration = duration;
}

/**
* Constructs a FixedDurationTask with specified description, duration, and
* whether it is done.
*/
public FixedDurationTask(String description, boolean isDone, String duration) {
super(description, isDone);
this.duration = duration;
}

/**
* Returns a String representation for FixedDurationTask for output.
*/
@Override
public String toString() {
return "[F]" + super.toString() + " (for: "
+ this.duration + ")";
}

/**
* Returns a String representation of FixedDurationTask for storage.
*/
@Override
public String toTxt() {
return "F | " + super.toTxt()
+ " | " + this.duration;
}

}
12 changes: 12 additions & 0 deletions src/main/java/duke/Launcher.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package duke;

import javafx.application.Application;

/**
* A launcher class to workaround classpath issues.
*/
public class Launcher {
public static void main(String[] args) {
Application.launch(Main.class, args);
}
}
34 changes: 34 additions & 0 deletions src/main/java/duke/Main.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package duke;

import java.io.IOException;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;


/**
* A GUI for Duke using FXML.
*/
public class Main extends Application {

private Duke duke = new Duke();

@Override
public void start(Stage stage) {
try {
FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("/view/MainWindow.fxml"));
AnchorPane ap = fxmlLoader.load();
Scene scene = new Scene(ap);
stage.setScene(scene);
MainWindow mw = fxmlLoader.<MainWindow>getController();
mw.setDuke(duke);
mw.start();
stage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
}
63 changes: 63 additions & 0 deletions src/main/java/duke/MainWindow.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package duke;

import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.image.Image;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.VBox;

/**
* Controller for MainWindow. Provides the layout for the other controls.
*/
public class MainWindow extends AnchorPane {
@FXML
private ScrollPane scrollPane;
@FXML
private VBox dialogContainer;
@FXML
private TextField userInput;
@FXML
private Button sendButton;

private Duke duke;

private Image userImage = new Image(this.getClass().getResourceAsStream("/images/DaUser.png"));
private Image dukeImage = new Image(this.getClass().getResourceAsStream("/images/DaDuke.png"));

@FXML
public void initialize() {
scrollPane.vvalueProperty().bind(dialogContainer.heightProperty());
}

public void setDuke(Duke d) {
duke = d;
}

/**
* Creates two dialog boxes, one echoing user input and the other
* containing Duke's reply and then appends them to
* the dialog container. Clears the user input after processing.
*/
@FXML
private void handleUserInput() {
String input = userInput.getText();
String response = duke.getResponse(input);

dialogContainer.getChildren().addAll(
DialogBox.getUserDialog(input, userImage),
DialogBox.getDukeDialog(response, dukeImage)
);
userInput.clear();
}

/**
* Starts the Ui interface with the welcome message.
*/
public void start() {
dialogContainer.getChildren().add(
DialogBox.getDukeDialog(Ui.welcomeMessage(), dukeImage)
);
}
}
130 changes: 130 additions & 0 deletions src/main/java/duke/Parser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package duke;

import java.time.LocalDate;

/**
* Parses the user input.
*/
public class Parser {
private String command;
private TaskList taskList;
private boolean isEnd = false;

protected Parser(String command) {
this.command = command;
}

/**
* Constructs a parser with specified Command and TaskList.
*/
public Parser(String command, TaskList taskList) {
this.command = command;
this.taskList = taskList;
}

/**
* Parses the user input and initiate following operations.
*
* @return The resulting message.
*/
public String parse() {
try {
if (command.startsWith("list")) {
return this.taskList.listTasks();
} else if (command.startsWith("mark")) {
return this.taskList.markTask(Integer.valueOf(command.split(" ")[1]) - 1);
} else if (command.startsWith("todo")) {
ToDo newToDo = this.createToDoFromCommand();
return this.taskList.addTask(newToDo);
} else if (command.startsWith("deadline")) {
Deadline newDeadline = this.createDeadlineFromCommand();
return this.taskList.addTask(newDeadline);
} else if (command.startsWith("event")) {
Event newEvent = this.createEventFromCommand();
return this.taskList.addTask(newEvent);
} else if (command.startsWith("fixedduration")) {
FixedDurationTask newFixedDurationTask = this.createFixedDurationTaskFromCommand();
return this.taskList.addTask(newFixedDurationTask);
} else if (command.startsWith("delete")) {
return this.taskList.deleteTask(Integer.valueOf(command.split(" ")[1]) - 1);
} else if (command.startsWith("find")) {
String keyword = command.split(" ", 2)[1];
return this.taskList.findTask(keyword);
} else if (command.startsWith("bye")) {
this.isEnd = true;
return Ui.farewellMessage();
} else {
throw new DukeException("OOPS!!! I'm sorry, but I don't know what that means :-(");
}
} catch (DukeException e) {
return Ui.printException(e);
}
}

/**
* Creates the new FixedDurationTask from the command.
*
* @return The new FixedDurationTask.
*/
protected FixedDurationTask createFixedDurationTaskFromCommand() {
String name = command.split(" /for ", 2)[0].split(" ", 2)[1];
String duration = command.split(" /for ", 2)[1];
FixedDurationTask newFixedDurationTask = new FixedDurationTask(name, duration);
return newFixedDurationTask;
}

/**
* Creates the new Event from the command.
*
* @return The new Event.
*/
protected Event createEventFromCommand() {
LocalDate startTime = LocalDate.parse(command.split(" /from ", 2)[1]
.split(" /to ", 2)[0]);
LocalDate endTime = LocalDate.parse(command.split(" /to ", 2)[1]);
String name = command.split(" /from ", 2)[0].split(" ", 2)[1];
Event newEvent = new Event(name, startTime, endTime);
return newEvent;
}

/**
* Creates the new Deadline from the command.
*
* @return The new Deadline.
*/
protected Deadline createDeadlineFromCommand() {
if (command.indexOf("/by") == -1) {
throw new DukeException("Please specify the deadline using /by");
}

if (command.split("/by")[0].strip().equals("deadline")) {
throw new DukeException("The description of a deadline cannot be empty.");
}

LocalDate deadline = LocalDate.parse(command.split(" /by ", 2)[1]);
String name = command.split(" /by ", 2)[0].split(" ", 2)[1];
Deadline newDeadline = new Deadline(name, deadline);
return newDeadline;
}

/**
* Creates the new ToDo from the command.
*
* @return The new ToDo.
*/
protected ToDo createToDoFromCommand() {
if (command.split(" ", 2).length == 1) {
throw new DukeException("OOPS!!! The description of a todo cannot be empty.");
}

ToDo newToDo = new ToDo(command.split(" ", 2)[1]);
return newToDo;
}

/**
* Returns if the parser is ended.
*/
public boolean isEnd() {
return this.isEnd;
}
}
186 changes: 186 additions & 0 deletions src/main/java/duke/Storage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
package duke;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Locale;
import java.util.Scanner;

/**
* Manages storage of the task list.
*/
public class Storage {
private String filePath;

/**
* Constructs a Storage with specific storage file path.
*/
public Storage(String filePath) {
this.filePath = filePath;
}

/**
* Loads the task list with file.
*
* @return The task list.
* @throws IOException If unable to gain input from file.
*/
public ArrayList<Task> load() throws IOException {
String dirPath = this.filePath.split("/")[0];
File f = getFile(dirPath);
ArrayList<Task> tasks = loadTasks(f);
return tasks;
}

/**
* Returns the file for storage. Initializes the directory and the file
* when necessary.
*
* @param path Path of the directory of the storage file.
* @throws IOException If an input or output exception occurs.
*/
private File getFile(String path) throws IOException {
File dir = new File(path);
if (!dir.exists()) {
dir.mkdir();
}
File f = new File(filePath);
if (!f.exists()) {
f.createNewFile();
}
return f;
}

/**
* Returns the task list after loading.
*
* @param f The file for storage.
* @throws FileNotFoundException If an attempt to open the file fails.
*/
private ArrayList<Task> loadTasks(File f) throws FileNotFoundException {
assert f.exists();
Scanner s = new Scanner(f);
ArrayList<Task> tasks = new ArrayList<>();
while (s.hasNext()) {
tasks.add(storageToTask(s.nextLine()));
}
return tasks;
}

/**
* Converts the String input to Task.
*
* @param input The String input.
* @return The corresponding Task.
*/
protected static Task storageToTask(String input) throws DukeException {
String taskType = input.split(" \\| ")[0];
boolean isComplete = input.split(" \\| ")[1].equals("1");
String description = input.split(" \\| ")[2];

if (taskType.equals("T")) {
return new ToDo(description, isComplete);
} else if (taskType.equals("D")) {
return createDeadlineFromStorage(input, description, isComplete);
} else if (taskType.equals("E")) {
return createEventFromStorage(input, description, isComplete);
} else if (taskType.equals("F")) {
return createFixedDurationTaskFromStorage(input, description, isComplete);
} else {
throw new DukeException("Unknown task type.");
}
}


/**
* Creates the FixedDurationTask from the storage input.
*
* @param input The input line.
* @param description The description of the FixedDurationTask.
* @param isComplete Whether the FixedDurationTask is completed.
* @return The Event.
*/
private static FixedDurationTask createFixedDurationTaskFromStorage(String input,
String description, boolean isComplete) {
String duration = input.split(" \\| ")[3];
return new FixedDurationTask(description, isComplete, duration);
}

/**
* Creates the Event from the storage input.
*
* @param input The input line.
* @param description The description of the Event.
* @param isComplete Whether the Event is completed.
* @return The Event.
*/
private static Event createEventFromStorage(String input, String description, boolean isComplete) {
LocalDate start = LocalDate.parse(input.split(" \\| ")[3],
DateTimeFormatter.ofPattern("MMM dd yyyy", Locale.ENGLISH));
LocalDate end = LocalDate.parse(input.split(" \\| ")[4],
DateTimeFormatter.ofPattern("MMM dd yyyy", Locale.ENGLISH));
return new Event(description, isComplete, start, end);
}

/**
* Creates the Deadline from the storage input.
*
* @param input The input line.
* @param description The description of the Deadline.
* @param isComplete Whether the Deadline is completed.
* @return The Event.
*/
private static Deadline createDeadlineFromStorage(String input, String description, boolean isComplete) {
LocalDate d = LocalDate.parse(input.split(" \\| ")[3],
DateTimeFormatter.ofPattern("MMM dd yyyy", Locale.ENGLISH));
return new Deadline(description, isComplete, d);
}


/**
* Adds the last task in the task list to file.
*
* @param list The task list.
* @throws DukeException If unable to write to file.
*/
public void addTheLastTaskToFile(ArrayList<Task> list) throws DukeException {
try {
FileWriter fw = new FileWriter(filePath, true);
if (list.size() != 1) {
fw.write("\n");
}
fw.write(list.get(list.size() - 1).toTxt());
fw.close();
} catch (IOException e) {
throw new DukeException("Unable to write to file.");
}
}

/**
* Rewrites the whole file with the task list.
*
* @param list The task list.
* @throws DukeException If unable to write to file.
*/
public void rewriteFile(ArrayList<Task> list) throws DukeException {
try {
FileWriter fw = new FileWriter(filePath);
for (int i = 0; i < list.size(); i++) {
if (i != list.size() - 1) {
fw.write(list.get(i).toTxt());
fw.write("\n");
continue;
}
fw.write(list.get(i).toTxt());
}
fw.close();
} catch (IOException e) {
throw new DukeException("Unable to write to file.");
}
}
}

64 changes: 64 additions & 0 deletions src/main/java/duke/Task.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package duke;

/**
* Encapsulates tasks for the chat bot.
*/
public class Task {
protected String description;
protected boolean isDone;

/**
* Constructs a Task with specified description.
*
* @param description Description of the task.
*/
public Task(String description) {
assert !description.isEmpty();

this.description = description;
this.isDone = false;
}

/**
* Constructs a Task with specified description and whether
* it is done.
*/
public Task(String description, boolean isDone) {
assert !description.isEmpty();

this.description = description;
this.isDone = isDone;
}

/**
* Gets the status Icon of the Task.
*/
public String getStatusIcon() {
// X for done task
return (isDone ? "X" : " ");
}

/**
* Marks the task as done.
*/
public void markAsDone() {
this.isDone = true;
}

/**
* Returns a String representation for the task for output.
*/
@Override
public String toString() {
return "[" + this.getStatusIcon() + "] " + this.description;
}

/**
* Returns a String representation of the task for storage.
*/
public String toTxt() {
// 1 for done task
return (this.isDone ? "1" : "0") + " | " + this.description;
}

}
97 changes: 97 additions & 0 deletions src/main/java/duke/TaskList.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package duke;

import java.util.ArrayList;

/**
* Encapsulates task list in the chat bot.
*/
public class TaskList {
protected ArrayList<Task> tasks;
private Storage storage;

/**
* Constructs an empty Tasklist with specified Storage.
*/
public TaskList(Storage storage) {
this.tasks = new ArrayList<>();
this.storage = storage;
}

/**
* Constructs a Tasklist with specified tasks and Storage.
*/
public TaskList(ArrayList<Task> tasks, Storage storage) {
this.tasks = tasks;
this.storage = storage;
}

/**
* Lists all tasks in the task list.
*
* @return The message for listing.
*/
public String listTasks() {
return Ui.listTasks(this.tasks);
}

/**
* Adds one task to the task list.
*
* @param t The task to be added.
* @return The message for adding.
*/
public String addTask(Task t) {
this.tasks.add(t);
this.storage.addTheLastTaskToFile(this.tasks);
return Ui.addTask(t, this.tasks);
}

/**
* Deletes the task at the specified position in the task list.
*
* @param num The position starts from 0.
* @return The message for deleting.
*/
public String deleteTask(int num) {
assert num >= 0;

Task re = tasks.remove(num);
this.storage.rewriteFile(tasks);
return Ui.deleteTask(re, tasks);
}

/**
* Marks the task at the specified position in the task list.
*
* @param num The position starts from 0.
* @return The message for marking.
*/
public String markTask(int num) {
assert num >= 0;

Task t = tasks.get(num);
t.markAsDone();
this.storage.rewriteFile(tasks);
return Ui.markTask(t);
}

/**
* Searches all Tasks with the keyword.
*
* @param keyword The keyword.
* @return The message for searching results.
*/
public String findTask(String keyword) {
assert keyword != null;

ArrayList<Task> result = new ArrayList<>();
for (int i = 0; i < this.tasks.size(); i++) {
if (!tasks.get(i).toString().contains(keyword)) {
continue;
}
result.add(tasks.get(i));
}
return Ui.listMatchingTasks(result);
}

}
38 changes: 38 additions & 0 deletions src/main/java/duke/ToDo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package duke;

/**
* Encapsulates todos which are Tasks.
*/
public class ToDo extends Task {

/**
* Constructs a ToDo with specified description.
*/
public ToDo(String description) {
super(description);
}

/**
* Constructs a ToDo with specified description and
* whether it is done.
*/
public ToDo(String description, boolean isDone) {
super(description, isDone);
}

/**
* Returns a String representation for the task for output.
*/
@Override
public String toString() {
return "[T]" + super.toString();
}

/**
* Returns a String representation of the task for storage.
*/
@Override
public String toTxt() {
return "T | " + super.toTxt();
}
}
99 changes: 99 additions & 0 deletions src/main/java/duke/Ui.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package duke;

import java.util.ArrayList;

/**
* Encapsulates ui for chat bot.
*/
public class Ui {

/**
* Returns welcome message.
*/
public static String welcomeMessage() {
return " Hello! I'm Jarvis.\n"
+ " What can I do for you?";
}

/**
* Returns all tasks in task list.
*
* @param tasks The task list.
*/
public static String listTasks(ArrayList<Task> tasks) {
String result = " Here are the tasks in your list:";
int counter = 0;
while (counter != tasks.size()) {
counter++;
result += "\n" + " " + counter + "."
+ tasks.get(counter - 1).toString();
}
return result;
}

/**
* Returns matching tasks in task list.
*
* @param tasks The task list.
*/
public static String listMatchingTasks(ArrayList<Task> tasks) {
String result = " Here are the matching tasks in your list:";
int counter = 0;
while (counter != tasks.size()) {
counter++;
result += "\n" + " " + counter + "."
+ tasks.get(counter - 1).toString();
}
return result;
}

/**
* Returns message for marking a task.
*
* @param t The task marked.
*/
public static String markTask(Task t) {
return " Nice! I've marked this task as done:\n"
+ " " + t.toString();
}

/**
* Returns the message for adding a task.
*
* @param t The task added.
* @param taskList The task list of the task.
*/
public static String addTask(Task t, ArrayList<Task> taskList) {
return " Got it. I've added this task:\n"
+ " " + t.toString() + "\n"
+ " Now you have " + taskList.size() + " tasks in the list.";
}

/**
* Returns the message for deleting a task.
*
* @param t The task deleted.
* @param taskList The task list of the task.
*/
public static String deleteTask(Task t, ArrayList<Task> taskList) {
return " Noted. I've removed this task:\n"
+ " " + t.toString() + "\n"
+ " Now you have " + taskList.size() + " tasks in the list.";
}

/**
* Returns the exception message.
*
* @param e The exception printed.
*/
public static String printException(DukeException e) {
return e.getMessage();
}

/**
* Returns farewell message.
*/
public static String farewellMessage() {
return "Bye. Hope to see you again soon!";
}
}
Binary file added src/main/resources/images/DaDuke.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/main/resources/images/DaUser.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions src/main/resources/view/DialogBox.fxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.layout.HBox?>

<fx:root alignment="TOP_RIGHT" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" prefWidth="400.0" type="javafx.scene.layout.HBox" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1">
<children>
<Label fx:id="dialog" text="Label" wrapText="true" />
<ImageView fx:id="displayPicture" fitHeight="99.0" fitWidth="99.0" pickOnBounds="true" preserveRatio="true" />
</children>
<padding>
<Insets bottom="15.0" left="5.0" right="5.0" top="15.0" />
</padding>
</fx:root>
19 changes: 19 additions & 0 deletions src/main/resources/view/MainWindow.fxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.VBox?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="duke.MainWindow">
<children>
<TextField fx:id="userInput" layoutY="558.0" onAction="#handleUserInput" prefHeight="41.0" prefWidth="324.0" AnchorPane.bottomAnchor="1.0" />
<Button fx:id="sendButton" layoutX="324.0" layoutY="558.0" mnemonicParsing="false" onAction="#handleUserInput" prefHeight="41.0" prefWidth="76.0" text="Send" />
<ScrollPane fx:id="scrollPane" hbarPolicy="NEVER" hvalue="1.0" prefHeight="557.0" prefWidth="400.0" vvalue="1.0">
<content>
<VBox fx:id="dialogContainer" prefHeight="552.0" prefWidth="388.0" />
</content>
</ScrollPane>
</children>
</AnchorPane>
103 changes: 103 additions & 0 deletions src/test/java/duke/ParserTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package duke;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.time.LocalDate;

import org.junit.jupiter.api.Test;

/**
* Tests Parser class.
*/
public class ParserTest {

/**
* Tests parse function with command bye.
*/
@Test
public void parse_bye() {
Parser p = new Parser("bye");
String farewellMessage = Ui.farewellMessage();
assertEquals(farewellMessage, p.parse());
}

/**
* Tests parse function with unknown command.
*/
@Test
public void parse_unknownCommand_exceptionThrown() {
try {
Parser p = new Parser("fvanfjpqner");
String response = p.parse();
} catch (DukeException e) {
String errorMessage = "OOPS!!! I'm sorry, but I don't know what that means :-(";
assertEquals(errorMessage, e.getMessage());
}
}

/**
* Tests createToDoFromCommand.
*/
@Test
public void createToDoFromCommand() {
Parser p = new Parser("todo homework");
ToDo t = p.createToDoFromCommand();
String expected = new ToDo("homework").toString();
assertEquals(expected, t.toString());
}

/**
* Tests createToDoFromCommand with empty description.
*/
@Test
public void createToDoFromCommand_emptyDescription_exceptionThrown() {
try {
Parser p = new Parser("todo");
String response = p.parse();
} catch (DukeException e) {
String errorMessage = "OOPS!!! The description of a todo cannot be empty.";
assertEquals(errorMessage, e.getMessage());
}
}

/**
* Tests createDeadlineFromCommand.
*/
@Test
public void createDeadlineFromCommand() {
String date = "2022-02-02";
Parser p = new Parser("deadline read article /by " + date);
Deadline t = p.createDeadlineFromCommand();
String expected = new Deadline("read article", LocalDate.parse(date)).toString();
assertEquals(expected, t.toString());
}

/**
* Tests createDeadlineFromCommand without /by to specify deadline.
*/
@Test
public void createDeadlineFromCommand_withoutBy_exceptionThrown() {
try {
Parser p = new Parser("deadline read article 2022-02-02");
String response = p.parse();
} catch (DukeException e) {
String errorMessage = "Please specify the deadline using /by";
assertEquals(errorMessage, e.getMessage());
}
}

/**
* Tests createDeadlineFromCommand with empty description.
*/
@Test
public void createDeadlineFromCommand_emptyDescription_exceptionThrown() {
try {
String date = "2022-02-02";
Parser p = new Parser("deadline /by " + date);
String response = p.parse();
} catch (DukeException e) {
String errorMessage = "The description of a deadline cannot be empty.";
assertEquals(errorMessage, e.getMessage());
}
}
}
118 changes: 118 additions & 0 deletions src/test/java/duke/StorageTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package duke;

import static duke.Storage.storageToTask;
import static org.junit.jupiter.api.Assertions.assertEquals;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

import org.junit.jupiter.api.Test;

/**
* Tests Storage class.
*/
public class StorageTest {

/**
* Tests storageToTask function with a ToDo not done.
*/
@Test
public void storageToTask_toDoNotDone() {
String input = "T | 0 | test";
ToDo expected = new ToDo("test", false);
assertEquals(expected.toString(), storageToTask(input).toString());
}

/**
* Tests storageToTask function with a ToDo done.
*/
@Test
public void storageToTask_toDoDone() {
String input = "T | 1 | test";
ToDo expected = new ToDo("test", true);
assertEquals(expected.toString(), storageToTask(input).toString());
}

/**
* Tests storageToTask function with a Deadline not done.
*/
@Test
public void storageToTask_deadlineNotDone() {
String d = "2022-02-02";
LocalDate date = LocalDate.parse(d);
String input = "D | 0 | test | "
+ date.format(DateTimeFormatter.ofPattern("MMM dd yyyy", Locale.ENGLISH));
Deadline expected = new Deadline("test", false, date);
assertEquals(expected.toString(), storageToTask(input).toString());
}

/**
* Tests storageToTask function with a Deadline done.
*/
@Test
public void storageToTask_deadlineDone() {
String d = "2022-02-02";
LocalDate date = LocalDate.parse(d);
String input = "D | 1 | test | "
+ date.format(DateTimeFormatter.ofPattern("MMM dd yyyy", Locale.ENGLISH));
Deadline expected = new Deadline("test", true, date);
assertEquals(expected.toString(), storageToTask(input).toString());
}

/**
* Tests storageToTask function with an Event not done.
*/
@Test
public void storageToTask_eventNotDone() {
String s = "2022-02-02";
LocalDate start = LocalDate.parse(s);
String e = "2023-02-02";
LocalDate end = LocalDate.parse(s);
String input = "E | 0 | test | "
+ start.format(DateTimeFormatter.ofPattern("MMM dd yyyy", Locale.ENGLISH))
+ " | "
+ end.format(DateTimeFormatter.ofPattern("MMM dd yyyy", Locale.ENGLISH));
Event expected = new Event("test", false, start, end);
assertEquals(expected.toString(), storageToTask(input).toString());
}

/**
* Tests storageToTask function with an Event done.
*/
@Test
public void storageToTask_eventDone() {
String s = "2022-02-02";
LocalDate start = LocalDate.parse(s);
String e = "2023-02-02";
LocalDate end = LocalDate.parse(s);
String input = "E | 1 | test | "
+ start.format(DateTimeFormatter.ofPattern("MMM dd yyyy", Locale.ENGLISH))
+ " | "
+ end.format(DateTimeFormatter.ofPattern("MMM dd yyyy", Locale.ENGLISH));
Event expected = new Event("test", true, start, end);
assertEquals(expected.toString(), storageToTask(input).toString());
}

/**
* Tests storageToTask function with a FixedDurationTask not done.
*/
@Test
public void storageToTask_fixedDurationTaskNotDone() {
String d = "one hour";
String input = "F | 0 | test | " + d;
FixedDurationTask expected = new FixedDurationTask("test", false, d);
assertEquals(expected.toString(), storageToTask(input).toString());
}

/**
* Tests storageToTask function with a FixedDurationTask done.
*/
@Test
public void storageToTask_fixedDurationTaskDone() {
String d = "one hour";
String input = "F | 1 | test | " + d;
FixedDurationTask expected = new FixedDurationTask("test", true, d);
assertEquals(expected.toString(), storageToTask(input).toString());
}
}
21 changes: 21 additions & 0 deletions src/test/java/duke/TaskTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package duke;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;

/**
* Tests task class.
*/
public class TaskTest {

/**
* Tests markAsDone function.
*/
@Test
public void markAsDone() {
Task t = new Task("test", false);
t.markAsDone();
assertEquals(true, t.isDone);
}
}
39 changes: 32 additions & 7 deletions text-ui-test/EXPECTED.TXT
Original file line number Diff line number Diff line change
@@ -1,7 +1,32 @@
Hello from
____ _
| _ \ _ _| | _____
| | | | | | | |/ / _ \
| |_| | |_| | < __/
|____/ \__,_|_|\_\___|

____________________________________________________________
Hello! I'm Jarvis
What can I do for you?
____________________________________________________________
____________________________________________________________
Got it. I've added this task:
[T][ ] finish homework
Now you have 1 tasks in the list.
____________________________________________________________
____________________________________________________________
Got it. I've added this task:
[E][ ] class (from: 8 am to: 10 am)
Now you have 2 tasks in the list.
____________________________________________________________
____________________________________________________________
Got it. I've added this task:
[D][ ] noon (by: buy lunch)
Now you have 3 tasks in the list.
____________________________________________________________
____________________________________________________________
Here are the tasks in your list:
1.[T][ ] finish homework
2.[E][ ] class (from: 8 am to: 10 am)
3.[D][ ] noon (by: buy lunch)
____________________________________________________________
____________________________________________________________
Nice! I've marked this task as done:
[T][X] finish homework
____________________________________________________________
____________________________________________________________
Bye. Hope to see you again soon!
____________________________________________________________
6 changes: 6 additions & 0 deletions text-ui-test/input.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
todo finish homework
event class /from 8 am /to 10 am
deadline buy lunch /by noon
list
mark 1
bye
Empty file modified text-ui-test/runtest.sh
100644 → 100755
Empty file.