Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Sean Ng] iP #286

Open
wants to merge 57 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
2519155
Level-1
snss231 Jan 19, 2022
a5c779a
Level-2
snss231 Jan 19, 2022
80d70fc
Level-3 A-Classes
snss231 Jan 19, 2022
d536355
Level-4 A-Inheritance
snss231 Jan 19, 2022
fb6d372
A-TextUiTesting
snss231 Jan 19, 2022
6f7b169
Level 5 A-Exceptions
snss231 Jan 19, 2022
719510a
Level-6 A-Collections
snss231 Jan 19, 2022
9863744
A-Enums
snss231 Jan 19, 2022
fbfe1e0
unindent switch cases
snss231 Jan 21, 2022
e97f636
Add save functionality, add more exceptions
snss231 Jan 29, 2022
d42a7f8
Handle data folder does not exist
snss231 Jan 29, 2022
a16f6ca
Add basic date functionality for Deadline
snss231 Jan 29, 2022
46af47a
Merge branch 'branch-level-7'
snss231 Jan 29, 2022
7cf6169
Merge branch 'branch-level-8'
snss231 Jan 29, 2022
0bac52b
Implement TaskList, Storage, add data/ to .gitignore
snss231 Jan 29, 2022
1d1ae32
Create and implement Command class + subclasses
snss231 Jan 29, 2022
1d109e0
Create and implement Command class + subclasses
snss231 Jan 29, 2022
d602326
Create and implement Command + subclasses
snss231 Jan 29, 2022
dfd72e3
Implement ui methods, bro-ify messages, organise into packages"
snss231 Jan 29, 2022
f4c7ed0
Add unit tests for Deadline and Todo
snss231 Jan 29, 2022
637c056
Add javadocs for commands
snss231 Jan 29, 2022
339d188
Add javadocs for tasks
snss231 Jan 29, 2022
03ad577
Add javadocs for Duke, DukeException, Parser, Storage, TaskList, Ui
snss231 Jan 29, 2022
724ff1d
Align to coding standard
snss231 Jan 29, 2022
ee1f046
Add find functionality
snss231 Jan 29, 2022
4ec3ff8
Fix merge conflicts
snss231 Jan 29, 2022
764c52e
Fix merge conflicts
snss231 Jan 29, 2022
40c3895
Fix typo in showMarkTask header
snss231 Jan 29, 2022
0ae899d
Update README.md
snss231 Feb 3, 2022
73414eb
Fix minor coding standard issues
snss231 Feb 4, 2022
699cad2
Fix import *
snss231 Feb 4, 2022
7cfb21a
Add gradle
snss231 Feb 4, 2022
1478520
Merge
snss231 Feb 4, 2022
6210e86
Add checkstyle and fix coding violations
snss231 Feb 4, 2022
1aabae6
Implement GUI
snss231 Feb 4, 2022
4b4fcd7
Add bot logic to GUI
snss231 Feb 4, 2022
3342d28
Add assertions in Duke constructor
snss231 Feb 12, 2022
b054cc9
Split up ShowFindTasks and ShowTasks to improve code quality
snss231 Feb 12, 2022
d2f7a01
Merge pull request #2 from snss231/branch-A-Assertions
snss231 Feb 12, 2022
7ce96b8
Merge branch 'master' into branch-A-CodeQuality
snss231 Feb 12, 2022
b37b782
Merge pull request #3 from snss231/branch-A-CodeQuality
snss231 Feb 12, 2022
44754e2
Setup Github Actions CI
snss231 Feb 12, 2022
7c31dac
Edit workflow file
snss231 Feb 12, 2022
dcd1ed1
Remove unused imports
snss231 Feb 12, 2022
243c2d5
There is no help command.
snss231 Feb 13, 2022
cdfb73d
Add background, adjust padding
snss231 Feb 21, 2022
de3e6db
Add screenshot
snss231 Feb 21, 2022
bd9c531
Make photos circle
snss231 Feb 21, 2022
c890315
Update ss
snss231 Feb 21, 2022
799a36f
Update ss
snss231 Feb 21, 2022
cd4d936
Update README.md
snss231 Feb 21, 2022
ac8d1b1
Update README.md
snss231 Feb 21, 2022
c9e074d
Update README.md
snss231 Feb 21, 2022
ab9f632
Update README.md
snss231 Feb 21, 2022
287cf9d
Update README.md
snss231 Feb 23, 2022
a316127
Update README.md
snss231 Feb 23, 2022
7079f72
Fix checkstyle
snss231 Feb 26, 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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ bin/

/text-ui-test/ACTUAL.txt
text-ui-test/EXPECTED-UNIX.TXT

data/
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Duke project template
# duke.Duke project template

This is a project template for a greenfield Java project. It's named after the Java mascot _Duke_. Given below are instructions on how to use it.

