diff --git a/README.md b/README.md deleted file mode 100644 index 8715d4d91..000000000 --- a/README.md +++ /dev/null @@ -1,24 +0,0 @@ -# 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 - ____ _ - | _ \ _ _| | _____ - | | | | | | | |/ / _ \ - | |_| | |_| | < __/ - |____/ \__,_|_|\_\___| - ``` diff --git a/UserGuide b/UserGuide new file mode 100644 index 000000000..953e3ea6f --- /dev/null +++ b/UserGuide @@ -0,0 +1,57 @@ +# Duke Task Manager +Duke is a task manager that helps users keep track of their daily tasks. Users can add, edit, delete, and search for tasks using the command-line interface. Duke uses a simple text file to store the tasks. +This guide will help you get started. + +## Prerequisites +Before using Duke, please ensure that you have the following: +- Java 11 or later installed on your computer +- The Duke.jar file downloaded on your computer + +## Getting Started +1. Download the Duke.jar file to your computer. +2. Open a terminal or command prompt and navigate to the directory where the Duke.jar file is located. +3. Run the following command to start Duke: + +java -jar Duke.jar +4. If Duke is running properly, you should see a welcome message. + +## Features +Duke currently supports the following features: + +### Adding Tasks +To add a task, type one of the following commands followed by the task description: +- todo: adds a new todo task +- event: adds a new event task +- deadline: adds a new deadline task +For example: +todo buy groceries +event attend meeting /at 2022-03-01 10:00-12:00 +deadline submit report /by 2022-03-05 23:59 + +### Listing Tasks +To list all the tasks currently in Duke, type the command list. + +### Marking Tasks +To mark a task as done, type the command mark followed by the task number. For example: +mark 2 + +### Unmarking Tasks +To unmark a task as done, type the command unmark followed by the task number. +For example: +unmark 2 + +### Deleting Tasks +To delete a task, type the command delete followed by the task number. For example: +delete 2 + +### Finding Tasks +To find tasks containing a specific keyword, type the command find followed by the keyword. For example: +find groceries + +### Exiting Duke +To exit Duke, type the command bye. + +## Notes +- All tasks added to Duke are automatically saved to a file named "Duke.txt" in the same directory as the Duke.jar file. +- If the Duke.txt file already exists, Duke will load the tasks from the file when it starts. +- If an error occurs while Duke is running, an error message will be displayed. diff --git a/docs/README.md b/docs/README.md index 8077118eb..915fffd69 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,29 +1,65 @@ -# User Guide +# Duke Task Manager +Duke is a task manager that helps users keep track of their daily tasks. Users can add, edit, delete, and search for tasks using the command-line interface. Duke uses a simple text file to store the tasks. +This guide will help you get started. -## Features +## Prerequisites +Before using Duke, please ensure that you have the following: +- Java 11 or later installed on your computer +- The Duke.jar file downloaded on your computer -### Feature-ABC +## Getting Started +1. Download the Duke.jar file to your computer. +2. Open a terminal or command prompt and navigate to the directory where the Duke.jar file is located. +3. Run the following command to start Duke: -Description of the feature. +java -jar Duke.jar +4. If Duke is running properly, you should see a welcome message. -### Feature-XYZ +## Features +Duke currently supports the following features: -Description of the feature. +### Adding Tasks +To add a task, type one of the following commands followed by the task description: +- todo: adds a new todo task +- event: adds a new event task +- deadline: adds a new deadline task -## Usage +For example: +todo borrow book +event project meeting /from Mon 2pm /to 4pm +deadline return book /by Sunday -### `Keyword` - Describe action +### Listing Tasks +To list all the tasks currently in Duke, type the command list. -Describe the action and its outcome. +### Marking Tasks +To mark a task as done, type the command mark followed by the task number. -Example of usage: +For example: +mark 2 -`keyword (optional arguments)` +### Unmarking Tasks +To unmark a task as done, type the command unmark followed by the task number. -Expected outcome: +For example: +unmark 2 -Description of the outcome. +### Deleting Tasks +To delete a task, type the command delete followed by the task number. -``` -expected output -``` +For example: +delete 2 + +### Finding Tasks +To find tasks containing a specific keyword, type the command find followed by the keyword. + +For example: +find groceries + +### Exiting Duke +To exit Duke, type the command bye. + +## Notes +- All tasks added to Duke are automatically saved to a file named "Duke.txt" in the same directory as the Duke.jar file. +- If the Duke.txt file already exists, Duke will load the tasks from the file when it starts. +- If an error occurs while Duke is running, an error message will be displayed. diff --git a/duke.txt b/duke.txt new file mode 100644 index 000000000..e69de29bb diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java new file mode 100644 index 000000000..134175212 --- /dev/null +++ b/src/main/java/Deadline.java @@ -0,0 +1,20 @@ +/** + Represents a task with a deadline. + Inherits from the Task class. + */ +public class Deadline extends Task { + protected String due; + /** + Constructs a Deadline object with the specified information and deadline. + @param info the description of the task. + @param due the deadline of the task. + */ + public Deadline(String info, String due) { + super(info); + this.due = due; + } + @Override + public String toString(){ + return "[D]" + super.toString() + "(by: " + due + ")"; + } +} diff --git a/src/main/java/Duke.java b/src/main/java/Duke.java index 5d313334c..a534c814b 100644 --- a/src/main/java/Duke.java +++ b/src/main/java/Duke.java @@ -1,10 +1,277 @@ +/** + * The Duke class represents a chatbot that can respond to user input. + */ +import java.util.Scanner; +import java.util.ArrayList; +import java.io.IOException; public class Duke { + private Memory memory; + private IO io; + private TaskList tasks; + private Parser parser; + + /** + * Constructor for Duke object. + * Initializes a new Duke object and loads tasks from a file. + * Prints a welcome message and loops for user input until the user types "bye". + * + * @param filepath Path to the file to load tasks from. + */ + public Duke(String filepath) { + memory = new Memory(filepath); + io = new IO(); + tasks = new TaskList(); + Scanner in = new Scanner(System.in); + io.printWelcome(); + try { + storeTasksInList(memory.loadFile()); + } catch (IOException e) { + io.showLoadingError(); + } + while (true) { + String userInput = in.nextLine(); + processUserInput(userInput, true); + } + } + + /** + * Loads a list of input commands to the TaskList. + * Each input command is processed by the processUserInput method. + * + * @param inputCommands A list of input commands to load to the TaskList. + * @throws IOException If there is an error reading the file. + */ + public void storeTasksInList(ArrayList inputCommands) throws IOException { + for (String s : inputCommands) { + processUserInput(s, false); + } + } public static void main(String[] args) { - String logo = " ____ _ \n" - + "| _ \\ _ _| | _____ \n" - + "| | | | | | | |/ / _ \\\n" - + "| |_| | |_| | < __/\n" - + "|____/ \\__,_|_|\\_\\___|\n"; - System.out.println("Hello from\n" + logo); - } -} + new Duke("DUKE/Duke.txt"); + } + + /** + * Processes user input by executing the appropriate action. + * Prints an error message if an invalid command is entered. + * + * @param userInput The user's input. + * @param fileDoesExist Whether the file exists or not. + */ + private void processUserInput(String userInput, boolean fileDoesExist) { + parser = new Parser(); + String[] actionAndDescription = parser.splitActionAndDescription(userInput); + String action = actionAndDescription[0]; + String description = actionAndDescription[1]; + try { + switch (action) { + case "bye": + io.printBye(); + break; + case "list": + executeListAction(fileDoesExist); + break; + case "mark": + executeMarkAction(description, fileDoesExist); + if (fileDoesExist) { + memory.writeToFile(); + } + break; + case "unmark": + executeUnmarkAction(description, fileDoesExist); + if (fileDoesExist) { + memory.writeToFile(); + } + break; + case "todo": + executeTodoAction(description, fileDoesExist); + if (fileDoesExist) { + memory.appendToFile(userInput); + } + break; + case "event": + executeEventAction(description, fileDoesExist); + if (fileDoesExist) { + memory.appendToFile(userInput); + } + break; + case "deadline": + executeDeadlineAction(description, fileDoesExist); + if (fileDoesExist) { + memory.appendToFile(userInput); + } + break; + case "delete": + executeDeleteAction(description); + break; + case "find": + executeFindAction(description); + break; + default: + io.showInvalidCommand(); + } + } catch (IOException e) { + io.showCannotEditFile(); + } + } + + /** + * Executes the "list" action by printing the list of tasks to the user. + * + * @param fileDoesExist A boolean indicating if the file exists or not. + */ + private void executeListAction(boolean fileDoesExist) { + if (fileDoesExist) { + io.printList(tasks.getTasks()); + } + } + + /** + * Executes the "mark" action by marking the specified task as done and printing an acknowledgement message to the user. + * + * @param description The task description provided by the user. + * @param fileDoesExist A boolean indicating if the file exists or not. + */ + private void executeMarkAction(String description, boolean fileDoesExist) { + int index = Integer.parseInt(description) - 1; + tasks.markAtIndex(index); + if (fileDoesExist) { + io.printMarked(tasks.getTasks(), index); + } + } + + /** + * Executes the "unmark" action by marking the specified task as undone and printing an acknowledgement message to the user. + * + * @param description The task description provided by the user. + * @param fileDoesExist A boolean indicating if the file exists or not. + */ + private void executeUnmarkAction(String description, boolean fileDoesExist) { + int index = Integer.parseInt(description) - 1; + tasks.unmarkAtIndex(Integer.parseInt(description) - 1); + if (fileDoesExist) { + io.printUnmarked(tasks.getTasks(), index); + } + } + + /** + * Executes the "todo" action by adding a new Todo task to the task list and printing an acknowledgement message to the user. + * + * @param description The task description provided by the user. + * @param fileDoesExist A boolean indicating if the file exists or not. + */ + private void executeTodoAction(String description, boolean fileDoesExist) { + try { + tasks.addTodoToList(description); + if (fileDoesExist) { + io.printAcknowledgement(tasks.getTasks()); + } + } catch (Exception e) { + io.showInsufficientTodo(); + } + } + + /** + * Executes an event action if the file exists. + * Parses the description into name, fromDate and toDate. + * Adds the parsed task to the task list and prints acknowledgement if the file exists. + * Otherwise, shows an error message. + * + * @param description The description of the event task. + * @param fileDoesExist Indicates whether the file exists. + */ + private void executeEventAction(String description, boolean fileDoesExist) { + if (fileDoesExist) { + try { + String[] indexArr = splitDescriptionEvent(description); + String name = indexArr[0].trim(); + String fromDate = indexArr[1].substring(5).trim(); + String toDate = indexArr[2].substring(3).trim(); + tasks.addEventToList(name, fromDate, toDate); + if (fileDoesExist) { + io.printAcknowledgement(tasks.getTasks()); + } + } catch (DukeException e) { + io.showInsufficientEvent(); + } + } + } + + /** + * Parses the description of an event task and returns an array containing the name, + * fromDate and toDate. + * + * @param description The description of the event task. + * @return An array containing the name, fromDate and toDate. + * @throws DukeException If there are insufficient arguments to parse the description. + */ + + private static String[] splitDescriptionEvent(String description) throws DukeException { + String[] indexArr = description.split("/", 3); + if (indexArr.length < 3) { + throw new DukeException(new IllegalArgumentException()); + } + return indexArr; + } + + /** + * Executes a deadline action. + * Parses the description into name and byDate. + * Adds the parsed task to the task list and prints acknowledgement if the file exists. + * Otherwise, shows an error message. + * + * @param description The description of the deadline task. + * @param fileDoesExist Indicates whether the file exists. + */ + private void executeDeadlineAction(String description, boolean fileDoesExist) { + try { + String[] indexArr = splitDescriptionDeadline(description); + String name = indexArr[0].trim(); + String byDate = indexArr[1].substring(3).trim(); + tasks.addDeadlineToList(name, byDate); + if (fileDoesExist) { + io.printAcknowledgement(tasks.getTasks()); + } + } catch (DukeException e) { + io.showInsufficientDeadline(); + } + } + + /** + * Parses the description of a deadline task and returns an array containing the name and byDate. + * + * @param description The description of the deadline task. + * @return An array containing the name and byDate. + * @throws DukeException If there are insufficient arguments to parse the description. + */ + private static String[] splitDescriptionDeadline(String description) throws DukeException { + String[] indexArr = description.split("/", 2); + if (indexArr.length < 2) { + throw new DukeException(new IllegalArgumentException()); + } + return indexArr; + } + + /** + * Executes a delete action. + * Deletes the task at the specified index and prints the deleted task and task list. + * + * @param description The index of the task to delete. + */ + private void executeDeleteAction(String description) { + Integer index = Integer.parseInt(description) - 1; + String deletedTask = tasks.deleteTaskAtIndex(index); + io.printDeleted(tasks.getTasks(), deletedTask); + } + + /** + * Executes a find action. + * Finds tasks containing the specified keyword and prints them. + * + * @param description The keyword to search for. + */ + private void executeFindAction(String description) { + ArrayList foundTasks = tasks.findTasks(description); + io.printFind(); + io.printList(foundTasks); + } +} \ No newline at end of file diff --git a/src/main/java/DukeException.java b/src/main/java/DukeException.java new file mode 100644 index 000000000..4c6b3c98a --- /dev/null +++ b/src/main/java/DukeException.java @@ -0,0 +1,5 @@ +public class DukeException extends Exception { + public DukeException(Throwable cause) { + super(cause); + } +} diff --git a/src/main/java/Event.java b/src/main/java/Event.java new file mode 100644 index 000000000..a14b8f1e8 --- /dev/null +++ b/src/main/java/Event.java @@ -0,0 +1,23 @@ +/** + Represents a task that is an event with a start time and end time. + Inherits from the Task class. + */ +public class Event extends Task { + protected String startTime; + protected String endTime; + /** + Constructs an Event object with the specified information, start time and end time. + @param info the description of the event. + @param startTime the start time of the event. + @param endTime the end time of the event. + */ + public Event(String info, String startTime, String endTime) { + super(info); + this.startTime = startTime; + this.endTime = endTime; + } + @Override + public String toString() { + return "[E]" + super.toString() + "(from: " + startTime + " to: " + endTime + ")"; + } +} diff --git a/src/main/java/IO.java b/src/main/java/IO.java new file mode 100644 index 000000000..dac9c55d4 --- /dev/null +++ b/src/main/java/IO.java @@ -0,0 +1,124 @@ +/** + Handles Input/Output operations for Duke. + */ +import java.util.ArrayList; +public class IO { + public IO(){ + } + /** + * Prints a welcome message. + */ + public void printWelcome(){ + System.out.println("Hello! I'm Duke \nWhat can I do for you?"); + } + /** + * Prints a goodbye message. + */ + public void printBye(){ + System.out.println("Bye. Hope to see you again soon!"); + System.exit(0); + } + /** + *Prints an acknowledgement message for adding a task to the list. + *@param "tasks" the current task list. + */ + public void printAcknowledgement(ArrayList tasks) { + int lastIndexOfTasks = tasks.size() - 1; + System.out.println("Got it. I've added this task:"); + System.out.println(tasks.get(lastIndexOfTasks).toString()); + if (tasks.size() == 1){ + System.out.println("Now you have " + tasks.size()+ " task in the list."); + } else { + System.out.println("Now you have " + tasks.size() + " tasks in the list."); + } + } + /** + * Prints the current task list. + * + * @param tasks the current task list. + */ + public void printList(ArrayList tasks) { + for (int i = 0; i < tasks.size(); i++) { + System.out.print(i + 1 + "."); + System.out.println(tasks.get(i).toString()); + } + } + /** + * Prints a message confirming that a task has been marked as completed. + * + * @param tasks the current task list. + * @param index the index of the completed task in the list. + */ + public void printMarked(ArrayList tasks, Integer index) { + System.out.println("Nice! I've marked this task as done:"); + System.out.println(tasks.get(index).toString()); + } + /** + * Prints a message confirming that a task has been marked as incomplete. + * + * @param tasks the current task list. + * @param index the index of the incomplete task in the list. + */ + public void printUnmarked(ArrayList tasks, Integer index) { + System.out.println("OK, I've marked this task as not done yet:"); + System.out.println(tasks.get(index).toString()); + } + /** + * Prints a message confirming that a task has been deleted from the list. + * + * @param tasks the current task list. + * @param deletedTask the deleted task. + */ + public void printDeleted(ArrayList tasks, String deletedTask) { + System.out.println("Noted. I've removed this task:"); + System.out.println(deletedTask); + if (tasks.size() == 1) { + System.out.println("Now you have " + tasks.size() + " task in the list."); + } else { + System.out.println("Now you have " + tasks.size() + " tasks in the list."); + } + } + /** + * Prints a message indicating that matching tasks were found. + */ + public void printFind() { + System.out.println("Here are the matching tasks in your list:"); + } + /** + * Prints an error message indicating that the program is unable to write or append to the file. + */ + public void showCannotEditFile(){ + System.out.println("Unable to write/append to file."); + } + /** + * Prints an error message indicating that the program is unable to read from the file. + */ + public void showLoadingError(){ + System.out.println("Could not read file."); + } + /** + * Prints an error message indicating that the user has entered an invalid command. + */ + public void showInvalidCommand(){ + System.out.println("OOPS!!! I'm sorry, but I don't know what that means :-("); + } + /** + * Prints an error message indicating that the user has not provided any description for a todo task. + */ + public void showInsufficientTodo(){ + System.out.println("Unable to add todo: No tasks given."); + } + /** + * Prints an error message indicating that the user has not provided enough information to create an event task. + */ + public void showInsufficientEvent(){ + System.out.println("Not enough commands to execute \"event\""); + } + /** + * Prints an error message indicating that the user has not provided enough information to create a deadline task. + */ + public void showInsufficientDeadline(){ + System.out.println("Not enough commands to execute \"deadline\""); + } + +} \ 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..9f37e4e0a --- /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/Memory.java b/src/main/java/Memory.java new file mode 100644 index 000000000..3aaf8db03 --- /dev/null +++ b/src/main/java/Memory.java @@ -0,0 +1,61 @@ +/** + * Memory is a class that saves the tasks in the hard disk automatically whenever the task list changes. + * And loads the data from the hard disk when Duke starts up. + */ + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Scanner; +public class Memory { + private String filePath; + private ArrayList fileContents = new ArrayList<>(); + private ArrayList commandInput = new ArrayList<>(); + public Memory(String filePath) { + this.filePath = filePath; + } + /** + * Loads the contents of the file into an ArrayList of Strings. + * + * @return an ArrayList of Strings containing the contents of the file + * @throws IOException if there is an error reading from the file + */ + public ArrayList loadFile() throws IOException { + File F = new File(filePath); + if (!F.exists()) { + F = new File("duke.txt"); + this.filePath = F.getPath(); + } + Scanner s = new Scanner(F); + while (s.hasNext()) { + fileContents.add(s.nextLine()); + } + return fileContents; + } + /** + * Writes the contents of the commandInput ArrayList to the file. + * + * @throws IOException if there is an error writing to the file + */ + public void writeToFile() throws IOException { + FileWriter fw = new FileWriter(this.filePath); + for (String s : commandInput) { + fw.write(s); + fw.write('\n'); + } + fw.close(); + } + /** + * Appends the specified userInput String to the file. + * + * @param userInput the String to append to the file + * @throws IOException if there is an error writing to the file + */ + public void appendToFile(String userInput) throws IOException { + FileWriter fw = new FileWriter(this.filePath, true); + fw.write(userInput); + fw.write('\n'); + fw.close(); + } +} \ No newline at end of file diff --git a/src/main/java/Parser.java b/src/main/java/Parser.java new file mode 100644 index 000000000..e11bd6133 --- /dev/null +++ b/src/main/java/Parser.java @@ -0,0 +1,24 @@ +public class Parser { + private String userInput; + + public Parser(String userInput) { + this.userInput = userInput; + } + + public Parser() { + } + + /** + * Splits user input into an action and a description array. + * + * @param userInput The user's input. + * @return An array containing the action and description of the input. + */ + public String[] splitActionAndDescription(String userInput){ + String[] commandAndArgs = userInput.split(" ",2); + if(commandAndArgs.length == 1){ + return new String[]{commandAndArgs[0],""}; + } + return commandAndArgs; + } +} diff --git a/src/main/java/Task.java b/src/main/java/Task.java new file mode 100644 index 000000000..60693a5ba --- /dev/null +++ b/src/main/java/Task.java @@ -0,0 +1,17 @@ +/** + Represents a general task with a name and completion status. + */ +public class Task { + protected String name; + protected boolean isCompleted; + /** + Constructs a Task object with the specified name. + @param info the name of the task. + */ + public Task(String info) { + this.name = info; + } + public String toString () { + return(isCompleted?"[X]"+this.name:"[ ]"+this.name); + } +} \ No newline at end of file diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java new file mode 100644 index 000000000..d823a2678 --- /dev/null +++ b/src/main/java/TaskList.java @@ -0,0 +1,80 @@ +/** + TaskList is a class that handles the manipulation of tasks in an ArrayList. + It contains methods to add, delete, mark as done, and find tasks. + */ +import java.util.ArrayList; +public class TaskList { + ArrayList tasks = new ArrayList<>(); + public TaskList() { + } + public ArrayList getTasks() { + return tasks; + } + /** + Marks the task at the given index as completed. + @param index The index of the task to be marked. + */ + public void markAtIndex(Integer index) { + tasks.get(index).isCompleted = true; + } + /** + Marks the task at the given index as incomplete. + @param index The index of the task to be unmarked. + */ + public void unmarkAtIndex(Integer index) { + tasks.get(index).isCompleted = false; + } + /** + Adds a Todo task to the list. + @param description The description of the Todo task. + @throws DukeException If description is an empty string. + */ + public void addTodoToList(String description) throws DukeException { + if(description.equals("")){ + throw new DukeException(new IllegalArgumentException()); + } + tasks.add(new Todo(description)); + } + /** + Adds a Deadline task to the list. + @param description The description of the Deadline task. + @param byDate The date and time by which the Deadline task should be completed. + */ + public void addDeadlineToList(String description, String byDate) { + tasks.add(new Deadline(description, byDate)); + } + /** + Adds an Event task to the list. + @param description The description of the Event task. + @param fromDate The date and time from which the Event task starts. + @param toDate The date and time at which the Event task ends. + */ + public void addEventToList(String description, String fromDate, String toDate) { + tasks.add(new Event(description, fromDate, toDate)); + } + /** + Deletes the task at the given index from the list. + @param index The index of the task to be deleted. + @return The name of the deleted task. + */ + public String deleteTaskAtIndex(Integer index){ + String nameOfToBeDeletedTask = tasks.get(index).name; + tasks.remove((int)index); + return nameOfToBeDeletedTask; + } + /** + Finds tasks in the list that match the given description. + @param description The description to search for in the tasks. + @return An ArrayList of tasks that match the description. + */ + public ArrayList findTasks(String description){ + ArrayList matchedTasks = new ArrayList<>(); + for(Task s:tasks){ + if (s.name.contains(description)){ + matchedTasks.add(s); + } + } + return matchedTasks; + } +} + diff --git a/src/main/java/Todo.java b/src/main/java/Todo.java new file mode 100644 index 000000000..43623d9cc --- /dev/null +++ b/src/main/java/Todo.java @@ -0,0 +1,16 @@ +/** + Represents a task that is a "todo item. + Inherits from the Task class. + */ +public class Todo extends Task { + /** + Constructs a Todo object with the specified information. + @param info the description of the todo item. + */ + public Todo (String info) { + super (info); + } + public String toString() { + return "[T]" + super.toString(); + } +}