Skip to content
Open
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
d839859
Add Gradle support
May 24, 2020
8d48ae0
added user echo
ovidharshini Jan 20, 2022
a71e87b
Store input list
ovidharshini Jan 25, 2022
3f61a7f
Represent task as class
ovidharshini Jan 25, 2022
177c694
Add marking for tasks
ovidharshini Jan 25, 2022
0438b9b
Add todo, deadline, event tasks
ovidharshini Jan 26, 2022
f2f611d
Add files for I/O redirection testing
ovidharshini Jan 26, 2022
fa10811
Add input sanitization
ovidharshini Jan 26, 2022
21a974e
Add delete feature for list
ovidharshini Jan 26, 2022
6fed456
Add save task feature
ovidharshini Jan 28, 2022
0409484
Add date, time recognition
ovidharshini Jan 28, 2022
c642af9
Merge branch 'branch-Level-7'
ovidharshini Jan 28, 2022
ce8a662
Merge branch 'branch-Level-8'
ovidharshini Jan 28, 2022
3b49e3e
Refactor to use more OOP-based code
ovidharshini Jan 31, 2022
3660e1d
Add packages
ovidharshini Jan 31, 2022
9946873
Add JUnit tests
ovidharshini Jan 31, 2022
5aad65b
Apply Java coding standards
ovidharshini Feb 1, 2022
769a988
Add keyword search command
ovidharshini Feb 1, 2022
b3aa7d8
Merge branch 'branch-Level-9'
ovidharshini Feb 1, 2022
924705b
Resolve merge conflict in import packages
ovidharshini Feb 1, 2022
5f5dd50
Resolve merge conflict
ovidharshini Feb 1, 2022
53505d2
Add JavaDoc comments
ovidharshini Feb 1, 2022
69cbb4b
Resolve merge conflict
ovidharshini Feb 1, 2022
529f480
Add comments for search functionality
ovidharshini Feb 1, 2022
b295aff
Resolve coding standard violations
ovidharshini Feb 10, 2022
e36ebcc
Merge remote-tracking branch 'origin/add-gradle-support' into HEAD
ovidharshini Feb 10, 2022
ffddffd
Add gradle support
ovidharshini Feb 10, 2022
6b35610
Resolve checkstyle warnings
ovidharshini Feb 10, 2022
16ca7b6
Delete redundant code
ovidharshini Feb 11, 2022
5860071
Add GUI
ovidharshini Feb 18, 2022
7ae1137
Merge branch 'branch-Level-10'
ovidharshini Feb 18, 2022
116bf2b
Use Java assert feature
ovidharshini Feb 21, 2022
fed8f6a
Improve code quality
ovidharshini Feb 21, 2022
d40a5c4
Merge pull request #3 from ovidharshini/branch-A-CodeQuality
ovidharshini Feb 21, 2022
9156df9
Merge branch 'master' into branch-A-Assertions
ovidharshini Feb 21, 2022
4a0baa9
Merge pull request #2 from ovidharshini/branch-A-Assertions
ovidharshini Feb 21, 2022
bd1716c
Fix bug with assertions
ovidharshini Feb 25, 2022
66c176c
Add DoAfter tasks
ovidharshini Feb 26, 2022
f2811c7
Handle NumberFormatException in input
ovidharshini Feb 26, 2022
e2e208b
Handle assertion edgecase
ovidharshini Feb 26, 2022
0060559
Merge branch 'branch-B-DoAfterTasks'
ovidharshini Feb 26, 2022
13e7025
Decrease font size
ovidharshini Feb 26, 2022
7798267
Fix minor spelling error
ovidharshini Feb 26, 2022
22cb406
Add tick unicode symbol
ovidharshini Feb 26, 2022
5a1a342
Add icon
ovidharshini Feb 26, 2022
a67fb2e
Add representative screenshot
ovidharshini Feb 26, 2022
7ec9d76
Fix date storage bug
ovidharshini Feb 26, 2022
9aabb5f
Add user guide
ovidharshini Feb 26, 2022
47ec326
Set theme jekyll-theme-minimal
ovidharshini Feb 26, 2022
063970e
Set theme jekyll-theme-slate
ovidharshini Feb 26, 2022
197ba6b
Set theme jekyll-theme-slate
ovidharshini Feb 26, 2022
dc40c8b
Set theme jekyll-theme-midnight
ovidharshini Feb 26, 2022
61ee763
Set theme jekyll-theme-slate
ovidharshini Feb 26, 2022
28108d3
Set theme jekyll-theme-time-machine
ovidharshini Feb 26, 2022
a4d416c
Set theme jekyll-theme-cayman
ovidharshini Feb 26, 2022
dd686dc
Set theme jekyll-theme-tactile
ovidharshini Feb 26, 2022
2af586e
Set theme jekyll-theme-hacker
ovidharshini Feb 26, 2022
6cd5b5f
Delete theme
ovidharshini Feb 26, 2022
fc44103
Set markdown processor for gh pages
ovidharshini Feb 26, 2022
cc59e17
Update _config.yml
ovidharshini Feb 26, 2022
00ea1fb
Fix bug with GFMD rendering
ovidharshini Feb 26, 2022
1c79bf6
Change Ui.png capitalization
ovidharshini Feb 26, 2022
8bdaf26
Add Ui.png
ovidharshini Feb 26, 2022
307ce9e
Add Mac, Linux compatibility
ovidharshini Mar 2, 2022
7aae63c
Change minor messages
ovidharshini Mar 2, 2022
cdf341e
Resolve filepath bug, GUI errors
ovidharshini Mar 3, 2022
1c9240d
Add updated Ui.png
ovidharshini Mar 3, 2022
af733da
Add attribution for images
ovidharshini Mar 3, 2022
6048095
Resolve bug with image display
ovidharshini Mar 3, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions src/main/java/Duke.java

