diff --git a/docs/README.md b/docs/README.md index fd4406959..ce68dc5aa 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,20 +1,154 @@ # User Guide -## Features +Welcome! Come and plan your tasks with Duke! :) -### Feature 1 -Description of feature. +#### Types of tasks: -## Usage +1. ToDo +2. Event +3. Deadline -### `Keyword` - Describe action +* [Quick Start](#quick-Start) +* [Features](#features) + * [List all Tasks : `list`](#list-all-tasks--list) + * [Add Todo : `todo`](#add-todo--todo) + * [Add Event : `event`](#add-event--event) + * [Add Deadline : `deadline`](#add-deadline--deadline) + * [Delete Task : `delete`](#delete-task--delete) + * [Mark Task as Done : `done`](#mark-task-as-done--done) + * [Find by Keyword : `find`](#find-by-keyword--find) + * [Exit : `bye`](#exit--bye) +* [Command Summary](#command-summary) -Describe action and its outcome. +  -Example of usage: +## Quick Start -`keyword (optional arguments)` +Download `Duke.jar` from +here: https://github.com/beaniestanley/ip/releases/tag/A-Release -Expected outcome: +**Requirements:** -`outcome` +Ensure you have Java 11 or above installed. + +**Usage:** + +1. Store the .jar file in a folder +2. Run the .jar file +3. Enter your command! + +  + +## Features + +### List all Tasks : `list` + +Displays all the tasks currently in your task list. + +> `[T]` Todo
+> `[E]` Event
+> `[D]` Deadline
+ +> `[X]` Done
+> `[ ]` Not done + +**Format:** `list` + +| | Example | +| --------- | ------------------------------------------------------- | +| Input | `list` | +| Output | `Here are the tasks in your list: `
`1.[T][ ] Exercise`
`2.[E][X] Meet friends (at: May 22nd 5pm)`
`3.[D][ ] Watch lecture (by: Sunday 3pm)` | + +  + +### Add ToDo : `todo` + +Adds a Todo with description.
+**Format:** `todo ` + +| | Example | +| --------- | ------------------------------------------------------- | +| Input | `todo eat apple` | +| Output | `Got it. I've added this task:`
`[T][ ] eat apple`
`Now you have 4 tasks in the list.` | + +  + +### Add Event : `event` + +Adds an event with description and datetime.
+**Format:** `event /at ` + +| | Example | +| --------- | ------------------------------------------------------- | +| Input | `Celebrate May's birthday /at 05/06/2021 1900` | +| Output | `Got it. I've added this task:`
`[E][ ] party (at: 05/06/2021 1900)`
`Now you have 5 tasks in the list.` |` + +  + +### Add Deadline : `deadline` + +Adds a deadline with description and datetime.
+**Format:** `deadline /by ` + +| | Example | +| --------- | ------------------------------------------------------- | +| Input | `deadline Finish iP /by Sunday 3pm` | +| Output | `Got it. I've added this task:`
`[D][ ] Finish iP (by: Sunday 3pm)`
`Now you have 6 tasks in the list.` | + +  + +### Delete Task : `delete` + +Deletes a task using specified index.
+**Format:** `delete ` + +| | Example | +| --------- | ------------------------------------------------------- | +| Input | `delete 6` | +| Output | `Noted, I've removed this task:`
`[D][ ] Finish iP (by: Sunday 3pm)` | + +  + +### Mark Task As Done : `done` + +Marks task as done.
+**Format:** `done ` + +| | Example | +| --------- | ------------------------------------------------------- | +| Input | `done 5` | +| Output | `Great job! I've marked this task as done:`
`[X] party` | + +  + +### Find by Keyword : `find` + +Displays all tasks containing the keyword.
+**Format:** `find ` + +| | Example | +| --------- | ------------------------------------------------------- | +| Input | `find project` | +| Output | `Here are the matching tasks in your list:`
`1. [T][ ] do project` | + +  + +### Exit : `bye` + +Exits Application.
+**Format:** `bye` + +  + +## Command summary + +| Command | Format | +| --------- | ------------------------------------------------------- | +| list | `list` | +| todo | `todo ` | +| event | `event /at ` | +| deadline | `deadline /by ` | +| delete | `delete ` | +| done | `done ` | +| find | `find ` | +| bye | `bye` | \ No newline at end of file diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 000000000..c4192631f --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-cayman \ No newline at end of file diff --git a/src/main/java/Classes/Deadline.java b/src/main/java/Classes/Deadline.java new file mode 100644 index 000000000..da70759a4 --- /dev/null +++ b/src/main/java/Classes/Deadline.java @@ -0,0 +1,26 @@ +package Classes; + +public class Deadline extends Task { + protected String by; + + public Deadline(String description, boolean isDone, String by) { + super(description, isDone); + this.by = by; + } + + /** + * @return String containing description of Deadline task + */ + @Override + public String toString() { + return "[D]" + super.toString() + "(by: " + this.by + ")"; + } + + /** + * @return String of formatted data to be written into the text file + */ + public String formatString() { + int done = (isDone ? 1 : 0); + return "D-" + done + "-" + description + "-" + by + "\n"; + } +} diff --git a/src/main/java/Classes/Event.java b/src/main/java/Classes/Event.java new file mode 100644 index 000000000..4e6f0c326 --- /dev/null +++ b/src/main/java/Classes/Event.java @@ -0,0 +1,27 @@ +package Classes; + +public class Event extends Task { + protected String at; + + public Event(String description, boolean isDone, String at) { + super(description, isDone); + this.at= at; + } + + /** + * @return String String containing description of Event task + */ + @Override + public String toString() { + return "[E]" + super.toString() + "(at: " + this.at + ")"; + } + + /** + * @return String of formatted data to be written into the text file + */ + public String formatString() { + int done = (isDone ? 1 : 0); + return "E-" + done + "-" + description + "-" + at + "\n"; + } +} + diff --git a/src/main/java/Classes/Task.java b/src/main/java/Classes/Task.java new file mode 100644 index 000000000..c4d4d414a --- /dev/null +++ b/src/main/java/Classes/Task.java @@ -0,0 +1,49 @@ +package Classes; + +public abstract class Task { + protected String description; + protected boolean isDone; + + public Task(String description) { + this.description = description; + this.isDone = false; + } + + public Task(String description, boolean isDone) { + this.description = description; + this.isDone = isDone; + } + + /** + * @return String with a cross sign if a Task is done, else no cross + */ + public String getStatusIcon() { + return (isDone ? "X" : " "); + } + + /** + * @return String with description of Task + */ + public String getDescription() { + return this.description; + } + + /** + * Marks a Task as done + */ + public void markAsDone() { + this.isDone = true; + } + + /** + * @return String contains whether the Task is done and its description + */ + public String toString() { + return "[" + getStatusIcon() + "] " + getDescription(); + } + + /** + * @return String of formatted data to be written into the text file + */ + public abstract String formatString(); +} \ No newline at end of file diff --git a/src/main/java/Classes/Todo.java b/src/main/java/Classes/Todo.java new file mode 100644 index 000000000..670c92457 --- /dev/null +++ b/src/main/java/Classes/Todo.java @@ -0,0 +1,24 @@ +package Classes; + +public class Todo extends Task { + + public Todo(String description, boolean isDone) { + super(description, isDone); + } + + /** + * @return String containing description of Todo task + */ + @Override + public String toString() { + return "[T]" + super.toString(); + } + + /** + * @return String of formatted data to be written into the text file + */ + public String formatString() { + int done = (isDone ? 1 : 0); + return "T-" + done + "-" + description + "\n"; + } +} diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 5d313334c..fc77a2dac 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,4 +1,19 @@ +import Classes.Deadline; +import Classes.Event; +import Classes.Task; +import Classes.Todo; + +import java.util.ArrayList; +import java.util.Scanner; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; + public class Duke { + public static final ArrayList tasks = new ArrayList<>(); + public static void main(String[] args) { String logo = " ____ _ \n" + "| _ \\ _ _| | _____ \n" @@ -6,5 +21,319 @@ public static void main(String[] args) { + "| |_| | |_| | < __/\n" + "|____/ \\__,_|_|\\_\\___|\n"; System.out.println("Hello from\n" + logo); + + Scanner sc = new Scanner(System.in); + + try { + loadFile(); + System.out.println("Save file loaded!"); + } catch (Exception e) { + System.out.println("No save files found."); + } + + System.out.println("\t------------------------------------------"); + System.out.println("\tHello there! I'm Duke."); + System.out.println("\tWhat can I help you with?"); + System.out.println("\t__________________________________________\n"); + + String userInput; + do { + userInput = sc.nextLine(); + dukeManager(userInput, tasks); + } while (!userInput.equals("bye")); + } + + /** + * Manager to handle logic + * @param input User's Input + * @param tasks Array List of Task + */ + public static void dukeManager(String input, ArrayList tasks) { + String [] subString = input.split(" "); + String command = subString[0]; + + switch (command) { + case "bye": + exitProgram(); + try { + saveFile(); + } catch (Exception e) { + System.out.println("Failed to save file."); + } + break; + case "list": + listTasks(tasks); + break; + case "done": + markTask(input, tasks); + break; + case "delete": + deleteTask(input, tasks); + break; + case "find": + findTasks(input, tasks); + break; + default: + addTask(input, tasks); + } + } + + /** + * Parses the data written in the text file into Task objects + * @param line String of data written in the text time + */ + public static void parseData(String line) { + String[] tokens = line.split("-"); + + boolean isDone = Integer.parseInt(tokens[1]) == 1; + + switch (tokens[0]) { + case "T": + try { + Todo todo = new Todo(tokens[2], isDone); + tasks.add(todo); + } catch (NumberFormatException e) { + return; + } + break; + case "D": + try { + Deadline deadline = new Deadline(tokens[2], isDone, tokens[3]); + tasks.add(deadline); + } catch (NumberFormatException e) { + return; + } + break; + case "E": + try { + Event event = new Event(tokens[2], isDone, tokens[3]); + tasks.add(event); + } catch (NumberFormatException e) { + return; + } + break; + default: + System.out.println("Invalid data!"); + break; + } + } + + /** + * Saves the current list of Tasks and writes them into a text file + * @throws IOException Exception while trying to create a new file + */ + public static void saveFile() throws IOException { + File path = new File("tasks.txt"); + if (!path.exists()) { + if (!path.createNewFile()) { + throw new IOException(); + } + } + FileWriter fileWriter = new FileWriter(path); + for (Task task : tasks) { + fileWriter.write(task.formatString()); + } + fileWriter.close(); + } + + /** + * Loads the list of Tasks written in the text file + * @throws FileNotFoundException Exception when the text file does not exist + */ + public static void loadFile() throws FileNotFoundException { + File path = new File("tasks.txt"); + if (!path.exists()) { + throw new FileNotFoundException(); + } + Scanner sc = new Scanner(path); + try { + while (sc.hasNext()) { + String fileInput = sc.nextLine(); + parseData(fileInput); + } + } catch (Exception e) { + System.out.println("Load failed."); + tasks.clear(); + } + } + + /** + * Exits the program + */ + public static void exitProgram() { + // exits the program + System.out.println("\t------------------------------------------"); + System.out.println("\tSee you soon! Goodbye! ^.^"); + System.out.println("\t__________________________________________\n"); + } + + /** + * Displays all the tasks stored in the Array List + * @param tasks Array List of Task + */ + public static void listTasks(ArrayList tasks) { + System.out.println("\t------------------------------------------"); + if (tasks.size() == 0) { + // if list is empty + System.out.println("\tYour list is empty!"); + } + else { + // displays the list of tasks + System.out.println("\tHere are the tasks in your list: "); + int i = 1; + for (Task task : tasks) { + System.out.println("\t" + i++ + "." + task.toString()); + } + } + System.out.println("\t__________________________________________\n"); + } + + /** + * Marks the specific task as done and notifies user the task is marked done + * @param userInput User's input + * @param tasks Array List of Task + * @throws NumberFormatException Exception when an integer is not given in the command + * @throws IndexOutOfBoundsException Exception when the input integer is out of bounds in the Array List + */ + public static void markTask(String userInput, ArrayList tasks) throws NumberFormatException, + IndexOutOfBoundsException { + // check if task exists + System.out.println("\t------------------------------------------"); + try { + int taskIndex = Integer.parseInt(userInput.split(" ")[1]) - 1; + if (taskIndex > tasks.size()-1) { + System.out.println("\tTask " + ++taskIndex + " does not exist! Please try again."); + } + else { + // sets a task as done + Task task = tasks.get(taskIndex); + task.markAsDone(); + System.out.println("\tGreat job! I've marked this task as done: "); + System.out.println("\t" + task.toString()); + } + } + catch (NumberFormatException e) { + System.out.println("\tOOPS!! To mark task, you have to enter an integer following the work done " + + "in this format e.g. 'done 3'."); + } + catch (IndexOutOfBoundsException e) { + System.out.println("\tOOPS!! Invalid task input!"); + } + System.out.println("\t__________________________________________\n"); + } + + /** + * Adds a new task to the list of Task + * @param userInput User's input + * @param tasks Array List of Task + * @throws StringIndexOutOfBoundsException Exception when wrong description format is entered + */ + public static void addTask(String userInput, ArrayList tasks) throws StringIndexOutOfBoundsException { + // adds a task to the list + System.out.println("\t------------------------------------------"); + switch (userInput.split(" ")[0].toLowerCase()) { + case "todo": + // adds to-do tasks + try { + Task todo = new Todo(userInput.substring(5), false); + tasks.add(todo); + System.out.println("\tGot it. I've added this task: "); + System.out.println("\t" + todo.toString()); + System.out.println("\tNow you have " + tasks.size() + " tasks in the list."); + } + catch (StringIndexOutOfBoundsException e) { + System.out.println("\tOOPS!!! The description of a todo cannot be empty! It must be in the following" + + " format e.g. 'todo Homework"); + } + break; + case "deadline": + // adds tasks with deadline + try { + Task deadline = new Deadline(userInput.substring(9, userInput.indexOf("/by")), false, + userInput.substring(userInput.indexOf("/by")+4)); + tasks.add(deadline); + System.out.println("\tGot it. I've added this task: "); + System.out.println("\t" + deadline.toString()); + System.out.println("\tNow you have " + tasks.size() + " tasks in the list."); + } + catch (StringIndexOutOfBoundsException e) { + System.out.println("\tOOPS!!! The description of a deadline is required in the following format e.g." + + " 'deadline CS2113 Project /by Thursday 9pm'."); + } + break; + case "event": + // adds event tasks + try { + Task event = new Event(userInput.substring(6, userInput.indexOf("/at")), false, + userInput.substring(userInput.indexOf("/at")+4)); + tasks.add(event); + System.out.println("\tGot it. I've added this task: "); + System.out.println("\t" + event.toString()); + System.out.println("\tNow you have " + tasks.size() + " tasks in the list."); + } + catch (StringIndexOutOfBoundsException e) { + System.out.println("\tOOPS!!! The description of an event is required in the following format e.g." + + " 'event CS2113 Meeting /at Monday 1pm'."); + } + break; + default: + // invalid command + System.out.println("\tOOPS! I'm sorry, but I don't know what that means! :-("); + } + System.out.println("\t__________________________________________\n"); + } + + /** + * Deletes a task from the list of Task + * @param userInput User's input + * @param tasks Array List of Task + * @throws StringIndexOutOfBoundsException Exception when wrong description format is entered + */ + public static void deleteTask(String userInput, ArrayList tasks) throws StringIndexOutOfBoundsException { + System.out.println("\t------------------------------------------"); + try { + int taskIndex = Integer.parseInt(userInput.split(" ")[1]) - 1; + if (taskIndex > tasks.size()-1) { + System.out.println("\tTask " + ++taskIndex + " does not exist! Please try again."); + } + else { + // sets a task as done + Task task = tasks.get(taskIndex); + System.out.println("\tNoted, I've removed this task: "); + System.out.println("\t" + task.toString()); + tasks.remove(task); + System.out.println("\tNow you have " + tasks.size() + " tasks in the list."); + } + } + catch (NumberFormatException e) { + System.out.println("\tOOPS!! To delete task, you have to enter an integer following the work delete " + + "in this format e.g. 'delete 3'."); + } + catch (IndexOutOfBoundsException e) { + System.out.println("\tOOPS!! Invalid task input!"); + } + System.out.println("\t__________________________________________\n"); + } + + /** + * Search for a specific task via user's input + * @param userInput User's input + * @param tasks Array List of Task + */ + public static void findTasks(String userInput, ArrayList tasks) { + System.out.println("\t------------------------------------------"); + System.out.println("\tHere are the matching tasks in your list:"); + String taskInput = userInput.split(" ")[1]; + ArrayList matchedTasks = new ArrayList<>(); + for (Task task : tasks) { + if (task.getDescription().contains(taskInput)) { + matchedTasks.add(task); + } + } + int i = 1; + for (Task task : matchedTasks) { + System.out.println("\t"+ i++ + ". " + task.toString()); + } + System.out.println("\t_________________________________________\n"); } } diff --git a/tasks.txt b/tasks.txt new file mode 100644 index 000000000..a3d7a19ed --- /dev/null +++ b/tasks.txt @@ -0,0 +1,3 @@ +T-1-do homework +D-0-upload videos -Sunday 3pm +E-1-project meeting -May 22nd diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 657e74f6e..95cfa3805 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -5,3 +5,46 @@ Hello from | |_| | |_| | < __/ |____/ \__,_|_|\_\___| + ------------------------------------------ + Hello there! I'm Duke. + What can I help you with? + __________________________________________ + + ------------------------------------------ + Got it. I've added this task: + [T][ ] read book + Now you have 1 tasks in the list. + __________________________________________ + + ------------------------------------------ + Here are the tasks in your list: + 1.[T][ ] read book + __________________________________________ + + ------------------------------------------ + Got it. I've added this task: + [D][ ] finish homeowork (by: Saturday) + Now you have 2 tasks in the list. + __________________________________________ + + ------------------------------------------ + Great job! I've marked this task as done: + [T][X] read book + __________________________________________ + + ------------------------------------------ + Got it. I've added this task: + [E][ ] dance (at: Thurday 6-8pm) + Now you have 3 tasks in the list. + __________________________________________ + + ------------------------------------------ + Here are the tasks in your list: + 1.[T][X] read book + 2.[D][ ] finish homeowork (by: Saturday) + 3.[E][ ] dance (at: Thurday 6-8pm) + __________________________________________ + + ------------------------------------------ + See you soon! Goodbye! ^.^ + __________________________________________ diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index e69de29bb..8dcc526e9 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -0,0 +1,7 @@ +todo read book +list +deadline finish homeowork /by Saturday +done 1 +event dance /at Thursday 6-8pm +list +bye \ No newline at end of file