diff --git a/README.md b/README.md index 8715d4d91..a62e419ac 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,175 @@ -# 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. - -## Setting up in Intellij - -Prerequisites: JDK 11, update Intellij to the most recent version. - -1. Open Intellij (if you are not in the welcome screen, click `File` > `Close Project` to close the existing project first) -1. Open the project into Intellij as follows: - 1. Click `Open`. - 1. Select the project directory, and click `OK`. - 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).
- 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: - ``` - Hello from - ____ _ - | _ \ _ _| | _____ - | | | | | | | |/ / _ \ - | |_| | |_| | < __/ - |____/ \__,_|_|\_\___| - ``` +# SAGE iP project + +# User Guide For Sage Task Manager +───────────────────────────────────────────────────────────── +─██████████████─██████████████─██████████████─██████████████─ +─██░░░░░░░░░░██─██░░░░░░░░░░██─██░░░░░░░░░░██─██░░░░░░░░░░██─ +─██░░██████████─██░░██████░░██─██░░██████████─██░░██████████─ +─██░░██─────────██░░██──██░░██─██░░██─────────██░░██───────── +─██░░██████████─██░░██████░░██─██░░██─────────██░░██████████─ +─██░░░░░░░░░░██─██░░░░░░░░░░██─██░░██──██████─██░░░░░░░░░░██─ +─██████████░░██─██░░██████░░██─██░░██──██░░██─██░░██████████─ +─────────██░░██─██░░██──██░░██─██░░██──██░░██─██░░██───────── +─██████████░░██─██░░██──██░░██─██░░██████░░██─██░░██████████─ +─██░░░░░░░░░░██─██░░██──██░░██─██░░░░░░░░░░██─██░░░░░░░░░░██─ +─██████████████─██████──██████─██████████████─██████████████─ +───────────────────────────────────────────────────────────── + +## Features + +### Add Task (Todo, Event or Deadline) + +This feature allows the user to add a task to the task list. The user can add a task to the application. + +### Delete A Task + +To delete a task from the application + +### List All Tasks + +To list all tasks in the application + +### Find A Task + +To find tasks with a matching query in the task description. + +### Mark/Unmark Task + +You can mark/unmark a task as done/not done in the application. + +### Data Persistence Support + +Your previous session data will be automatically stored (in ./data/sage.txt) and restored (If applicable) + +## Usage + +### `Todo` - Add a Todo Task + +Adds a Todo task to the task list. + +Example of usage: + +`todo buy groceries` + +Expected outcome: + +``` +Got it. I've added this task: +[T][ ] buy groceries +Now you have X tasks in the list. +``` + +### `deadline` - Add a Deadline Task + +Adds a Deadline task to the task list. + +Example of usage: + +`deadline submit report /by 2022-03-31` + +Expected outcome: + +``` +Got it. I've added this task: +[D][ ] submit report (by: 31 Mar 2022) +Now you have X tasks in the list. +``` + +### `event` - Add an Event Task + +Adds an Event task to the task list. + +Example of usage: + +`event project meeting /from 2022-04-01 /to 2022-04-02` + +Expected outcome: + +``` +Got it. I've added this task: +[E][ ] project meeting (from: 2022-04-01 to: 2022-04-02) +Now you have X tasks in the list. +``` + +### `delete` - Delete a Task + +Deletes the specified task from the task list. + +Example of usage: + +`delete 2` + +Expected outcome: + +``` +Noted. I've removed this task: +[D][ ] submit report (by: 31 Mar 2022) +Now you have X tasks in the list. +``` + +### `find` - Find Tasks + +Displays a list of tasks that match the specified keyword. + +Example of usage: + +`find meeting` + +Expected outcome: + +``` +Found 1 matching queries! +1.[E][ ] project meeting (from: 2022-04-01 to: 2022-04-02) +``` + +### `list` - List All Tasks + +Displays a list of all tasks in the task list. + +Example of usage: + +`list` + +Expected outcome: + +``` +Here are the tasks in your list: +1.[T][ ] buy groceries +2.[E][ ] project meeting (from: 2022-04-01 to: 2022-04-02) +``` + +### `mark` - Mark a Task as Done + +Marks the specified task as done. + +Example of usage: + +`mark 1` + +Expected outcome: + +``` +Nice! I've marked this task as done: +[T][X] buy groceries +``` + +### `unmark` - Unmark a Task as Undone + +Marks the specified task as undone. + +Example of usage: + +`unmark 1` + +Expected outcome: + +``` +Noted. I've marked this task as undone: +[T][ ] buy groceries +``` + +## Other Commands + +### `bye` - Quit the application + +Exit the application diff --git a/data/sage.txt b/data/sage.txt new file mode 100644 index 000000000..fee1a737f --- /dev/null +++ b/data/sage.txt @@ -0,0 +1,4 @@ +[T][ ] read book +[D][ ] return book (by: June 6th) +[T][ ] aasdadsada +[D][X] ajsdkaakd,as (by: wkjsdas) diff --git a/docs/README.md b/docs/README.md index 8077118eb..7281790d7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,29 +1,160 @@ -# User Guide +# User Guide For Sage Task Manager -## Features +## Features -### Feature-ABC +### Add Task (Todo, Event or Deadline) -Description of the feature. +This feature allows the user to add a task to the task list. The user can add a task to the application. -### Feature-XYZ +### Delete A Task -Description of the feature. +To delete a task from the application + +### List All Tasks + +To list all tasks in the application + +### Find A Task + +To find tasks with a matching query in the task description. + +### Mark/Unmark Task + +You can mark/unmark a task as done/not done in the application. + +### Data Persistence Support + +Your previous session data will be automatically stored (in ./data/sage.txt) and restored (If applicable) ## Usage -### `Keyword` - Describe action +### `Todo` - Add a Todo Task -Describe the action and its outcome. +Adds a Todo task to the task list. -Example of usage: +Example of usage: -`keyword (optional arguments)` +`todo buy groceries` Expected outcome: -Description of the outcome. +``` +Got it. I've added this task: +[T][ ] buy groceries +Now you have X tasks in the list. +``` + +### `deadline` - Add a Deadline Task + +Adds a Deadline task to the task list. + +Example of usage: + +`deadline submit report /by 2022-03-31` + +Expected outcome: ``` -expected output +Got it. I've added this task: +[D][ ] submit report (by: 31 Mar 2022) +Now you have X tasks in the list. ``` + +### `event` - Add an Event Task + +Adds an Event task to the task list. + +Example of usage: + +`event project meeting /from 2022-04-01 /to 2022-04-02` + +Expected outcome: + +``` +Got it. I've added this task: +[E][ ] project meeting (from: 2022-04-01 to: 2022-04-02) +Now you have X tasks in the list. +``` + +### `delete` - Delete a Task + +Deletes the specified task from the task list. + +Example of usage: + +`delete 2` + +Expected outcome: + +``` +Noted. I've removed this task: +[D][ ] submit report (by: 31 Mar 2022) +Now you have X tasks in the list. +``` + +### `find` - Find Tasks + +Displays a list of tasks that match the specified keyword. + +Example of usage: + +`find meeting` + +Expected outcome: + +``` +Found 1 matching queries! +1.[E][ ] project meeting (from: 2022-04-01 to: 2022-04-02) +``` + +### `list` - List All Tasks + +Displays a list of all tasks in the task list. + +Example of usage: + +`list` + +Expected outcome: + +``` +Here are the tasks in your list: +1.[T][ ] buy groceries +2.[E][ ] project meeting (from: 2022-04-01 to: 2022-04-02) +``` + +### `mark` - Mark a Task as Done + +Marks the specified task as done. + +Example of usage: + +`mark 1` + +Expected outcome: + +``` +Nice! I've marked this task as done: +[T][X] buy groceries +``` + +### `unmark` - Unmark a Task as Undone + +Marks the specified task as undone. + +Example of usage: + +`unmark 1` + +Expected outcome: + +``` +Noted. I've marked this task as undone: +[T][ ] buy groceries +``` + +## Other Commands + +### `bye` - Quit the application + +Exit the application diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java deleted file mode 100644 index 5d313334c..000000000 --- a/src/main/java/Duke.java +++ /dev/null @@ -1,10 +0,0 @@ -public class Duke { - public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); - } -} diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 000000000..62b526a76 --- /dev/null +++ b/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: sage.main.Sage + diff --git a/src/main/java/sage/enums/TaskType.java b/src/main/java/sage/enums/TaskType.java new file mode 100644 index 000000000..ed74470a8 --- /dev/null +++ b/src/main/java/sage/enums/TaskType.java @@ -0,0 +1,7 @@ +package sage.enums; + +public enum TaskType { + DEADLINE, + TODO, + EVENT +} diff --git a/src/main/java/sage/exceptions/EmptyListException.java b/src/main/java/sage/exceptions/EmptyListException.java new file mode 100644 index 000000000..8a2603160 --- /dev/null +++ b/src/main/java/sage/exceptions/EmptyListException.java @@ -0,0 +1,11 @@ +package sage.exceptions; + +/** + * Exception which returns an error message when operations is conducted on an empty list. + */ +public class EmptyListException extends Exception { + + public void errorMsg() { + System.out.println("There are currently no tasks in your list!"); + } +} diff --git a/src/main/java/sage/exceptions/IllegalOperationException.java b/src/main/java/sage/exceptions/IllegalOperationException.java new file mode 100644 index 000000000..eb5b02c79 --- /dev/null +++ b/src/main/java/sage/exceptions/IllegalOperationException.java @@ -0,0 +1,15 @@ +package sage.exceptions; + +/** + * Exception which returns an error message when operations is conducted on an empty list. + */ +public class IllegalOperationException extends Exception { + + public void errorAlreadyUnmarked() { + System.out.println("Task already marked as not completed!"); + } + + public void errorAlreadyMarked() { + System.out.println("Task already marked as completed!"); + } +} diff --git a/src/main/java/sage/exceptions/MissingParameterException.java b/src/main/java/sage/exceptions/MissingParameterException.java new file mode 100644 index 000000000..b18c32709 --- /dev/null +++ b/src/main/java/sage/exceptions/MissingParameterException.java @@ -0,0 +1,32 @@ +package sage.exceptions; + +/** + * Exception which returns an error message when there are missing parameter(s) in task operations. + */ +public class MissingParameterException extends Exception { + + public void missingParamDesc() { + System.out.println("Task \"description\" parameter is missing"); + } + + public void missingParamStart() { + System.out.println("Task \"from\" parameter is missing"); + } + + public void missingParamEnd() { + System.out.println("Task \"to\" parameter is missing"); + + } + + public void missingParamBy() { + System.out.println("Task \"by\" parameter is missing"); + } + + public void missingParamTaskIndex() { + System.out.println("\"index\" parameter is missing"); + } + + public void missingParamKeyword() { + System.out.println("\"Keywords\" parameter is missing"); + } +} diff --git a/src/main/java/sage/exceptions/OutOfBoundException.java b/src/main/java/sage/exceptions/OutOfBoundException.java new file mode 100644 index 000000000..ab41e14e0 --- /dev/null +++ b/src/main/java/sage/exceptions/OutOfBoundException.java @@ -0,0 +1,20 @@ +package sage.exceptions; + +/** + * Exception which returns an error message when an out-of-bound task index is provided by the user + */ +public class OutOfBoundException extends Exception { + + public void errorMark() { + System.out.println("Unable to mark the specified task: task index provided is invalid."); + } + + public void errorUnmark() { + System.out.println("Unable to unmark the specified task: task index provided is invalid."); + } + + public void errorDelete() { + System.out.println("Unable to delete the specified task: task index provided is invalid."); + } + +} diff --git a/src/main/java/sage/main/Sage.java b/src/main/java/sage/main/Sage.java new file mode 100644 index 000000000..ef7d6b95e --- /dev/null +++ b/src/main/java/sage/main/Sage.java @@ -0,0 +1,21 @@ +package sage.main; + +import sage.utility.Display; +import sage.utility.Parser; +import sage.utility.Ui; + + +public class Sage { + public static void main(String[] args) { + Display display = new Display(); + Ui ui = new Ui(); + ui.recoverData(); + boolean isExit = false; + display.printWelcomeUser(); + while (!isExit) { + String input = ui.readInput(); + Parser parsed = new Parser(input); + isExit = ui.readCommand(parsed); + } + } +} diff --git a/src/main/java/sage/tasktypes/Deadline.java b/src/main/java/sage/tasktypes/Deadline.java new file mode 100644 index 000000000..a94788057 --- /dev/null +++ b/src/main/java/sage/tasktypes/Deadline.java @@ -0,0 +1,57 @@ +package sage.tasktypes; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; + + +/** + * An inherited class from Task that represents Deadline which also stores the expected completion date of a task + */ + +public class Deadline extends Task { + private String byWhen = ""; + + private LocalDate date = null; + + public Deadline(String taskName, String byWhen) { + super(taskName); + DateTimeFormatter dateformat1 = DateTimeFormatter.ofPattern("dd-MM-uuuu"); + DateTimeFormatter dateformat2 = DateTimeFormatter.ofPattern("uuuu-MM-dd"); + try { + this.date = LocalDate.parse(byWhen, dateformat1); + } catch (DateTimeParseException e1) { + try { + this.date = LocalDate.parse(byWhen, dateformat2); + } catch (DateTimeParseException e2) { + this.byWhen = byWhen; + } + } + } + + public String getByWhen() { + return byWhen; + } + + public String getFormattedTime() { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MMM yyyy"); + return this.date.format(formatter); + } + + @Override + public String toString() { + if (this.date != null) { + if (super.isCompleted()) { + return "[D][X] " + super.getTaskDetails() + "(by: " + getFormattedTime() + ")"; + } else { + return "[D][ ] " + super.getTaskDetails() + "(by: " + getFormattedTime() + ")"; + } + } else { + if (super.isCompleted()) { + return "[D][X] " + super.getTaskDetails() + "(by: " + getByWhen() + ")"; + } else { + return "[D][ ] " + super.getTaskDetails() + "(by: " + getByWhen() + ")"; + } + } + } +} diff --git a/src/main/java/sage/tasktypes/Event.java b/src/main/java/sage/tasktypes/Event.java new file mode 100644 index 000000000..b30dc4f61 --- /dev/null +++ b/src/main/java/sage/tasktypes/Event.java @@ -0,0 +1,34 @@ +package sage.tasktypes; + +/** + * An inherited class from Task that represents Event which also stores the expected starting and ending time of a task + */ + +public class Event extends Task { + + private String startWhen = ""; + private String endWhen = ""; + + public Event(String taskName, String startWhen, String endWhen) { + super(taskName); + this.startWhen = startWhen; + this.endWhen = endWhen; + } + + public String getStartWhen() { + return startWhen; + } + + public String getEndWhen() { + return endWhen; + } + + @Override + public String toString() { + if (super.isCompleted()) { + return "[E][X] " + super.getTaskDetails() + "(from: " + getStartWhen() + " to: " + getEndWhen() + ")"; + } else { + return "[E][ ] " + super.getTaskDetails() + "(from: " + getStartWhen() + " to: " + getEndWhen() + ")"; + } + } +} diff --git a/src/main/java/sage/tasktypes/Task.java b/src/main/java/sage/tasktypes/Task.java new file mode 100644 index 000000000..95d9a168f --- /dev/null +++ b/src/main/java/sage/tasktypes/Task.java @@ -0,0 +1,40 @@ +package sage.tasktypes; + + +/** + * A parent class that represents a task's description and completion status. + */ +public class Task { + private String taskDetails = ""; + private boolean isCompleted = false; + + public Task(String taskDetails) { + this.taskDetails = taskDetails; + this.isCompleted = false; + } + + public String getTaskDetails() { + return this.taskDetails; + } + + public void setCompleted(boolean completed) { + this.isCompleted = completed; + } + + public boolean isCompleted() { + return isCompleted; + } + + public char printStatusSymbol() { + if (isCompleted) { + return 'X'; + } + return ' '; + } + + public String toString() { + return ""; + } + + ; +} diff --git a/src/main/java/sage/tasktypes/Todo.java b/src/main/java/sage/tasktypes/Todo.java new file mode 100644 index 000000000..8cd10a385 --- /dev/null +++ b/src/main/java/sage/tasktypes/Todo.java @@ -0,0 +1,21 @@ +package sage.tasktypes; + +/** + * An inherited class from Task that represents Todo. + */ +public class Todo extends Task { + + public Todo(String taskName) { + super(taskName); + } + + @Override + public String toString() { + if (super.isCompleted()) { + return "[T][X] " + super.getTaskDetails(); + } else { + return "[T][ ] " + super.getTaskDetails(); + } + } + +} diff --git a/src/main/java/sage/utility/Display.java b/src/main/java/sage/utility/Display.java new file mode 100644 index 000000000..5ad377d99 --- /dev/null +++ b/src/main/java/sage/utility/Display.java @@ -0,0 +1,105 @@ +package sage.utility; + +import java.util.ArrayList; + +import sage.tasktypes.Task; + +/** + * A class containing methods for printing text on the console. + */ + +public class Display { + private static final String LINE = + "█████╗█████╗█████╗█████╗█████╗█████╗█████╗\n" + + "╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝"; + private static final String LOGO = "░██████╗░█████╗░░██████╗░███████╗\n" + + "██╔════╝██╔══██╗██╔════╝░██╔════╝\n" + + "╚█████╗░███████║██║░░██╗░█████╗░░\n" + + "░╚═══██╗██╔══██║██║░░╚██╗██╔══╝░░\n" + + "██████╔╝██║░░██║╚██████╔╝███████╗\n" + + "╚═════╝░╚═╝░░╚═╝░╚═════╝░╚══════╝"; + + public String printLine() { + return LINE; + } + + public void printWelcomeUser() { + String welcome = "Hello! I'm SAGE, the knowledgeable one\n" + + "What can I do for you today?\n"; + System.out.println(LOGO); + System.out.println(welcome); + } + + public void printGoodByeUser() { + System.out.println("Bye. Hope to see you again soon!"); + } + + public void printResumeSession() { + System.out.println("Info: Data from previous session is resumed"); + } + + /** + * This method prints a message to the console indicating the addition of a TODO task to the task list and its details. + * + * @param taskObj A task object (TODO/DEADLINE/EVENT) + * @param taskCount The number of tasks in list. + */ + public void printAddedTask(Task taskObj, int taskCount) { + System.out.println(LINE); + System.out.println("Got it. I've added this task:"); + System.out.println(taskObj); + System.out.println("Now you have " + taskCount + " tasks in the list"); + System.out.println(LINE); + } + + public void printUnknownInput() { + System.out.println("I don't understand what you mean, please try again!"); + } + + + /** + * This method is used to display a marked/unmark task as not done/done in the task list. + * + * @param list the list of tasks + * @param taskNumber the taskNumber index that is to be unmarked + * @param isToMark whether operation executed is to mark a task + */ + public void printMarking(ArrayList list, int taskNumber, boolean isToMark) { + Task taskObj = list.get(taskNumber - 1); + if (isToMark) { + System.out.println("Nice! I've marked this task as done:"); + } else { + System.out.println("OK, I've marked this task as not done yet:"); + } + System.out.println(taskObj); + } + + /** + * This method is used to display delete operation in the task list. + * + * @param list the list of tasks + * @param taskNumber the taskNumber index of the task that is to be deleted + */ + public void printDeletedTask(ArrayList list, int taskNumber) { + Task taskObj = list.get(taskNumber - 1); + System.out.println("Noted. I've removed this task:"); + System.out.println(taskObj); + System.out.println("Now you have " + (list.size() - 1) + " tasks in the list."); + } + + public void printSearchTask(ArrayList results) { + System.out.println(LINE); + if (results.isEmpty()) { + System.out.println("Found no matching query. Please try another again!"); + } else { + System.out.println("Found " + results.size() + " matching queries!"); + for (int i = 0; i < results.size(); i++) { + System.out.print(i + 1 + "."); + System.out.println(results.get(i)); + } + + } + System.out.println(LINE); + } + +} diff --git a/src/main/java/sage/utility/Parser.java b/src/main/java/sage/utility/Parser.java new file mode 100644 index 000000000..eda400645 --- /dev/null +++ b/src/main/java/sage/utility/Parser.java @@ -0,0 +1,69 @@ +package sage.utility; + + +/** + * A class containing methods for parsing of raw user input for easier reading + */ +public class Parser { + private String[] rawOutput; + private String taskType; + private String taskDescription; + private String by = null; + private String from = null; + private String to = null; + + private static final Integer MAXSPLIT = 2; + private static final Integer TASKTYPEINDEX = 0; + private static final Integer TASKDESCRIPTIONINDEX = 1; + + /** + * Parses user input into its respective task type, description and other attributes + * + * @param input raw user input to be parsed + */ + public Parser(String input) { + this.rawOutput = input.split("/"); + String[] body = rawOutput[TASKTYPEINDEX].split(" ", MAXSPLIT); + this.taskType = body[TASKTYPEINDEX].toLowerCase(); + if (body.length > 1) { + this.taskDescription = body[TASKDESCRIPTIONINDEX]; + } + + for (String i : rawOutput) { + String[] line = i.split(" ", MAXSPLIT); + String field = line.length > 1 ? line[TASKDESCRIPTIONINDEX].trim() : null; + switch (line[TASKTYPEINDEX]) { + case "by": + this.by = field; + break; + case "from": + this.from = field; + break; + case "to": + this.to = field; + break; + } + } + + } + + public String getTaskType() { + return taskType; + } + + public String getTaskDescription() { + return taskDescription; + } + + public String getBy() { + return by; + } + + public String getFrom() { + return from; + } + + public String getTo() { + return to; + } +} diff --git a/src/main/java/sage/utility/Storage.java b/src/main/java/sage/utility/Storage.java new file mode 100644 index 000000000..0229bf078 --- /dev/null +++ b/src/main/java/sage/utility/Storage.java @@ -0,0 +1,106 @@ +package sage.utility; + +import sage.tasktypes.Task; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Scanner; + + +/** + * A class that contains storage and file related I/O methods + */ +public class Storage { + + private static final String PROJECT_FILE_DIR = "./data/sage.txt"; + private static final Integer TASKTYPEINDEX = 1; + private static final Integer TASKCOMPLETIONINDEX = 4; + private static final Integer TASKFROMLENGTH = 6; + private static final Integer TASKTOLENGTH = 4; + + private static final Integer TASKBYLENGTH = 2; + + private static final Integer TASKDESCENTRYINDEX = 7; + + /** + * Recovers and parse any stored data in ./data/sage.txt to taskList + * + * @param taskList contains information and methods about all the tasks currently in the list + */ + public void recoverData(TaskList taskList) { + File f = new File(PROJECT_FILE_DIR); + if (f.exists()) { + Display UI = new Display(); + UI.printResumeSession(); + try { + Scanner scanner = new Scanner(f); + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + writeToApp(line, taskList); + } + scanner.close(); + } catch (FileNotFoundException e) { + System.out.println("An error occurred when trying to read/access the data file"); + } + } + } + + /** + * Writes a given line recovered from previous session data to the application + * + * @param line contains information about a recovered task from the previous session + * @param taskList contains information and methods about all the tasks currently in the list + */ + public void writeToApp(String line, TaskList taskList) { + char taskType = line.charAt(TASKTYPEINDEX); + String taskDescription = ""; + boolean isCompleted = false; + char s = line.charAt(TASKCOMPLETIONINDEX); + + if (s == 'X') { + isCompleted = true; + } + if (taskType == 'T') { + taskDescription = line.substring(TASKDESCENTRYINDEX); + taskList.addTask(taskDescription, isCompleted, true); + } else { + String taskPeriod = line.substring(line.indexOf('(') + 1, line.indexOf(')')); + taskDescription = line.substring(7, line.indexOf('(') - 1) + " "; + if (taskType == 'D') { + String taskBy = taskPeriod.substring(taskPeriod.indexOf(':') + TASKBYLENGTH); + taskList.addTask(taskDescription, taskBy, isCompleted, true); + } else { + String taskFrom = taskPeriod.substring(taskPeriod.indexOf("from: ") + TASKFROMLENGTH, + taskPeriod.indexOf("to: ") - 1); + String taskTo = taskPeriod.substring(taskPeriod.indexOf("to: ") + TASKTOLENGTH); + taskList.addTask(taskDescription, taskFrom, taskTo, isCompleted, true); + } + } + } + + /** + * Updates the data file in ./data/sage.txt with the latest list of tasks + * + * @param list list of tasks information in the application + */ + + public void updateFile(ArrayList list) { + File f = new File(PROJECT_FILE_DIR); + try { + f.getParentFile().mkdirs(); + if (!f.exists()) { + f.createNewFile(); + } + FileWriter fw = new FileWriter(PROJECT_FILE_DIR); + for (Task taskobj : list) { + fw.write(taskobj + " \r\n"); + } + fw.close(); + } catch (IOException e) { + System.out.println("Info: Error Updating Changes to Data File, Please refresh App!"); + } + } +} diff --git a/src/main/java/sage/utility/TaskList.java b/src/main/java/sage/utility/TaskList.java new file mode 100644 index 000000000..91bc13494 --- /dev/null +++ b/src/main/java/sage/utility/TaskList.java @@ -0,0 +1,214 @@ +package sage.utility; + +import java.util.ArrayList; + +import sage.exceptions.IllegalOperationException; +import sage.exceptions.MissingParameterException; +import sage.exceptions.EmptyListException; +import sage.exceptions.OutOfBoundException; +import sage.tasktypes.Deadline; +import sage.tasktypes.Event; +import sage.tasktypes.Task; +import sage.tasktypes.Todo; + +/** + * A class that stores the list of tasks in the application and access methods for all task operations + */ + +public class TaskList { + private static ArrayList list = new ArrayList<>(); + + private static final Display display = new Display(); + private static final Storage fm = new Storage(); + + /** + * Display a list of tasks with its description matching the search query (keywords) provided by the user. + * + * @param keywords the search term input provided by the user + */ + public void findTask(String keywords) { + ArrayList results = new ArrayList(); + try { + if (keywords == null) { + throw new MissingParameterException(); + } + for (Task t : list) { + if (t.getTaskDetails().contains(keywords)) { + results.add(t); + } + } + display.printSearchTask(results); + } catch (MissingParameterException e) { + e.missingParamKeyword(); + } + } + + /** + * This method instantiate a Todo object and add the Todo object to the TaskList + * + * @param taskName The name of the TODO task to be added + **/ + public void addTask(String taskName, boolean isCompleted, boolean isSilentMode) { + try { + if (taskName == null) { + throw new MissingParameterException(); + } else { + Todo t = new Todo(taskName); + list.add(t); + t.setCompleted(isCompleted); + if (!isSilentMode) { + display.printAddedTask(t, list.size()); + fm.updateFile(list); + } + } + } catch (MissingParameterException e) { + e.missingParamDesc(); + } + } + + /** + * This method instantiate a Deadline object and add the Deadline object to the TaskList + * + * @param taskName a string that represents the name of the Deadline task to add. + * @param byWhen a string that represents the deadline of the Deadline task. + **/ + public void addTask(String taskName, String byWhen, boolean isCompleted, boolean isSilentMode) { + try { + if (taskName == null || byWhen == null) { + throw new MissingParameterException(); + } else { + Deadline d = new Deadline(taskName, byWhen); + list.add(d); + d.setCompleted(isCompleted); + if (!isSilentMode) { + fm.updateFile(list); + display.printAddedTask(d, list.size()); + } + } + } catch (MissingParameterException e) { + if (taskName == null) { + e.missingParamDesc(); + } else { + e.missingParamBy(); + } + } + } + + /** + * This method instantiate an Event object and add the Event object to the TaskList + * + * @param taskName a string that represents the name of the Event task to add. + * @param startWhen a string that represents the start date and time of the Event task. + * @param endWhen a string that represents the end date and time of the Event task. + */ + public void addTask(String taskName, String startWhen, String endWhen, boolean isCompleted, boolean isSilentMode) { + try { + if (taskName == null || startWhen == null || endWhen == null) { + throw new MissingParameterException(); + } else { + Event e = new Event(taskName, startWhen, endWhen); + list.add(e); + e.setCompleted(isCompleted); + if (!isSilentMode) { + fm.updateFile(list); + display.printAddedTask(e, list.size()); + } + } + } catch (MissingParameterException e) { + if (taskName == null) { + e.missingParamDesc(); + } else if (startWhen == null) { + e.missingParamStart(); + } else { + e.missingParamEnd(); + } + } + } + + /** + * Deletes a task. + * + * @param taskIndex string that represents the index of the task to unmark (1-Indexed). + */ + public void deleteTask(String taskIndex) { + try { + if (taskIndex == null) { + throw new MissingParameterException(); + } + int taskNumber = Integer.parseInt(taskIndex); + if (taskNumber <= 0 || taskNumber > list.size()) { + throw new OutOfBoundException(); + } else { + display.printDeletedTask(list, taskNumber); + list.remove(taskNumber - 1); + fm.updateFile(list); + } + } catch (OutOfBoundException e) { + e.errorDelete(); + } catch (MissingParameterException e) { + e.missingParamTaskIndex(); + } + } + + /** + * Unmarks a completed task. + * + * @param taskIndex string that represents the index of the task to unmark (1-Indexed). + */ + public void markingTask(String taskIndex, Boolean isMark) { + + try { + if (taskIndex == null) { + throw new MissingParameterException(); + } + int taskNumber = Integer.parseInt(taskIndex); + if (taskNumber <= 0 || taskNumber > list.size()) { + throw new OutOfBoundException(); + } else if ((!isMark && !list.get(taskNumber - 1).isCompleted()) || + (isMark && list.get(taskNumber - 1).isCompleted())) { + throw new IllegalOperationException(); + } else { + list.get(taskNumber - 1).setCompleted(isMark); + fm.updateFile(list); + display.printMarking(list, taskNumber, isMark); + } + } catch (OutOfBoundException e) { + e.errorUnmark(); + } catch (IllegalOperationException e) { + if (isMark) { + e.errorAlreadyMarked(); + } else { + e.errorAlreadyUnmarked(); + } + } catch (MissingParameterException e) { + e.missingParamTaskIndex(); + } + + } + + /** + * Display a list of tasks currently stored in the list + */ + public void listTask() { + System.out.println(display.printLine()); + try { + if (list.size() > 0) { + System.out.println("Here are the tasks in your list:"); + for (int i = 0; i < list.size(); i++) { + System.out.print(i + 1 + "."); + System.out.println(list.get(i).toString()); + } + } else { + throw new EmptyListException(); + } + } catch (EmptyListException e) { + e.errorMsg(); + } + System.out.println(display.printLine()); + } + + public int getTaskCount() { + return list.size(); + } +} + diff --git a/src/main/java/sage/utility/Ui.java b/src/main/java/sage/utility/Ui.java new file mode 100644 index 000000000..76d128aa2 --- /dev/null +++ b/src/main/java/sage/utility/Ui.java @@ -0,0 +1,71 @@ +package sage.utility; + +import java.util.Scanner; + +/** + * A class that represents user interaction methods such as the execution of user input and recovering previous session. + */ + +public class Ui { + + private static Display display = new Display(); + private static TaskList taskList = new TaskList(); + + private static Storage fm = new Storage(); + + + /** + * Retrieves and restore any available task information data stored in ./data/sage.txt + */ + public void recoverData() { + fm.recoverData(taskList); + } + + public String readInput() { + Scanner input = new Scanner(System.in); + return input.nextLine(); + } + + /** + * Reads the parsed user input and delegate the respective operation based on the task type + * + * @param parsed a Parser object that contains parsed user input + * @return boolean that indicates whether to exit the application + */ + public boolean readCommand(Parser parsed) { + switch (parsed.getTaskType()) { + case "bye": + display.printGoodByeUser(); + return true; + case "list": + taskList.listTask(); + break; + case "unmark": + taskList.markingTask(parsed.getTaskDescription(), false); + break; + case "mark": + taskList.markingTask(parsed.getTaskDescription(), true); + break; + case "delete": + taskList.deleteTask(parsed.getTaskDescription()); + break; + case "todo": + taskList.addTask(parsed.getTaskDescription(), false, false); + break; + case "deadline": + taskList.addTask(parsed.getTaskDescription(), parsed.getBy(), false, false); + break; + case "event": + taskList.addTask(parsed.getTaskDescription(), parsed.getFrom(), parsed.getTo(), false, false); + break; + case "find": + taskList.findTask(parsed.getTaskDescription()); + break; + default: + display.printUnknownInput(); + break; + } + return false; + } + +} diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 657e74f6e..c713e4352 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,7 +1,62 @@ -Hello from - ____ _ -| _ \ _ _| | _____ -| | | | | | | |/ / _ \ -| |_| | |_| | < __/ -|____/ \__,_|_|\_\___| +Hello! I'm SAGE, the knowledgeable one +What can I do for you today? +Got it. I've added this task: +[T][ ] return books +Now you have 1 tasks in the list +Got it. I've added this task: +[T][ ] return laundry +Now you have 2 tasks in the list +***************************** +Here are the tasks in your list: +1.[T][ ] return books +2.[T][ ] return laundry +***************************** +Got it. I've added this task: +[D][ ] assignment 1 (by: Next monday) +Now you have 3 tasks in the list +Got it. I've added this task: +[D][ ] lab 10 (by: Next tues) +Now you have 4 tasks in the list +***************************** +Here are the tasks in your list: +1.[T][ ] return books +2.[T][ ] return laundry +3.[D][ ] assignment 1 (by: Next monday) +4.[D][ ] lab 10 (by: Next tues) +***************************** +I don't understand what you mean, please try again! +I don't understand what you mean, please try again! +Got it. I've added this task: +[E][ ] funfair 1 (from: 21 jan to: 4 feb) +Now you have 5 tasks in the list +Got it. I've added this task: +[E][ ] fund raising (from: 30 feb to: 31 mar) +Now you have 6 tasks in the list +***************************** +Here are the tasks in your list: +1.[T][ ] return books +2.[T][ ] return laundry +3.[D][ ] assignment 1 (by: Next monday) +4.[D][ ] lab 10 (by: Next tues) +5.[E][ ] funfair 1 (from: 21 jan to: 4 feb) +6.[E][ ] fund raising (from: 30 feb to: 31 mar) +***************************** +Nice! I've marked this task as done: +[X] assignment 1 +Nice! I've marked this task as done: +[X] funfair 1 +Uh-oh! Task Not Found! +Task already marked as not completed! +OK, I've marked this task as not done yet: +[ ] assignment 1 +Task already marked as completed! +***************************** +Here are the tasks in your list: +1.[T][ ] return books +2.[T][ ] return laundry +3.[D][ ] assignment 1 (by: Next monday) +4.[D][ ] lab 10 (by: Next tues) +5.[E][X] funfair 1 (from: 21 jan to: 4 feb) +6.[E][ ] fund raising (from: 30 feb to: 31 mar) +***************************** \ No newline at end of file diff --git a/text-ui-test/input.txt b/text-ui-test/input.txt index e69de29bb..dde8dc667 100644 --- a/text-ui-test/input.txt +++ b/text-ui-test/input.txt @@ -0,0 +1,18 @@ +todo return books +todo return laundry +list +deadline assignment 1 /by Next monday +deadline lab 10 /by Next tues +list +garbage 12323 +garbage asdasda +event funfair 1 /from 21 jan /to 4 feb +event fund raising /from 30 feb /to 31 mar +list +mark 3 +mark 5 +mark 100 +unmark 2 +unmark 3 +mark 5 +list \ No newline at end of file