Expand All @@ -13,7 +13,7 @@ Prerequisites: JDK 11, update Intellij to the most recent version.
1. If there are any further prompts, accept the defaults.
1. Configure the project to use **JDK 11** (not other versions) as explained in [here](https://www.jetbrains.com/help/idea/sdk.html#set-up-jdk).<br>
In the same dialog, set the **Project language level** field to the `SDK default` option.
3. After that, locate the `src/main/java/Duke.java` file, right-click it, and choose `Run Duke.main()` (if the code editor is showing compile errors, try restarting the IDE). If the setup is correct, you should see something like the below as the output:
3. After that, locate the `src/main/java/duke.Duke.java` file, right-click it, and choose `Run duke.Duke.main()` (if the code editor is showing compile errors, try restarting the IDE). If the setup is correct, you should see something like the below as the output:
```
Hello from
____ _
Expand Down
10 changes: 0 additions & 10 deletions src/main/java/Duke.java

This file was deleted.

3 changes: 3 additions & 0 deletions src/main/java/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Manifest-Version: 1.0
Main-Class: duke.Duke

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

import duke.command.Command;

/**
* Main driver class for task organisation bot Duke.
*/
public class Duke {

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

/**
* Creates a new Duke.
*/
public Duke() {
ui = new Ui();
storage = new Storage();
try {
tasks = new TaskList(storage.load());
} catch (Exception e) {
ui.showLoadingError();
tasks = new TaskList();
}
}

/**
* Listen for user input and respond until "bye" command is issued.
*/
public void run() {
this.ui.greet();
boolean isExit = false;
while (!isExit) {
try {
String fullCommand = ui.readCommand();
Command c = Parser.parse(fullCommand);
c.execute(tasks, ui, storage);
isExit = c.isExit();
} catch (DukeException e) {
ui.showError(e.getMessage());
}
}
}

public static void main(String[] args) {
new Duke().run();
}
}
16 changes: 16 additions & 0 deletions src/main/java/duke/DukeException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package duke;

/**
* Custom exception class for Duke.
*/
public class DukeException extends Exception {

/**
* Creates a new DukeException
*
* @param errorMessage Error message explaining the reason for generating the DukeException.
*/
public DukeException(String errorMessage) {
super(errorMessage);
}
}
100 changes: 100 additions & 0 deletions src/main/java/duke/Parser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package duke;

import duke.command.*;
snss231 marked this conversation as resolved.
Show resolved Hide resolved

import java.time.LocalDate;
import java.time.format.DateTimeParseException;

/**
* Class that parses user input and returns the corresponding command.
*/
public class Parser {

/**
* Main method that takes in raw user input and returns the corresponding command.
*
* @param fullCommand The raw string input by the user.
* @return The command corresponding to the user's input.
* @throws DukeException If user's input is invalid (does not correspond to any command or invalid parameters).
*/
public static Command parse(String fullCommand) throws DukeException {
String[] input = fullCommand.split(" ", 2); //return [commandWord, restOfCommand]
snss231 marked this conversation as resolved.
Show resolved Hide resolved
String commandWord = input[0];

switch(commandWord) {
case ListCommand.COMMAND_WORD:
return new ListCommand();
case MarkCommand.COMMAND_WORD: {
int index = -1;
try {
index = Integer.valueOf(input[1]) - 1;
return new MarkCommand(index);
} catch (NumberFormatException e) {
throw new DukeException("Invalid parameter(s). Usage: mark [taskNumber]");
} catch (IndexOutOfBoundsException e) {
throw new DukeException("Invalid parameter(s). duke.task.Task " + (index + 1) + " does not exist");

Choose a reason for hiding this comment

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

I think IndexOutOfBoundsException will never be caught here? The error will be thrown in the execute function and the same error was handled there as well.

}
}
case UnmarkCommand.COMMAND_WORD: {
int index = -1;
try {
index = Integer.valueOf(input[1]) - 1;
return new UnmarkCommand(index);
} catch (NumberFormatException e) {
throw new DukeException("Invalid parameter(s). Usage: mark [taskNumber]");
} catch (IndexOutOfBoundsException e) {
throw new DukeException("Invalid parameter(s). duke.task.Task " + (index + 1) + " does not exist");
}
}
case TodoCommand.COMMAND_WORD:
try {
String description = input[1];
return new TodoCommand(description);
} catch (IndexOutOfBoundsException e) {
throw new DukeException("Invalid parameter(s). Usage: todo [description]");
}
case DeadlineCommand.COMMAND_WORD:
try {
String[] args = input[1].split(" /by ", 2);
String description = args[0];
LocalDate deadline = LocalDate.parse(args[1]);
return new DeadlineCommand(description, deadline);
} catch (DateTimeParseException e) {
throw new DukeException("Please specify your date in the format \"yyyy-mm-dd\"");
} catch (IndexOutOfBoundsException e) {
throw new DukeException("Invalid parameter(s). Usage: deadline [description] /by [time]");
}
case EventCommand.COMMAND_WORD:
try {
String[] args = input[1].split(" /at ", 2);
String description = args[0];
String at = args[1];
return new EventCommand(description, at);
} catch (IndexOutOfBoundsException e) {
throw new DukeException("Invalid parameter(s). Usage: event [description] /at [time]");
}
case DeleteCommand.COMMAND_WORD: {
int index = -1;
try {
index = Integer.parseInt(input[1]) - 1;
return new DeleteCommand(index);
} catch (NumberFormatException e) {
throw new DukeException("Invalid parameter(s). Usage: delete [taskNumber]");
} catch (IndexOutOfBoundsException e) {
throw new DukeException("Invalid parameter(s). duke.task.Task " + (index + 1) + " does not exist");
}
}
case FindCommand.COMMAND_WORD:
try {
String keyword = input[1];
return new FindCommand(keyword);
} catch (IndexOutOfBoundsException e) {
throw new DukeException("Invalid parameters. Usage: find [keyword]");
}
case ByeCommand.COMMAND_WORD:
return new ByeCommand();
default:
throw new DukeException("Unknown command");
}
}
}
49 changes: 49 additions & 0 deletions src/main/java/duke/Storage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package duke;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;

/**
* Responsible for writing and loading the list of tasks to and from the user's memory.
*/
public class Storage {

static final String PROJECT_ROOT = System.getProperty("user.dir");
snss231 marked this conversation as resolved.
Show resolved Hide resolved

/**
* Writes the list of tasks to {PROJECT_ROOT}/data/duke.txt
*
* @param tasks The list of tasks to be written.
*/
public void save(TaskList tasks) {
try {
String path = Path.of(PROJECT_ROOT, "data", "duke.txt").toString();
FileOutputStream fos = new FileOutputStream(path);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(tasks);
} catch (IOException e) {
System.out.println(e);
}
}

/**
* Loads the list of tasks from {{PROJECT_ROOT}/data/duke.txt}
*
* @return The saved list of tasks.
*/
public TaskList load() {
Path dataFolder = Path.of(PROJECT_ROOT, "data");
if (!Files.exists(dataFolder)) { //initialize data directory if not present

Choose a reason for hiding this comment

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

Good use of guard clause here

new File(dataFolder.toString()).mkdir();
}
try {
String path = Path.of(PROJECT_ROOT, "data", "duke.txt").toString();
FileInputStream fis = new FileInputStream(path);
ObjectInputStream ois = new ObjectInputStream(fis);
return (TaskList) ois.readObject();
} catch (IOException | ClassNotFoundException e) { //if duke.txt does not exist or is weird
return new TaskList();
}
}
}
106 changes: 106 additions & 0 deletions src/main/java/duke/TaskList.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package duke;

import duke.task.Task;

import java.io.Serializable;
import java.sql.Array;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
* Represents the list of user's tasks.
*/
public class TaskList implements Serializable {

private ArrayList<Task> tasks;

/**
* Creates a new empty list of tasks.
*/
public TaskList() {
this.tasks = new ArrayList<>();
}

/**
* Initialize based on the list of tasks saved in the user's memory.
*
* @param tasks The saved list of tasks.
*/
public TaskList(TaskList tasks) {
this.tasks = new ArrayList<>(tasks.tasks);
}

/**
* Marks the task corresponding to the index as completed.
*
* @param index The index of the task to be marked completed.
* @return The completed task.
*/
public Task mark(int index) {
Task task = this.tasks.get(index);
Copy link

Choose a reason for hiding this comment

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

I am unsure if "this" statement is necessary?

This doesn't recommend based on the coding standard.

Can considering removing this statement.

Copy link
Author

Choose a reason for hiding this comment

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

I wasn't aware of this, my perception was that the "this" keyword should be used where possible to make the code more explicit. I tried finding information related to the "this" keyword in the coding standard document @ https://se-education.org/guides/conventions/java/intermediate.html but couldn't find it, mind pointing me in the right direction? thanks 😄

task.mark();
return task;
}

/**
* Unmarks the task corresponding to the index as completed.
*
* @param index The index of the task to be unmarked completed.
* @return The incomplete task.
*/
public Task unmark(int index) {
Task task = this.tasks.get(index);
task.unmark();
return task;
}

/**
* Adds a task to the list of tasks.
*
* @param task The task to be added.
*/
public void addTask(Task task) {
tasks.add(task);
}

/**
* Deletes a task from the list of tasks based on the index.
*
* @param index The index of the task to be deleted.
* @return The deleted task.
*/
public Task deleteTask(int index) {
Task task = tasks.get(index);
tasks.remove(index);
return task;
}

/**
* Counts the number of tasks in the list.
*
* @return The number of tasks.
*/
public int count() {
return this.tasks.size();
}

@Override
public String toString() {
List<String> taskStrings = IntStream.range(0, tasks.size())
.mapToObj(i -> (i + 1) + ". " + tasks.get(i).toString())
.collect(Collectors.toList());
return String.join("\n", taskStrings);
}

public boolean isEmpty() {
return this.tasks.size() == 0;
}

public TaskList findTasks(String keyword) {
TaskList tl = new TaskList(this);
tl.tasks.removeIf(task -> !task.descriptionContains(keyword));
return tl;
}
}
Loading