This file was deleted.

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

import duke.task.Todo;
import duke.task.Event;
import duke.task.Deadline;
import duke.task.TaskList;

/**
* The Duke program implements a simple task bot application with CRUD functionality.
* The program can add three different types of tasks (todo, deadline, event), mark tasks as done, and
* delete tasks.
*
* @author Elumalai Oviya Dharshini
* @version 0.1
*/
public class Duke {
private Storage storage;
private TaskList tasks;
private final Ui ui;

/**
* Constructor for Duke that instantiates UI and storage, and loads Tasks from a file into tasks.
* If there is an error with loading Tasks from the specified file, it initializes tasks to be an empty
* TaskList.
*
* @param filePath path of the storage file from the current directory
*/
public Duke(String filePath) {
ui = new Ui();
try {
storage = new Storage(filePath);
tasks = new TaskList(storage.load());
} catch (Exception e) {
ui.showLoadingError();
tasks = new TaskList();
}
}

/**
* Handles the execution and main logic of the Duke program.
* It polls for user input continuously, parses user input and displays appropriate messages until user
* input is "bye", upon which it displays a goodbye message and terminates the program.
*/
public void run() {
ui.showWelcome();
boolean isExit = false;
while (!isExit) {
try {
String input = ui.readInput();
String command = Parser.parse(input);

if (command.equals("")) {
ui.showCommandMessage(command, tasks);
continue;
}
input = Parser.handleInput(input);

try {
switch (command) {
case "list":
ui.showCommandMessage(command, tasks);
break;
case "do":
int i = Integer.parseInt(input.replaceAll("[^0-9]", "")) - 1;
tasks.get(i).markComplete();
ui.showCommandMessage(command, tasks);
break;
case "undo":
int j = Integer.parseInt(input.replaceAll("[^0-9]", "")) - 1;
tasks.get(j).markIncomplete();
ui.showCommandMessage(command, tasks);
break;
case "delete":
int k = Integer.parseInt(input.replaceAll("[^0-9]", "")) - 1;
tasks.remove(k);
ui.showCommandMessage(command, tasks);
break;
case "todo":
Todo t = new Todo(input);
tasks.add(t);
ui.showCommandMessage(command, tasks);
System.out.println(t);
break;
case "find":
ui.showCommandMessage(command, tasks);
System.out.println(tasks.find(input));
break;
case "deadline":
String datetime = input.replaceAll(".* by ", "");
input = input.replaceAll(" by .*", "");
Deadline d = new Deadline(input, datetime);
tasks.add(d);
ui.showCommandMessage(command, tasks);
System.out.println(d);
break;
case "event":
String time = input.replaceAll(".* at ", "");
input = input.replaceAll(" at .*", "");
Event e = new Event(input, time);
tasks.add(e);
ui.showCommandMessage(command, tasks);
System.out.println(e);
break;
}

if (!command.equals("list") && !command.equals("bye")) {
storage.save(tasks);
}
} catch (Exception e) {
throw new RuntimeException(e.getMessage());
}

isExit = command.equals("bye");
} catch (Exception e) {
ui.showError(e.getMessage());
}
}
}

/**
* Main method that starts the program by calling a new instance of Duke with a specified file path.
*
* @param args command-line arguments
*/
public static void main(String[] args) {
new Duke("../../../data/tasks.txt").run();
}

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

/**
* Represents a class that validates and interprets user input with a pre-generated list of allowable
* input formats.
* Note: Current allowable formats are "list", "bye", "do X", "undo X", "delete X", "todo S",
* "deadline S by T", "event S at T", "find W", where X is an integer, S is a string descriptor of the task, W
* is a singular keyword and T is a string descriptor of the date(s) and/or time(s) associated with the task.
*
* @author Elumalai Oviya Dharshini
* @version 0.1
*/
public class Parser {

/**
* Extracts the non-command contents of a given input string.
* Strips the string of leading whitespaces and removes the first word.
*
* @return input consisting of the non-command contents of the input string
*/
public static String handleInput(String input) {
input = input.trim();
if (input.contains(" ")) {
input = input.substring(input.indexOf(" "));
}
return input;
}

/**
* Validates format of input and extracts command from the given input, if any.
* Note: Current allowable formats are "list", "bye", "do X", "undo X", "delete X", "todo S", "find W",
* "deadline S by T", "event S at T", where X is an integer, S is a string descriptor of the task, W is a
* singular keyword and T is a string descriptor of the date(s) and/or time(s) associated with the task.
*
* @return command from input string if input is of a valid format, "" otherwise
*/
public static String parse(String input) {
input = input.trim();
String command = input.replaceAll(" .*", "");

input = input.trim();
if (input.equals("bye") || input.equals("list")) {
return command;
}

// Handle do, undo, delete
String firstWord = input.replaceAll(" .*", "");
if (firstWord.equals("do") || firstWord.equals("undo") || firstWord.equals("delete")) {
input = input.replaceAll(".* ", "");
if (input.matches("[0-9]+")) {
return command;
}
System.out.println("You need to specify the task you want to "+ firstWord + " by its index :c");
return "";
}

// Handle todo
if (firstWord.equals("todo")) {
input = input.substring(4).trim();
if (input.equals("")) {
System.out.println("Oops, you need to mention what the task is :c");
return "";
}
return command;
}

// Handle deadline
if (firstWord.equals("deadline")) {
input = input.substring(8).trim();
if (!input.contains(" by ")) {
System.out.println("Oops, you need to format deadline tasks as \"deadline X by Y\" :c");
return "";
}
String lastWord = input.substring(input.lastIndexOf(" ") + 1);
if (lastWord.equals("by")) {
return "";
}
return command;
}

// Handle event
if (firstWord.equals("event")) {
input = input.substring(5).trim();
if (!input.contains(" at ")) {
System.out.println("Oops, you need to format event tasks as \"event X at Y\" :c");
return "";
}
String lastWord = input.substring(input.lastIndexOf(" ")+1);
if (lastWord.equals("at")) {
return "";
}
return command;
}

// Handle find
if (firstWord.equals("find")) {
input = input.substring(4).trim();
if (input.equals("")) {
System.out.println("Oops, you need to mention what the keyword is :c");
return "";
}
if (input.contains(" ")) {
System.out.println("Oops, you can only search for one keyword at a time :c");
return "";
}
return command;
}

return "";
}
Comment thread
ovidharshini marked this conversation as resolved.
}
124 changes: 124 additions & 0 deletions src/main/java/duke/Storage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package duke;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;

import duke.task.Task;
import duke.task.Todo;
import duke.task.Event;
import duke.task.Deadline;
import duke.task.TaskList;

/**
* Represents a storage space for tasks on hard-drive.
* It handles the loading of tasks from a file and saving of tasks to the same file.
*
* @author Elumalai Oviya Dharshini
* @version 0.1
*/
public class Storage {
protected String filePath;
ArrayList<Task> tasks;

/**
* Suppresses any unused warnings from a given boolean result.
*
* @param result variable to suppress warnings from
*/
//@@author Eric Lange-reused
//Reused from https://stackoverflow.com/questions/27904329/warning-file-mkdir-is-ignored#answer-54341862
// with minor modifications
@SuppressWarnings("unused")
private static void IGNORE_RESULT(boolean result) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure what does this means, it is not returning anything

Copy link
Copy Markdown
Author

@ovidharshini ovidharshini Feb 10, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This utility function is defined for mkdirs - which creates parent directories of a given location (if they don't exist) and returns True or False depending on whether directories were created. This suppresses the File.mkdirs() is ignored warning that results from not handling the return value of mkdirs.

I am not certain if this is the recommended way to handle it so I am leaving it as is for now.


}
//@@author

/**
* Constructor for Storage that initializes the Storage object with a given file path.
* It parses input from the specified file and saves the list of Tasks from the specified file, if any.
* If file does not exist, it creates the file.
* Note: any missing parent directories in the specified file path are created prior to file creation.
*
* @param filePath path of the specified file from the current directory
* @throws IOException if an exception occurs in the creation/access of the specified file
* @throws RuntimeException if file at specified path contains data in a non-standard format
*/
Storage(String filePath) throws IOException {
this.filePath = filePath;
File data = new File(filePath);
data.getParentFile().mkdirs();
IGNORE_RESULT(data.getParentFile().mkdirs()); //make preceding directories, if any are not found

tasks = new ArrayList<>();
if (!data.createNewFile()) { //if file exists
Scanner fileReader = new Scanner(data);
while (fileReader.hasNextLine()) {
String line = fileReader.nextLine();
String[] tmp = line.split("\\|");
boolean isDone = tmp[1].trim().equals("D");

switch (tmp[0].trim()) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You followed the coding standard for switch case! Great Job!

case "T":
Todo t = new Todo(tmp[2].trim());
if (isDone) {
t.markComplete();
}
tasks.add(t);
break;
case "D":
Deadline d = new Deadline(tmp[2].trim(), tmp[3].trim());
if (isDone) {
d.markComplete();
}
tasks.add(d);
break;
case "E":
Event e = new Event(tmp[2].trim(), tmp[3].trim());
if (isDone) {
e.markComplete();
}
tasks.add(e);
break;
default:
throw new RuntimeException("Corrupted data in data file at " + filePath);
}
}
fileReader.close();
}
}

/**
* Retrieves and returns Tasks saved from the storage file.
*
* @return ArrayList of saved Tasks
*/
public ArrayList<Task> load() {
return tasks;
}

/**
* Updates the list of Tasks saved on hard-drive at filePath by overwriting the existing file at filePath.
* Note: File creation is to be handled via load() prior this method as this assumes that filePath is
* valid and that the file exists at filePath.
*
* @param tasks TaskList of Tasks to be saved on hard-drive
* @throws IOException if an exception occurs in the saving of data to the file at filePath
*/
public void save(TaskList tasks) throws IOException {
File data = new File(filePath);
FileWriter f;

f = new FileWriter(data, false);
boolean isFirst = true;
for (int i = 0; i < tasks.size(); i++) {
String s = isFirst ? "" : "\n";
f.write(s + tasks.get(i).writeToFile());
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps a line break after the "." operators would enhance readability? I noticed the same issue in several other places too.

isFirst = false;
}
f.close();
}
}
Loading