diff --git a/README.md b/README.md index 8715d4d91..676cb9553 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,38 @@ -# 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 - ____ _ - | _ \ _ _| | _____ - | | | | | | | |/ / _ \ - | |_| | |_| | < __/ - |____/ \__,_|_|\_\___| - ``` +# Duke +Welcome to Duke! This is a user guide for the task tracker Duke. + +## Installation +Requires: JDK 11 +1. Download the jar file for Duke under "Releases" +2. Extract it to an empty folder +3. Run the jar file +4. Enjoy! + +### Commands +Below are the list of commands that can be used with Duke +Please remember to follow the input format strictly! + +1. list || (to see the current tasks saved) +2. `todo ` || Adds a task with no particular time to take note of +3. `event /from /to ` || Adds an event with a start and end time +4. `deadline /by ` || Adds a task with a deadline +5. `mark ` || To mark a task as done +6. `unmark ` || To mark a task as not done +7. `delete ` || To remove a task from the list +8. `bye` || To terminate the programme + +## Usage + +Example of usage: + +`event study /from 2pm /tp 4pm` + +Expected outcome: +``` +Got it. I've added this task: +[E][ ] study (From: 2pm to To: 4pm) +Now you have 1 tasks in the list. +____________________________________________________________ + +What would you like to do? +``` diff --git a/docs/README.md b/docs/README.md index 8077118eb..cf14af59a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,29 +1,38 @@ -# User Guide - -## Features - -### Feature-ABC - -Description of the feature. - -### Feature-XYZ - -Description of the feature. +# Duke +Welcome to Duke! This is a user guide for the task tracker Duke. + +## Installation +Requires: JDK 11 +1. Download the jar file for Duke under "Releases" +2. Extract it to an empty folder +3. Run the jar file +4. Enjoy! + +### Commands +Below are the list of commands that can be used with Duke +Please remember to follow the input format strictly! + +1. list || (to see the current tasks saved) +2. `todo ` || Adds a task with no particular time to take note of +3. `event /from /to ` || Adds an event with a start and end time +4. `deadline /by ` || Adds a task with a deadline +5. `mark ` || To mark a task as done +6. `unmark ` || To mark a task as not done +7. `delete ` || To remove a task from the list +8. `bye` || To terminate the programme ## Usage -### `Keyword` - Describe action - -Describe the action and its outcome. - Example of usage: -`keyword (optional arguments)` +`event study /from 2pm /tp 4pm` Expected outcome: - -Description of the outcome. - ``` -expected output +Got it. I've added this task: +[E][ ] study (From: 2pm to To: 4pm) +Now you have 1 tasks in the list. +____________________________________________________________ + +What would you like to do? ``` diff --git a/duke.txt b/duke.txt new file mode 100644 index 000000000..e69de29bb diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 5d313334c..7316f9df1 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,10 +1,30 @@ +import User.Parser; +import User.Storage; +import User.TaskList; +import User.UI; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Scanner; + public class Duke { - public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); + + public static void main(String[] args) throws IOException { + try{ + TaskList.taskList = Storage.readFile("duke.txt"); + } catch (FileNotFoundException e) { + System.out.println("File not found, a new one will be created shortly!"); + } + UI.printLogo(); + Scanner myObj = new Scanner(System.in); + String userInput; + userInput = myObj.nextLine(); + while (!userInput.equals("bye")) { + Parser.parsing(userInput); + System.out.println("What would you like to do?"); + userInput = myObj.nextLine(); + } + Storage.clearFile(); + Storage.updateFile(TaskList.taskList); + UI.printBye(); } -} +} \ No newline at end of file diff --git a/src/main/java/META-INF/MANIFEST.MF b/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 000000000..d2ffd5b4d --- /dev/null +++ b/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Main-Class: Duke + diff --git a/src/main/java/Tasks/Deadline.java b/src/main/java/Tasks/Deadline.java new file mode 100644 index 000000000..c72448e02 --- /dev/null +++ b/src/main/java/Tasks/Deadline.java @@ -0,0 +1,46 @@ +package Tasks; + +import Tasks.Task; + +public class Deadline extends Task { + + protected String by; + protected String symbol = "[D]"; + + public String getDescription() { + return super.getDescription(); + } + + public String getSymbol() { + return symbol; + } + + /** + * Constructs a deadline-type task + * @param description the activity that needs be done by the user + * @param by the deadline by which the user needs to finish said activity + */ + public Deadline(String description, String by) { + super(description); + this.by = by; + this.description = description + "(By:" + by + ")"; + } + + /** + * Returns a string representation of the deadline-type task to be printed for the user + * @return the formatted string output + */ + @Override + public String toString() { + return "[D]" + super.getStatusIcon() + " " + super.getDescription() ; + } + + /** + * Returns a string representation of the deadline-type task to be stored in the text file + * @return the formatted string output + */ + @Override + public String toFile() { + return this.getStatusIcon() + " : " +"D"+ " : " + this.description; + } +} diff --git a/src/main/java/Tasks/Event.java b/src/main/java/Tasks/Event.java new file mode 100644 index 000000000..f1b471591 --- /dev/null +++ b/src/main/java/Tasks/Event.java @@ -0,0 +1,37 @@ +package Tasks; + +public class Event extends Task { + protected String from; + protected String to; + protected String symbol = "[E]"; + + public Event(String description, String from, String to) { + super(description); + this.from = from; + this.to = to; + this.description = description + "(From:" + this.from + "To:" + this.to + ")"; + } + + @Override + public String getSymbol() { + return symbol; + } + + /** + * Returns the string in a format to be presented to the user + * @return the formatted string output + */ + @Override + public String toString(){ + return "[E]" + super.getStatusIcon() + " " + super.getDescription(); + } + + /** + * Returns the string in a format to be stored in the text file + * @return the formatted string to be stored in the text file + */ + @Override + public String toFile() { + return this.getStatusIcon() + " : " + "E" + " : " + this.description; + } +} diff --git a/src/main/java/Tasks/Task.java b/src/main/java/Tasks/Task.java new file mode 100644 index 000000000..2c29a0b68 --- /dev/null +++ b/src/main/java/Tasks/Task.java @@ -0,0 +1,73 @@ +package Tasks; + +public class Task { + protected String description; + protected boolean isDone; + protected String symbol = "[T]"; + + public String getDescription() { + return description; + } + + public Task(String description) { + this.description = description; + this.isDone = false; + } + + /** + * Returns the symbol of the task + * @return + */ + public String getSymbol() { + return symbol; + } + + /** + * marks the task as done + */ + public void markAsDone() { + this.isDone = true; + } + + /** + * Returns the boolean value of whether a task has been marked as done or not + * @return true if the task has been marked as done, false otherwise + */ + public boolean isDone() { + return isDone; + } + + /** + * marks the task as not done + */ + public void markAsUnDone() { + this.isDone = false; + } + + /** + * Checks if the task has been marked as done and returns the appropriate symbol + * @return returns "[X]" if done, and "[ ]" if not done + */ + public String getStatusIcon() { + return (isDone ? "[X]" : "[ ]"); // mark done task with X + } + + /** + * Returns a string representation of the task to be presented to the user + * @return the formatted string output + */ + @Override + public String toString(){ + return "[T]" + this.getStatusIcon() + " " + getDescription(); + } + + /** + * Returns a string representation of the task to be stored in the text file + * @return the formatted string output + */ + public String toFile() { + return this.getStatusIcon() + " : " +"T"+ " : " + this.description; + } +} + + diff --git a/src/main/java/User/Parser.java b/src/main/java/User/Parser.java new file mode 100644 index 000000000..4c2abf914 --- /dev/null +++ b/src/main/java/User/Parser.java @@ -0,0 +1,49 @@ +package User; + +public class Parser { + /** + * Takes in the users command and carries out the corresponding action + * @param userInput the command that the user inputs + */ + public static void parsing(String userInput){ + String[] inputParts; + inputParts = userInput.split(" ",2); + String command = inputParts[0]; + switch(command){ + case("list"): + TaskList.printList(); + break; + case("delete"): + TaskList.deleteItem(userInput); + break; + case("mark"): + TaskList.markItem(userInput); + break; + case("unmark"): + TaskList.unMarkItem(userInput); + break; + case("event"): + TaskList.createEvent(userInput); + break; + case("todo"): + TaskList.createToDo(userInput); + break; + case("deadline"): + TaskList.createDeadline(userInput); + break; + case("help"): + UI.printHelp(); + break; + case("find"): + if(!TaskList.taskList.isEmpty()) { + TaskList.find(userInput); + } else { + UI.listIsEmpty(); + } + break; + default: + UI.invalidCommand(); + break; + } + } +} diff --git a/src/main/java/User/Storage.java b/src/main/java/User/Storage.java new file mode 100644 index 000000000..8e3ab0473 --- /dev/null +++ b/src/main/java/User/Storage.java @@ -0,0 +1,99 @@ +package User; +import Tasks.Deadline; +import Tasks.Task; +import Tasks.Event; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Scanner; + +public class Storage { + /** + * Reads through the text file and initiates all the saved tasks + * @param filePath the string that represents the filepath where the text is stored + * @return The ArrayList with all the stored tasks + * @throws FileNotFoundException throws an error if the file is not found + */ + public static ArrayList readFile(String filePath) throws FileNotFoundException { + ArrayList tempTasks = new ArrayList(100); + String[] userInputParts; + File f = new File(filePath); // create a File for the given file path + Scanner s = new Scanner(f); // create a Scanner using the File as the source + while (s.hasNext()) { + String newLine = s.nextLine(); + String[] newInput = newLine.split(" : ",3); + String userInput = newInput[2]; + String taskType = newInput[1]; + switch (taskType) { + case "T": + Task task = new Task(userInput); + tempTasks.add(task); + break; + case "D": + userInput = userInput.replace("(",""); + userInput = userInput.replace(")",""); + userInputParts = userInput.split("By:"); + Deadline deadline = new Deadline(userInputParts[0], userInputParts[1]); + tempTasks.add(deadline); + break; + case "E": + userInput = userInput.replace("(",""); + userInput = userInput.replace(")",""); + userInputParts = userInput.split("From:"); + String description = userInputParts[0]; + userInputParts = userInputParts[1].split("To:"); + Event event = new Event(description, userInputParts[0], userInputParts[1]); + tempTasks.add(event); + break; + default: + UI.errorReadingFile(); + break; + } + if (newInput[0].equals("[X]")) { + tempTasks.get(tempTasks.size() - 1).markAsDone(); + } + } + return tempTasks; + } + + /** + * Writes a string into the text file to be stored + * @param toFile the formatted string from the tasks that are to be written into the text file + * @throws IOException if an I/O error occurs while writing to this file + */ + public static void writeToFile(String toFile) throws IOException { + FileWriter fw = new FileWriter("duke.txt",true); + fw.write(toFile); + fw.close(); + } + + /** + * Wipes the file clean + * @throws IOException if an I/O error occurs while writing to this file + */ + public static void clearFile() throws IOException { + FileWriter fw = new FileWriter("duke.txt"); + fw.write(""); + fw.close(); + } + + /** + * Updates the text file with the current list of tasks during the latest running of Duke + * @param taskList the ArrayList of tasks to be updated to the text file + */ + public static void updateFile(ArrayList taskList) { + for (int i = 0; i < taskList.size(); i++) { + try { + writeToFile(taskList.get(i).toFile()); + if (i < taskList.size()-1){ + writeToFile("\n"); + } + } catch (IOException e) { + System.out.println("ERROR!"); + } + } + } + +} diff --git a/src/main/java/User/TaskList.java b/src/main/java/User/TaskList.java new file mode 100644 index 000000000..a96f04b70 --- /dev/null +++ b/src/main/java/User/TaskList.java @@ -0,0 +1,181 @@ +package User; +import Tasks.Deadline; +import Tasks.Event; +import Tasks.Task; +import java.util.ArrayList; +import static User.UI.line; + +public class TaskList { + + public static ArrayList taskList = new ArrayList(100); + + /** + *Iterates through taskList and prints the task number, description, status and other + * details such as start and end time for the relevant task types + */ + public static void printList(){ + if (taskList.isEmpty()) { + UI.listIsEmpty(); + } else { + System.out.println("Here are the tasks in your list:\n"); + for (Task item : taskList) { + System.out.print((taskList.indexOf(item) + 1) + "."); + System.out.println(item.toString()); + } + System.out.println(line); + } + } + + /** + * Deletes a task from the array based on its index + * @param userInput The index of the item that is to be deleted + */ + public static void deleteItem(String userInput) { + int itemNumber = Integer.parseInt(userInput.replaceAll("[^0-9]", "")) - 1; + //to check if an item is within the index of the list + if (itemNumber >= taskList.size()) { + UI.indexNotFound(); + } else { + System.out.println(line); + System.out.println("Noted. I've removed this task:\n" + taskList.get(itemNumber).getSymbol() + + taskList.get(itemNumber).getStatusIcon() + taskList.get(itemNumber).getDescription() + '\n'); + taskList.remove(itemNumber); + System.out.println("Now you have " + taskList.size() + " tasks in the list."); + System.out.println(line); + } + } + + /** + * Accesses the index of the item in the array and updates its status to be done + * @param userInput The index of the item to be marked as done + */ + public static void markItem(String userInput) { + int itemNumber = Integer.parseInt(userInput.replaceAll("[^0-9]", "")) - 1; + //to check if an item is within the index of the list + System.out.println(line); + if (itemNumber >= taskList.size()){ + UI.indexNotFound(); + } else { + if (taskList.get(itemNumber).isDone()){ + System.out.println("The task has already been completed!"); + System.out.println(line); + } else { + taskList.get(itemNumber).markAsDone(); + System.out.println("Nice! I've marked this task as done: \n" + taskList.get(itemNumber).getStatusIcon() + taskList.get(itemNumber).getDescription()); + System.out.println(line); + } + } + } + /** + * Accesses the index of the item in the array and updates its status to be not done + * @param userInput The index of the item to be marked as not done + */ + public static void unMarkItem(String userInput) { + int itemNumber = Integer.parseInt(userInput.replaceAll("[^0-9]", "")) - 1; + //to check if an item is within the index of the list + System.out.println(line); + if (itemNumber >= taskList.size()) { + UI.indexNotFound(); + } else { + if (taskList.get(itemNumber).isDone()) { + taskList.get(itemNumber).markAsUnDone(); + System.out.println("OK, I've marked this task as not done yet: \n" + " " + + taskList.get(itemNumber).getStatusIcon() + taskList.get(itemNumber).getDescription()); + System.out.println(line); + } else { + System.out.println("The task has not been completed!"); + System.out.println(line); + } + } + } + + /** + * Creates an Event-type task and adds it to the array list + * The user input is parsed into the function and split into three parts: the description, + * the start time and the end time. + * A message at the end will inform the user what is the updated number of tasks that they have + * @param userInput The user input to be parsed and split into its parts. + */ + public static void createEvent(String userInput){ + String[] userInputParts; + userInput = userInput.replace("event ",""); + userInputParts = userInput.split("/"); + userInputParts[1] = userInputParts[1].replace("from ", ""); + userInputParts[2] = userInputParts[2].replace("to ", ""); + Event event = new Event(userInputParts[0], userInputParts[1], userInputParts[2]); + taskList.add(event); + System.out.println("Got it. I've added this task: "); + System.out.println(event.toString()); + System.out.println("Now you have " + taskList.size() + " tasks in the list. "); + System.out.println(line); + } + /** + * Creates a Deadline-type task and adds it to the array list + * The user input is parsed into the function and split into two parts: the description + * and the deadline time. + * A message at the end will inform the user what is the updated number of tasks that they have + * @param userInput The user input to be parsed and split into its parts. + */ + public static void createDeadline(String userInput){ + String[] userInputParts; + userInput = userInput.replace("deadline ",""); + userInputParts = userInput.split("/"); + userInputParts[1] = userInputParts[1].replace("by ", ""); + Deadline deadline = new Deadline(userInputParts[0], userInputParts[1]); + taskList.add(deadline); + System.out.println(deadline.toString()); + System.out.println("Now you have " + taskList.size() + " tasks in the list. "); + System.out.println(line); + } + /** + * Creates an todo-type task and adds it to the array list + * The user input is parsed in the function + * A message at the end will inform the user what is the updated number of tasks that they have + * @param userInput The user input to be parsed + */ + public static void createToDo(String userInput){ + userInput = userInput.replace("todo ",""); + String dummy = userInput.replace(" ",""); + //checks if description is empty and throws warning back to user + if (dummy.isEmpty()){ + UI.emptyDescription(); + } else { + Task task = new Task(userInput); + taskList.add(task); + System.out.println("Got it. I've added this task: "); + System.out.println(task.getSymbol() + task.getStatusIcon() + " " + task.getDescription()); + System.out.println("Now you have " + taskList.size() + " tasks in the list. "); + System.out.println(line); + } + } + /** + * Prints out all items in the task list that contain the keyword and their respective indexes + * If no items are found with the given keyword, a prompt will be given to the user + * to use a different keyword + * @param userInput The keyword the user will use to look for the item + */ + public static void find(String userInput) { + ArrayList findList = new ArrayList(100); + ArrayList indexOfItem = new ArrayList(100); + userInput = userInput.replace("find ", ""); + for (int i = 0; i < taskList.size(); i++) { + if (taskList.get(i).getDescription().contains(userInput)) { + findList.add(taskList.get(i)); + indexOfItem.add(i+1); + } + } + if (!findList.isEmpty()) { + System.out.println(line); + System.out.println("Here are the matching tasks in your list:"); + for (int j = 0; j < indexOfItem.size(); j++) { + System.out.print((indexOfItem.get(j)) + "."); + System.out.println(findList.get(j).toString()); + } + System.out.println(line); + } else { + System.out.println("Use another keyword!"); + System.out.println(line); + } + } + +} diff --git a/src/main/java/User/UI.java b/src/main/java/User/UI.java new file mode 100644 index 000000000..be29a9476 --- /dev/null +++ b/src/main/java/User/UI.java @@ -0,0 +1,66 @@ +package User; + +public class UI { + + /** + *These are the list of prompts/greetings/error messages that will be presented to the user at the + * appropriate times + */ + + static String logo = " ____ _ \n" + + "| _ \\ _ _| | _____ \n" + + "| | | | | | | |/ / _ \\\n" + + "| |_| | |_| | < __/\n" + + "|____/ \\__,_|_|\\_\\___|\n"; + static String line = "____________________________________________________________\n"; + static String greeting = (line + "Hello! I'm Duke\n" + "What can I do for you?\n" + line); + static String goodBye = (line + "Bye. Hope to see you again soon!\n" + line); + + public static void printLogo(){ + System.out.println("Hello from\n" + logo); + System.out.println(greeting); + printHelp(); + } + + public static void printBye(){ + System.out.println(goodBye); + } + + public static void printHelp(){ + System.out.println("Here are the list of commands:"); + System.out.println("1. list (to see the current tasks saved)"); + System.out.println("2. todo (for tasks with no particular time to take note of)"); + System.out.println("3. event /from /to "); + System.out.println("4. deadline /by "); + System.out.println("5. mark (to mark a task as done)"); + System.out.println("6. unmark (to mark a task as not done)"); + System.out.println("7. delete (to remove a task from the list)"); + System.out.println("8. bye (to terminate the programme)"); + System.out.println(line); + } + public static void emptyDescription(){ + System.out.println("Please do not leave the description empty!"); + System.out.println(line); + } + + public static void invalidCommand(){ + System.out.println("Please enter a valid command!"); + System.out.println("Enter command 'help' to see the list of available commands!"); + System.out.println(line); + } + + public static void indexNotFound(){ + System.out.println("Please ensure the number you have entered is within the list!"); + System.out.println(line); + } + + public static void listIsEmpty(){ + System.out.println("Invalid command! The list is empty!"); + System.out.println(line); + } + + public static void errorReadingFile(){ + System.out.println("Error reading file!"); + System.out.println(line); + } +}