diff --git a/README.md b/README.md index 90aa7f092..58979847a 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,134 @@ -# 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 17, 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 17** (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 - ____ _ - | _ \ _ _| | _____ - | | | | | | | |/ / _ \ - | |_| | |_| | < __/ - |____/ \__,_|_|\_\___| - ``` +# DBot - User Guide + +Welcome to **DBot**, a simple command-line task management chatbot designed to help you keep track of your tasks efficiently. This guide will walk you through all the key features of DBot, explaining how to interact with it and use its commands. + +## Getting Started + +When you run DBot, it will greet you with a welcome message and wait for your input. The interaction with DBot happens via commands that you type. DBot will help you manage tasks such as to-dos, deadlines, and events. + +### Commands Overview + +DBot supports a variety of commands, each of which performs a specific action. Here's a list of the commands you can use: + +- `list` – Displays all your current tasks. +- `mark ` – Marks a task as done. +- `unmark ` – Marks a task as not done. +- `todo ` – Adds a new to-do task. +- `deadline /by ` – Adds a new deadline task. +- `event /from /to ` – Adds a new event task. +- `delete ` – Removes a task from the list. +- `find ` – Finds and displays tasks containing a keyword. +- `bye` – Exits DBot and saves your tasks to a file. + +## Command Details + +### 1. `list` + +Displays the current list of tasks. Each task will be shown with a number and its completion status. + +Example: +``` +Command: list +1. [T][ ] Read a book +2. [D][X] Submit assignment (by: Sunday) +3. [E][ ] Attend workshop (from: Monday 10am to: Monday 12pm) +``` + +### 2. `mark ` + +Marks a task as completed. Replace `` with the task number as shown in the `list` command. + +Example: +``` +Command: mark 2 +Nice! I've marked this task as done: +[D][X] Submit assignment (by: Sunday) +``` + +### 3. `unmark ` + +Marks a task as not completed. Replace `` with the task number. + +Example: +``` +Command: unmark 2 +OK, I've marked this task as not done yet: +[D][ ] Submit assignment (by: Sunday) +``` + +### 4. `todo ` + +Adds a new to-do task with the provided description. + +Example: +``` +Command: todo Buy groceries +Got it. I've added this task: +[T][ ] Buy groceries +Now you have 4 tasks in the list. +``` + +### 5. `deadline /by ` + +Adds a new deadline task with a description and due date. + +Example: +``` +Command: deadline Submit report /by Friday +Got it. I've added this task: +[D][ ] Submit report (by: Friday) +Now you have 5 tasks in the list. +``` + +### 6. `event /from /to ` + +Adds a new event task with a description, start time, and end time. + +Example: +``` +Command: event Team meeting /from 2pm /to 4pm +Got it. I've added this task: +[E][ ] Team meeting (from: 2pm to: 4pm) +Now you have 6 tasks in the list. +``` + +### 7. `delete ` + +Removes a task from the list. Replace `` with the task number. + +Example: +``` +Command: delete 3 +Noted. I've removed this task: +[E][ ] Attend workshop (from: Monday 10am to: Monday 12pm) +Now you have 5 tasks in the list. +``` + +### 8. `find ` + +Searches for tasks containing the specified keyword (case-insensitive). + +Example: +``` +Command: find report +Here are the matching tasks in your list: +1. [D][ ] Submit report (by: Friday) +``` + +### 9. `bye` + +Saves your tasks to a file and exits DBot. + +Example: +``` +Command: bye +Bye. Hope to see you again soon! +``` + +## Saving and Loading Data + +DBot automatically saves your tasks to a file (`data/tasks.txt`) when you exit using the `bye` command. When you restart DBot, it will load your saved tasks, so you can continue where you left off. + +--- + +That’s it! You are now ready to use DBot to manage your tasks. We hope DBot makes your life a little easier! diff --git a/docs/README.md b/docs/README.md index 47b9f984f..58979847a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,30 +1,134 @@ -# Duke User Guide +# DBot - User Guide -// Update the title above to match the actual product name +Welcome to **DBot**, a simple command-line task management chatbot designed to help you keep track of your tasks efficiently. This guide will walk you through all the key features of DBot, explaining how to interact with it and use its commands. -// Product screenshot goes here +## Getting Started -// Product intro goes here +When you run DBot, it will greet you with a welcome message and wait for your input. The interaction with DBot happens via commands that you type. DBot will help you manage tasks such as to-dos, deadlines, and events. -## Adding deadlines +### Commands Overview -// Describe the action and its outcome. +DBot supports a variety of commands, each of which performs a specific action. Here's a list of the commands you can use: -// Give examples of usage +- `list` – Displays all your current tasks. +- `mark ` – Marks a task as done. +- `unmark ` – Marks a task as not done. +- `todo ` – Adds a new to-do task. +- `deadline /by ` – Adds a new deadline task. +- `event /from /to ` – Adds a new event task. +- `delete ` – Removes a task from the list. +- `find ` – Finds and displays tasks containing a keyword. +- `bye` – Exits DBot and saves your tasks to a file. -Example: `keyword (optional arguments)` +## Command Details -// A description of the expected outcome goes here +### 1. `list` +Displays the current list of tasks. Each task will be shown with a number and its completion status. + +Example: +``` +Command: list +1. [T][ ] Read a book +2. [D][X] Submit assignment (by: Sunday) +3. [E][ ] Attend workshop (from: Monday 10am to: Monday 12pm) +``` + +### 2. `mark ` + +Marks a task as completed. Replace `` with the task number as shown in the `list` command. + +Example: +``` +Command: mark 2 +Nice! I've marked this task as done: +[D][X] Submit assignment (by: Sunday) +``` + +### 3. `unmark ` + +Marks a task as not completed. Replace `` with the task number. + +Example: +``` +Command: unmark 2 +OK, I've marked this task as not done yet: +[D][ ] Submit assignment (by: Sunday) +``` + +### 4. `todo ` + +Adds a new to-do task with the provided description. + +Example: +``` +Command: todo Buy groceries +Got it. I've added this task: +[T][ ] Buy groceries +Now you have 4 tasks in the list. +``` + +### 5. `deadline /by ` + +Adds a new deadline task with a description and due date. + +Example: +``` +Command: deadline Submit report /by Friday +Got it. I've added this task: +[D][ ] Submit report (by: Friday) +Now you have 5 tasks in the list. +``` + +### 6. `event /from /to ` + +Adds a new event task with a description, start time, and end time. + +Example: +``` +Command: event Team meeting /from 2pm /to 4pm +Got it. I've added this task: +[E][ ] Team meeting (from: 2pm to: 4pm) +Now you have 6 tasks in the list. +``` + +### 7. `delete ` + +Removes a task from the list. Replace `` with the task number. + +Example: +``` +Command: delete 3 +Noted. I've removed this task: +[E][ ] Attend workshop (from: Monday 10am to: Monday 12pm) +Now you have 5 tasks in the list. +``` + +### 8. `find ` + +Searches for tasks containing the specified keyword (case-insensitive). + +Example: ``` -expected output +Command: find report +Here are the matching tasks in your list: +1. [D][ ] Submit report (by: Friday) ``` -## Feature ABC +### 9. `bye` + +Saves your tasks to a file and exits DBot. + +Example: +``` +Command: bye +Bye. Hope to see you again soon! +``` -// Feature details +## Saving and Loading Data +DBot automatically saves your tasks to a file (`data/tasks.txt`) when you exit using the `bye` command. When you restart DBot, it will load your saved tasks, so you can continue where you left off. -## Feature XYZ +--- -// Feature details \ No newline at end of file +That’s it! You are now ready to use DBot to manage your tasks. We hope DBot makes your life a little easier! diff --git a/src/main/java/DBot.java b/src/main/java/DBot.java new file mode 100644 index 000000000..c9fe1dbd3 --- /dev/null +++ b/src/main/java/DBot.java @@ -0,0 +1,171 @@ +import java.util.Hashtable; +import java.util.List; + +public class DBot { + private static boolean isOn; + private static Ui ui; + private static TaskList taskList; + private static Storage storage; + private static Parser parser; + + public static void main(String[] args) { + isOn = true; + + ui = new Ui(); + storage = new Storage("data/tasks.txt"); + taskList = new TaskList(storage.loadData()); + parser = new Parser(); + + while (isOn) { + String line = ui.readLine(); + parser.parseCommand(line); + + try { + switch (parser.getCommand()) { + case "bye": + isOn = false; + break; + case "list": + list(); + break; + case "mark": + mark(); + break; + case "unmark": + unmark(); + break; + case "todo": + todo(); + break; + case "event": + event(); + break; + case "deadline": + deadline(); + break; + case "delete": + delete(); + break; + case "find": + find(); + break; + default: + throw new DBotException("Unknown command: " + line, "Unknown command"); + } + } catch (Exception e) { + if (e instanceof DBotException) + ui.printDBotError((DBotException) e); + else ui.printGenericError(e); + } + } + ui.printShortMessage("Bye. Hope to see you again soon!"); + storage.saveData(taskList.getTaskList()); + } + + private static void list() { + ui.printShortMessage(ui.listTasks(taskList.getTaskList())); + } + + private static void mark() throws DBotException { + try { + int option = Integer.parseInt(parser.getPrompt()); + Task task = taskList.getTask(option - 1); + task.mark(); + + ui.printLongMessage(new Object[]{ + "Nice! I've marked this task as done:", + task.toString() + }); + } catch (Exception e) { + throw new DBotException("Invalid input, input must be a positive integer and must exist", "Invalid input"); + } + } + + private static void unmark() throws DBotException { + try { + int option = Integer.parseInt(parser.getPrompt()); + Task task = taskList.getTask(option - 1); + task.unmark(); + ui.printLongMessage(new Object[]{ + "OK, I've marked this task as not done yet:", + task.toString() + }); + } catch (Exception e) { + throw new DBotException("Invalid input, input must be a positive integer and must exist", "Invalid input"); + } + } + + private static void todo() throws DBotException { + if (parser.getPrompt().isEmpty()) + throw new DBotException("Cannot have empty prompt", "Invalid input"); + + Todo task = new Todo(parser.getPrompt()); + taskList.addTask(task); + ui.printLongMessage(new Object[]{ + "Got it. I've added this task:", + task, + "Now you have " + taskList.getSize() + " tasks in the list." + }); + } + + private static void deadline() throws DBotException { + if (parser.getPrompt().isEmpty()) + throw new DBotException("Cannot have empty prompt", "Invalid input"); + + Hashtable arguments = parser.getArguments(); + Deadline task; + try { + task = new Deadline(parser.getPrompt(), arguments.get("by")); + } catch (Exception e) { + throw new DBotException("Deadline missing argument '/by'", "Missing argument"); + } + + taskList.addTask(task); + ui.printLongMessage(new Object[]{ + "Got it. I've added this task:", + task, + "Now you have " + taskList.getSize() + " tasks in the list." + }); + } + + private static void event() throws DBotException { + if (parser.getPrompt().isEmpty()) + throw new DBotException("Cannot have empty prompt", "Invalid input"); + + Hashtable arguments = parser.getArguments(); + Event task; + try { + task = new Event(parser.getPrompt(), arguments.get("from"), arguments.get("to")); + } catch (Exception e) { + throw new DBotException("Event missing argument(s) '/from' or '/to'", "Missing argument"); + } + taskList.addTask(task); + ui.printLongMessage(new Object[]{ + "Got it. I've added this task:", + task, + "Now you have " + taskList.getSize() + " tasks in the list." + }); + } + + private static void delete() throws DBotException { + try { + int option = Integer.parseInt(parser.getPrompt()); + Task removed = taskList.removeTask(option - 1); + ui.printLongMessage(new Object[]{ + "Noted. I've removed this task:", + removed, + "Now you have " + taskList.getSize() + " tasks in the list." + }); + } catch (Exception e) { + throw new DBotException("Invalid input, input must be a positive integer and must exist", "Invalid input"); + } + } + + private static void find() { + List result = taskList.find(parser.getPrompt()); + ui.printLongMessage(new Object[]{ + "Here are the matching tasks in your list:", + ui.listTasks(result) + }); + } +} diff --git a/src/main/java/DBotException.java b/src/main/java/DBotException.java new file mode 100644 index 000000000..d12657624 --- /dev/null +++ b/src/main/java/DBotException.java @@ -0,0 +1,24 @@ +public class DBotException extends Exception { + private final String errorType; + + /** + * Represents a custom exception for DBot with an associated error type. + * Extends the standard Exception class to include both an error message and an error type. + * + * @param message the detail message associated with the exception + * @param errorType the type of the error that caused the exception + */ + public DBotException(String message, String errorType) { + super(message); + this.errorType = errorType; + } + + /** + * Returns the type of the error that caused the exception. + * + * @return the error type as a string + */ + public String getErrorType() { + return this.errorType; + } +} diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java new file mode 100644 index 000000000..38a5c61a6 --- /dev/null +++ b/src/main/java/Deadline.java @@ -0,0 +1,35 @@ +public class Deadline extends Task { + String by; + + /** + * Represents a deadline task with a specific due date or time ("by"). + * Extends the Task class to include deadline-specific details. + * + * @param task the description of the deadline task + * @param by the due date or time of the task + */ + public Deadline(String task, String by) { + super(task); + this.by = by.trim(); + } + + /** + * Returns the due date or time of the deadline task. + * + * @return the due date or time as a string + */ + public String getBy() { + return by; + } + + /** + * Returns a string representation of the deadline, including the task description + * and the due date or time in the format "[D] task (by: due date)". + * + * @return a formatted string representing the deadline task + */ + @Override + public String toString() { + return "[D]" + super.toString() + " (by: " + by + ")"; + } +} 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/Event.java b/src/main/java/Event.java new file mode 100644 index 000000000..8cb3d2f02 --- /dev/null +++ b/src/main/java/Event.java @@ -0,0 +1,47 @@ +public class Event extends Task { + String from; + String to; + + /** + * Represents an event task with a start time ("from") and an end time ("to"). + * Extends the Task class to include event-specific details. + * + * @param task the description of the event task + * @param from the starting time of the event + * @param to the ending time of the event + */ + public Event(String task, String from, String to) { + super(task); + this.from = from.trim(); + this.to = to.trim(); + } + + /** + * Returns the start time of the event. + * + * @return the start time of the event as a string + */ + public String getFrom() { + return from; + } + + /** + * Returns the end time of the event. + * + * @return the end time of the event as a string + */ + public String getTo() { + return to; + } + + /** + * Returns a string representation of the event, including the task description, + * start time, and end time in the format "[E] task (from: start time to: end time)". + * + * @return a formatted string representing the event + */ + @Override + public String toString() { + return "[E]" + super.toString() + " (from: " + from + " to: " + to + ")"; + } +} diff --git a/src/main/java/Parser.java b/src/main/java/Parser.java new file mode 100644 index 000000000..507f3de3c --- /dev/null +++ b/src/main/java/Parser.java @@ -0,0 +1,86 @@ +import java.util.Hashtable; + +public class Parser { + private Hashtable arguments; + private String command; + private String prompt; + + public Parser() { + command = ""; + prompt = ""; + arguments = new Hashtable<>(); + } + + /** + * Parses the given command line and extracts the command, prompt, and arguments. + * The command is the first word in the line, the prompt is any non-argument + * text following the command, and the arguments are key-value pairs prefixed + * by "/". + * + * @param line the command line input to be parsed + */ + public void parseCommand(String line) { + prompt = ""; + arguments = new Hashtable<>(); + String[] words = line.trim().split("\\s+"); + command = words[0]; + if (words.length > 1) { + StringBuilder value = new StringBuilder(); + String arg = ""; + boolean isArgument = false; + for (int i = 1; i < words.length; i++) { + if (!words[i].startsWith("/")) { + value.append(words[i]); + value.append(" "); + continue; + } + + if (!isArgument) { + prompt = value.toString().trim(); + } else { + arguments.put(arg, value.toString().trim()); + } + + arg = words[i].substring(1).trim(); + isArgument = true; + value = new StringBuilder(); + } + + if (!isArgument) { + prompt = value.toString().trim(); + } else { + arguments.put(arg, value.toString().trim()); + } + } + } + + /** + * Returns the command extracted from the parsed input. + * + * @return the command as a string + */ + public String getCommand() { + return command; + } + + /** + * Returns the prompt text extracted from the parsed input. + * The prompt is the text that follows the command but is not part of any argument. + * + * @return the prompt as a string + */ + public String getPrompt() { + return prompt; + } + + /** + * Returns the arguments extracted from the parsed input. + * The arguments are stored as key-value pairs in a Hashtable, where each argument + * key is prefixed with "/" in the original input. + * + * @return a Hashtable containing the arguments as key-value pairs + */ + public Hashtable getArguments() { + return arguments; + } +} diff --git a/src/main/java/Storage.java b/src/main/java/Storage.java new file mode 100644 index 000000000..b98e84b27 --- /dev/null +++ b/src/main/java/Storage.java @@ -0,0 +1,103 @@ +import java.io.File; +import java.io.FileWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +public class Storage { + private final String filePath; + private final char DONE_SYMBOL = 'X'; + private final char NOT_DONE_SYMBOL = 'O'; + + public Storage(String filePath) { + this.filePath = filePath; + } + + /** + * Loads the task data from the file at the specified file path. + * The tasks are represented as lines in the file, with each line + * containing the task type, its completion status, and relevant task details. + *

+ * If the file does not exist or an error occurs, an empty list is returned. + * + * @return a list of tasks loaded from the file + */ + public List loadData() { + List data = new ArrayList<>(); + try { + File file = new File(filePath); + if (!file.exists()) { + return data; + } + Scanner s = new Scanner(file); + while (s.hasNextLine()) { + String line = s.nextLine(); + if (line.charAt(1) == 'T') { + Todo todo = new Todo(line.substring(2)); + if (line.charAt(0) == DONE_SYMBOL) todo.mark(); + data.add(todo); + } else if (line.charAt(1) == 'D') { + Deadline deadline = new Deadline(line.substring(2), s.nextLine()); + if (line.charAt(0) == DONE_SYMBOL) deadline.mark(); + data.add(deadline); + } else if (line.charAt(1) == 'E') { + Event event = new Event(line.substring(2), s.nextLine(), s.nextLine()); + if (line.charAt(0) == DONE_SYMBOL) event.mark(); + data.add(event); + } + } + return data; + } catch (Exception e) { + return new ArrayList<>(); + } + } + + /** + * Saves the given list of tasks to the file at the specified file path. + * Each task is saved with its type, completion status, and relevant task details. + *

+ * If the file does not exist, it will be created along with any necessary directories. + * Returns true if the data is successfully saved, or false if an error occurs. + * + * @param taskList the list of tasks to save + * @return true if the data is saved successfully, false otherwise + */ + public boolean saveData(List taskList) { + try { + File file = new File(filePath); + file.getParentFile().mkdirs(); + + FileWriter fw = new FileWriter(file); + StringBuilder sb = new StringBuilder(); + + for (Task task : taskList) { + sb.append(task.isDone() ? DONE_SYMBOL : NOT_DONE_SYMBOL); + if (task instanceof Deadline) { + sb.append('D'); + sb.append(task.getTask()); + sb.append(System.lineSeparator()); + sb.append(((Deadline) task).getBy()); + sb.append(System.lineSeparator()); + } else if (task instanceof Event) { + sb.append('E'); + sb.append(task.getTask()); + sb.append(System.lineSeparator()); + sb.append(((Event) task).getFrom()); + sb.append(System.lineSeparator()); + sb.append(((Event) task).getTo()); + sb.append(System.lineSeparator()); + } else if (task instanceof Todo) { + sb.append('T'); + sb.append(task.getTask()); + sb.append(System.lineSeparator()); + } + } + + fw.write(sb.toString()); + fw.close(); + return true; + } catch (Exception e) { + return false; + } + } +} diff --git a/src/main/java/Task.java b/src/main/java/Task.java new file mode 100644 index 000000000..f9f6fe6cd --- /dev/null +++ b/src/main/java/Task.java @@ -0,0 +1,73 @@ +public class Task { + protected boolean isDone; + protected String task; + + /** + * Represents a task with a description and a completion status. + * The task can be marked as done or not done. + * + * @param task the description of the task + */ + public Task(String task) { + this(task, false); + } + + /** + * Represents a task with a description and a specified completion status. + * The task can be marked as done or not done. + * + * @param task the description of the task + * @param isDone the initial completion status of the task + */ + public Task(String task, boolean isDone) { + this.task = task.trim(); + this.isDone = isDone; + } + + /** + * Returns the description of the task. + * + * @return the task description as a string + */ + public String getTask() { + return task; + } + + /** + * Returns the completion status of the task. + * + * @return true if the task is done, false otherwise + */ + public boolean isDone() { + return isDone; + } + + /** + * Marks the task as done. + */ + public void mark() { + isDone = true; + } + + /** + * Marks the task as not done. + */ + public void unmark() { + isDone = false; + } + + /** + * Returns a string representation of the task, including its completion status + * (marked with "X" for done and " " for not done) and its description. + * + * @return a formatted string representing the task + */ + @Override + public String toString() { + return "[" + + (isDone ? "X" : " ") + + "] " + + task; + } + +} diff --git a/src/main/java/TaskList.java b/src/main/java/TaskList.java new file mode 100644 index 000000000..77b5df327 --- /dev/null +++ b/src/main/java/TaskList.java @@ -0,0 +1,80 @@ +import java.util.ArrayList; +import java.util.List; + +public class TaskList { + private final List tasks; + + /** + * Represents a list of tasks. Provides methods to manage tasks, such as adding, + * removing, retrieving, and searching tasks. + * + * @param tasks the initial list of tasks + */ + public TaskList(List tasks) { + this.tasks = tasks; + } + + /** + * Returns the number of tasks in the task list. + * + * @return the size of the task list + */ + public int getSize() { + return tasks.size(); + } + + /** + * Adds a new task to the task list. + * + * @param task the task to be added + */ + public void addTask(Task task) { + tasks.add(task); + } + + /** + * Searches for tasks that contain the specified keyword in their descriptions. + * The search is case-insensitive and trims leading and trailing spaces. + * + * @param keyword the keyword to search for + * @return a list of tasks that contain the keyword + */ + public List find(String keyword) { + List result = new ArrayList<>(); + for (Task task : tasks) { + if (task.task.toLowerCase().contains(keyword.trim().toLowerCase())) { + result.add(task); + } + } + return result; + } + + /** + * Returns the task at the specified index in the task list. + * + * @param index the index of the task to retrieve + * @return the task at the specified index + */ + public Task getTask(int index) { + return tasks.get(index); + } + + /** + * Removes and returns the task at the specified index in the task list. + * + * @param index the index of the task to remove + * @return the removed task + */ + public Task removeTask(int index) { + return tasks.remove(index); + } + + /** + * Returns the entire list of tasks. + * + * @return the list of tasks + */ + public List getTaskList() { + return tasks; + } +} diff --git a/src/main/java/Todo.java b/src/main/java/Todo.java new file mode 100644 index 000000000..66231c3f5 --- /dev/null +++ b/src/main/java/Todo.java @@ -0,0 +1,22 @@ +public class Todo extends Task { + /** + * Represents a to-do task, which is a simple task without any date or time constraints. + * Extends the Task class to inherit task-related properties and behaviors. + * + * @param task the description of the to-do task + */ + public Todo(String task) { + super(task); + } + + /** + * Returns a string representation of the to-do task in the format "[T] task description", + * including the task description and its completion status. + * + * @return a formatted string representing the to-do task + */ + @Override + public String toString() { + return "[T]" + super.toString(); + } +} diff --git a/src/main/java/Ui.java b/src/main/java/Ui.java new file mode 100644 index 000000000..ec0247c2c --- /dev/null +++ b/src/main/java/Ui.java @@ -0,0 +1,97 @@ +import java.util.List; +import java.util.Scanner; + +public class Ui { + private final String BREAK_LINE = "____________________"; + private final String GREETING_LINE = BREAK_LINE + "\nHello! I'm DBot\nWhat can I do for you?\n" + BREAK_LINE; + Scanner in; + + /** + * Displays a greeting message when the Ui object is initialized. + * Initializes the Scanner to read input from the user. + */ + public Ui() { + in = new Scanner(System.in); + System.out.println(GREETING_LINE); + } + + /** + * Prints a short message surrounded by a break line to format the output. + * + * @param message the message to be printed + */ + public void printShortMessage(String message) { + System.out.println(BREAK_LINE + " Result " + BREAK_LINE); + System.out.println(message); + System.out.println(BREAK_LINE + BREAK_LINE + "\n"); + } + + /** + * Prints a long message or a list of objects surrounded by a break line + * to format the output. Each object is printed on a new line. + * + * @param list an array of objects to be printed + */ + public void printLongMessage(Object[] list) { + System.out.println(BREAK_LINE + " Result " + BREAK_LINE); + for (Object o : list) { + System.out.println(o); + } + System.out.println(BREAK_LINE + BREAK_LINE + "\n"); + } + + private void printError(String message) { + System.out.println(BREAK_LINE + " Error " + BREAK_LINE); + System.out.println(message); + System.out.println(BREAK_LINE + BREAK_LINE + "\n"); + } + + /** + * Prints an error specific to DBot using the details from a DBotException. + * The error includes the type of the error and its cause. + * + * @param error the DBotException containing the error type and message + */ + public void printDBotError(DBotException error) { + printError("Error: " + error.getErrorType() + "\nDue to: " + error.getMessage()); + } + + /** + * Prints a generic error message for undocumented exceptions. + * This is used to handle any unexpected or unhandled exceptions. + * + * @param e the Exception containing the error message + */ + public void printGenericError(Exception e) { + printError("Undocumented error occurred\nDue to: " + e.getMessage()); + } + + /** + * Returns a formatted string representation of the list of tasks. + * Each task is numbered and printed on a new line. + * + * @param tasks the list of tasks to be printed + * @return a string containing the formatted list of tasks + */ + public String listTasks(List tasks) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < tasks.size(); i++) { + sb.append(i + 1); + sb.append(". "); + sb.append(tasks.get(i).toString()); + sb.append('\n'); + } + return sb.toString().trim(); + } + + /** + * Reads a line of input from the user after printing a "Command:" prompt. + * + * @return the user's input as a string, with leading and trailing whitespace removed + */ + public String readLine() { + System.out.print("Command: "); + return in.nextLine().strip(); + } + +}