diff --git a/.gitignore b/.gitignore index 2873e189e..e8510ae46 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ bin/ /text-ui-test/ACTUAL.TXT text-ui-test/EXPECTED-UNIX.TXT +Erii.jar \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..001c4361e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.checkstyle.configuration": "/sun_checks.xml" +} \ No newline at end of file diff --git a/README.md b/README.md index 8715d4d91..ca31d7f81 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,50 @@ -# 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 - ____ _ - | _ \ _ _| | _____ - | | | | | | | |/ / _ \ - | |_| | |_| | < __/ - |____/ \__,_|_|\_\___| - ``` +# User Guide for the Erii Application + +## Introduction +Welcome to the Erii application, your comprehensive assistant for managing tasks and personal data at Kassel Academy. Designed with ease of use in mind, Erii helps you keep track of your daily tasks, manage your personal details, and interact seamlessly with the Kassel Academy's database. + +## Getting Started +### System Requirements +- Java Runtime Environment (JRE) version 11 or higher. +- An active internet connection for initial setup and database synchronization (if applicable). + +### Installation +1. Ensure Java is installed on your computer by running `java -version` in your command line or terminal. +2. Download `Erii.jar` to a convenient location on your computer. +3. Launch the application by double-clicking the file or executing `java -jar Erii.jar` in your command line or terminal. + +## Main Features +### User Registration and Login +- Initial Setup: Upon first launch, you'll be prompted to enter your personal details, including name, birthday, and gender. This information is crucial for personalizing your experience with Erii. +- Welcome Back Message: Returning users are greeted with a welcome back message, streamlining the login process. + +### Task Management +- Task Overview: Erii provides a comprehensive task management system. View, create, and track tasks tailored to your academic or personal needs. +- Loading Tasks: Your tasks are loaded upon application startup, ensuring you're immediately up to date with your schedule. + +### Data Storage and Retrieval +- Secure Data Storage: Personal details and tasks are securely stored, with the ability to retrieve and update information as needed. +- Synchronization: Erii ensures your data is always synchronized, keeping your schedule and personal details up to date. + +### Personalized Interaction +- Customized Greetings and Messages: Receive personalized messages based on your user profile, including verification status, rank, and course schedule. + +### Control Panel +- User Interface: Erii's Control Panel provides an intuitive interface for managing your tasks and personal details, designed for ease of use and efficiency. + +## Navigating the Control Panel +The Control Panel is the heart of your interaction with Erii. From here, you can access all the features of the application. +- Task List: Access your list of tasks from the main interface. +- Add Task: Create various task types, from deadline to event tasks. +- Mark Task: Mark a Task as done. +- Search Task: Search tasks by keyword or by date. + +## FAQs +- Q: How do I update my personal information? + - A: Navigate to the User Details section in the Control Panel to update your information. + +- Q: What should I do if I encounter errors or need support? + - A: Please contact Kassel Academy's technical support team for assistance with any issues or questions. + +## Conclusion +Erii is designed to enhance your productivity and streamline your interactions with Kassel Academy. By effectively managing your tasks and personal details, you can focus on your academic goals and personal development. Welcome to a more organized and efficient way of managing your daily activities with Erii. diff --git a/data/641 (D) - Shortcut.lnk b/data/641 (D) - Shortcut.lnk new file mode 100644 index 000000000..e6274d43b Binary files /dev/null and b/data/641 (D) - Shortcut.lnk differ diff --git a/data/tasks.txt b/data/tasks.txt new file mode 100644 index 000000000..e69de29bb diff --git a/data/userDetails.txt b/data/userDetails.txt new file mode 100644 index 000000000..e69de29bb diff --git a/docs/README.md b/docs/README.md index 8077118eb..816182640 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,29 +1,112 @@ # User Guide +Welcome to the comprehensive User Guide for your application. This guide will walk you through the features and usage instructions to help you get the most out of your application. -## Features +## Features +### Feature-Greeting -### Feature-ABC +**Description:** -Description of the feature. +This feature initiates a user-friendly interaction by prompting new users to enter their name, birthday, and gender directly through the console. After receiving the inputs, it generates a personalized welcome message that incorporates the user's provided details, simulating a verification and enrollment process to an exclusive roster - in this case, the fictional Kassel Academy. This introductory procedure not only greets the user but also seamlessly collects essential information for a customized experience. -### Feature-XYZ +### Feature-Read in and Save Basic Info of the User -Description of the feature. +**Description:** + +This feature allows the application to collect and store basic information about the user, such as their name, birthday, gender, and preferences. This personalized information helps in tailoring the application's functionality and responses to fit the user's needs, enhancing the overall user experience. ## Usage +### 'inputName' - Enter User Name + +**Description:** + +Prompts the user to input their full name (First Name Last Name). The application validates the input to ensure it includes both names, enhancing the personalized interaction. + +**Example of usage:** + +Please enter your full name (First Name Last Name): John Doe + +**Expected outcome:** + + The user's name is stored and utilized for personalized greetings and interactions within the application. +Welcome, John Doe! Your name has been recorded. + +### inputBirthday - Enter Birthday + +**Description:** + +Ask the user to input their birthday in a specific format (DD/MM/YYYY). This information is crucial for personalized messages and functionalities related to the user's age or significant dates. + +**Example of usage:** + +Please enter your birthday (DD/MM/YYYY): 01/01/1990 + +**Expected outcome:** + +The application stores the user's birthday for age-related functionalities and personalized greetings. ++ Your birthday, 01/01/1990, has been saved successfully. + +### inputGender - Select Gender + +**Description:** + +The user is prompted to select their gender from predefined options. This feature allows for more tailored interactions and can be used to personalize the user experience further. + +**Example of usage:** + +Please enter your gender: 1. Male 2. Female 3. Other +**Expected outcome:** + +The application records the user's gender selection, which can be used for personalized communication and functionalities. + +Your gender, Male/Female/Other, has been recorded. + +### addTask - Add a New Task + +**Description:** + +Allows users to add tasks to their list by entering a description and selecting a priority level. This feature is central to the task management functionality of the application. + +**Example of usage:** + +addTask Complete the project report /S + +**Expected outcome:** + +The task is added to the user's list with the specified priority, enhancing their productivity and task management. + +Got it. I've added this task: Complete the project report + +Now you have [number] tasks in the list. + +### listTasks - List All Tasks + +**Description:** + +Displays all tasks currently in the user's list, providing a comprehensive overview of pending, completed, and scheduled tasks. + +**Example of usage:** + +listTasks + +**Expected outcome:** + +A list of all tasks, along with their details such as status, description, and priority, is displayed to the user. + +Here are the tasks in your list: +1. [T][ ] Complete the project report -### `Keyword` - Describe action +### markTaskAsDone - Mark a Task as Done -Describe the action and its outcome. +**Description:** +Enables users to mark a task as completed by specifying the task number. This feature helps users keep track of their progress. -Example of usage: +**Example of usage:** -`keyword (optional arguments)` +markTaskAsDone 1 -Expected outcome: +**Expected outcome:** -Description of the outcome. +The specified task is marked as completed, and its status is updated in the task list. -``` -expected output -``` +- Task 1 marked as done. +This guide should help you navigate through the application's features and functionalities. Enjoy managing your tasks and personalizing your experience with our 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/com/erii/Main.java b/src/main/java/com/erii/Main.java new file mode 100644 index 000000000..0c5222df1 --- /dev/null +++ b/src/main/java/com/erii/Main.java @@ -0,0 +1,50 @@ +package com.erii; +import java.util.List; +import com.erii.core.Erii; +import com.erii.core.TaskManager; +import com.erii.user.UserDetails; +import com.erii.data.DataStorage; +import com.erii.ui.ControlPanel; + +/** + * The main class of the program. + * It initializes the necessary objects and starts the program execution. + */ +public class Main { + public static void main(String[] args) { + DataStorage storage = new DataStorage(); + TaskManager taskManager = new TaskManager(); + UserDetails userDetails = storage.loadUserDetails(); + ControlPanel controlPanel = new ControlPanel(taskManager, storage, userDetails); + + Erii.main(args); + + System.out.println("Initializing Kassel Academy..."); + + if (userDetails == null || userDetails.getUserName() == null || userDetails.getUserName().isEmpty()) { + userDetails = new UserDetails(); + userDetails.inputName(); + userDetails.inputBirthday(); + userDetails.inputGender(); + storage.saveUserDetails(userDetails); + String message = String.format( + "Verification passed.\nOptions enabled.\n%s Born on %s\n%s\nID A.D.0013\n" + + "Rank 'S'\nListed in the Kassel Academy roster.\n" + + "Database access granted\nAccount activated\nCourse schedule generated\n" + + "I am Erii, the secretary of Kassel Academy, pleased to serve you.", + userDetails.getUserName(), userDetails.getUserBirthday(), userDetails.getUserGender()); + System.out.println(message); + } else { + String message = "Welcome back, " + userDetails.getUserName(); + System.out.println(message); + } + + List loadedTasks = storage.loadTasks(taskManager); + for (TaskManager.Task task : loadedTasks) { + taskManager.loadTask(task); + } + taskManager.listTasks(); + + controlPanel.start(); + } +} \ No newline at end of file diff --git a/src/main/java/com/erii/core/Erii.java b/src/main/java/com/erii/core/Erii.java new file mode 100644 index 000000000..83b944deb --- /dev/null +++ b/src/main/java/com/erii/core/Erii.java @@ -0,0 +1,33 @@ +package com.erii.core; + +/** + * The Erii class represents a program that prints out the ASCII art of the word "Erii". + * It contains the main method which executes the program. + */ +public class Erii { + public static void main(String[] args) { + String art = + " _____ _____ _____ _____ \n" + + " /\\ \\ /\\ \\ /\\ \\ /\\ \\ \n" + + " /::\\ \\ /::\\ \\ /::\\ \\ /::\\ \\ \n" + + " /::::\\ \\ /::::\\ \\ \\:::\\ \\ \\:::\\ \\ \n" + + " /::::::\\ \\ /::::::\\ \\ \\:::\\ \\ \\:::\\ \\ \n" + + " /:::/\\:::\\ \\ /:::/\\:::\\ \\ \\:::\\ \\ \\:::\\ \\ \n" + + " /:::/__\\:::\\ \\ /:::/__\\:::\\ \\ \\:::\\ \\ \\:::\\ \\ \n" + + " /::::\\ \\:::\\ \\ /::::\\ \\:::\\ \\ /::::\\ \\ /::::\\ \\ \n" + + "/::::::\\ \\:::\\ \\ /::::::\\ \\:::\\ \\ ____ /::::::\\ \\ ____ /::::::\\ \\ \n" + + "/:::/\\:::\\ \\:::\\ \\ /:::/\\:::\\ \\:::\\____\\ /\\ \\ /:::/\\:::\\ \\ /\\ \\ /:::/\\:::\\ \\ \n" + + "/:::/__\\:::\\ \\:::\\____\\/:::/ \\:::\\ \\:::| |/::\\ \\/:::/ \\:::\\____\\/::\\ \\/:::/ \\:::\\____\\\n" + + "\\:::\\ \\:::\\ \\::/ /\\::/ |::::\\ /:::|____|\\:::\\ /:::/ \\::/ /\\:::\\ /:::/ \\::/ /\n" + + " \\:::\\ \\:::\\ \\/____/ \\/____|:::::\\/:::/ / \\:::\\/:::/ / \\/____/ \\:::\\/:::/ / \\/____/ \n" + + " \\:::\\ \\:::\\ \\ |:::::::::/ / \\::::::/ / \\::::::/ / \n" + + " \\:::\\ \\:::\\____\\ |::|\\::::/ / \\::::/____/ \\::::/____/ \n" + + " \\:::\\ \\::/ / |::| \\::/____/ \\:::\\ \\ \\:::\\ \\ \n" + + " \\:::\\ \\/____/ |::| ~| \\:::\\ \\ \\:::\\ \\ \n" + + " \\:::\\ \\ |::| | \\:::\\ \\ \\:::\\ \\ \n" + + " \\:::\\____\\ \\::| | \\:::\\____\\ \\:::\\____\\ \n" + + " \\::/ / \\:| | \\::/ / \\::/ / \n" + + " \\/____/ \\|___| \\/____/ \\/____/ \n"; + System.out.println(art); + } +} diff --git a/src/main/java/com/erii/core/TaskManager.java b/src/main/java/com/erii/core/TaskManager.java new file mode 100644 index 000000000..af5932abd --- /dev/null +++ b/src/main/java/com/erii/core/TaskManager.java @@ -0,0 +1,483 @@ +package com.erii.core; + +import java.util.ArrayList; +import java.util.List; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * The TaskManager class represents a task management system that allows users to manage tasks. + * It provides functionality to add tasks, list tasks, mark tasks as done, delete tasks, and search for tasks. + * Tasks can be of different types, such as Todo, Deadline, and Event, each with its own properties and behaviors. + */ + +public class TaskManager { + + /** + * The Priority enum represents the priority levels of a task. + */ + public enum Priority { + SS, S, A, B, C, D + } + + /** + * The Task class represents a generic task. + */ + public abstract class Task { + protected String name; + protected String description; + protected Priority priority; + + /** + * Constructs a Task object with the specified name, description, and priority. + * + * @param name the name of the task + * @param description the description of the task + * @param priority the priority of the task + */ + public Task(final String name, final String description, final Priority priority) { + this.name = name; + this.description = description; + this.priority = priority; + } + + /** + * Returns the name of the task. + * + * @return the name of the task + */ + public String getName() { + return name; + } + + /** + * Returns the description of the task. + * + * @return the description of the task + */ + public String getDescription() { + return description; + } + + /** + * Returns the priority of the task. + * + * @return the priority of the task + */ + public Priority getPriority() { + return priority; + } + + /** + * Sets the priority of the task. + * + * @param priority the priority to be set + */ + public void setPriority(final Priority priority) { + this.priority = priority; + } + + /** + * Returns the status icon of the task. + * + * @return the status icon of the task + */ + public abstract String getStatusIcon(); + + /** + * Returns a string representation of the task. + * + * @return a string representation of the task + */ + @Override + public abstract String toString(); + } + + /** + * The Todo class represents a todo task. + */ + public class Todo extends Task { + protected boolean isDone; + + /** + * Constructs a Todo object with the specified name, description, and priority. + * + * @param name the name of the todo task + * @param description the description of the todo task + * @param priority the priority of the todo task + */ + public Todo(final String name, final String description, final Priority priority) { + super(name, description, priority); + isDone = false; + } + + /** + * Sets the done status of the todo task. + * + * @param done the done status to be set + */ + public void setDone(final boolean done) { + isDone = done; + } + + /** + * Returns the done status of the todo task. + * + * @return the done status of the todo task + */ + public boolean isDone() { + return isDone; + } + + /** + * Returns the status icon of the todo task. + * + * @return the status icon of the todo task + */ + @Override + public String getStatusIcon() { + return (isDone ? "[X]" : "[ ]"); + } + + /** + * Returns a string representation of the todo task. + * + * @return a string representation of the todo task + */ + @Override + public String toString() { + return "[T]" + getStatusIcon() + " " + description + " <" + priority + "> "; + } + } + + /** + * The Deadline class represents a deadline task. + */ + public class Deadline extends Todo { + protected LocalDateTime by; + + /** + * Constructs a Deadline object with the specified name, description, deadline, + * and priority. + * + * @param name the name of the deadline task + * @param description the description of the deadline task + * @param by the deadline of the deadline task + * @param priority the priority of the deadline task + */ + public Deadline(final String name, final String description, final LocalDateTime by, final Priority priority) { + super(name, description, priority); + this.by = by; + } + + /** + * Returns the deadline of the deadline task. + * + * @return the deadline of the deadline task + */ + public LocalDateTime getBy() { + return this.by; + } + + /** + * Sets the deadline of the deadline task. + * + * @param by the deadline to be set + */ + public void setBy(final LocalDateTime by) { + this.by = by; + } + + /** + * Returns a string representation of the deadline task. + * + * @return a string representation of the deadline task + */ + @Override + public String toString() { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd yyyy"); + String formattedDate = by.format(formatter); + return "[D]" + super.getStatusIcon() + " " + description + " <" + priority + "> " + " (by: " + formattedDate + + ")"; + } + } + + /** + * The Event class represents an event task. + */ + public class Event extends Todo { + protected boolean isDone; + protected LocalDate start; + protected LocalDate end; + + /** + * Constructs an Event object with the specified name, description, start date, + * end date, and priority. + * + * @param name the name of the event task + * @param description the description of the event task + * @param start the start date of the event task + * @param end the end date of the event task + * @param priority the priority of the event task + */ + public Event(final String name, final String description, final LocalDate start, final LocalDate end, + final Priority priority) { + super(name, description, priority); + this.start = start; + this.end = end; + } + + /** + * Sets the done status of the event task. + * + * @param done the done status to be set + */ + public void setDone(final boolean done) { + isDone = done; + } + + /** + * Returns the start date of the event task. + * + * @return the start date of the event task + */ + public LocalDate getStart() { + return this.start; + } + + /** + * Returns the end date of the event task. + * + * @return the end date of the event task + */ + public LocalDate getEnd() { + return this.end; + } + + /** + * Returns the status icon of the event task. + * + * @return the status icon of the event task + */ + @Override + public String getStatusIcon() { + return isDone ? "[X]" : "[ ]"; + } + + /** + * Returns a string representation of the event task. + * + * @return a string representation of the event task + */ + @Override + public String toString() { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMM dd yyyy"); + return "[E]" + getStatusIcon() + " " + description + " <" + priority + "> " + " (from: " + + start.format(formatter) + " to: " + end.format(formatter) + ")"; + } + } + + private List tasks = new ArrayList<>(); + + /** + * Returns the size of the task list. + * + * @return the size of the task list + */ + public int listSize() { + return tasks.size(); + } + + /** + * Adds a task to the task list. + * + * @param task the task to be added + */ + public void addTask(final Task task) { + tasks.add(task); + System.out.println("\nGot it. I've added this task:"); + System.out.println(" " + task); + System.out.println("\nNow you have " + tasks.size() + " tasks in the list."); + System.out.println("____________________________________________________________"); + } + + /** + * Loads a task from Text to the task list. + * + * @param task the task to be loaded + */ + public void loadTask(final Task task) { + tasks.add(task); + } + + /** + * Lists all tasks in the task list. + */ + public void listTasks() { + System.out.println("\nHere are the tasks in your list:"); + for (int i = 0; i < tasks.size(); i++) { + System.out.println((i + 1) + "." + tasks.get(i)); + } + System.out.println("____________________________________________________________"); + } + + /** + * Sorts the task list by priority. + */ + public void sortListByPriority() { + tasks.sort((Task t1, Task t2) -> t1.getPriority().compareTo(t2.getPriority())); + System.out.println("\nTasks sorted by priority."); + } + + /** + * Sorts the task list by type. + */ + public void sortListByType() { + tasks.sort((Task t1, Task t2) -> t1.getName().compareTo(t2.getName())); + System.out.println("\nTasks sorted by type."); + } + + /** + * Marks a task as done. + * + * @param taskIndex the index of the task to be marked as done + */ + public void markTaskAsDone(final int taskIndex) { + if (taskIndex >= 0 && taskIndex < tasks.size()) { + Task task = tasks.get(taskIndex); + if (task instanceof Todo) { + ((Todo) task).setDone(true); + } else if (task instanceof Event) { + ((Event) task).setDone(true); + } else { + System.out.println("\nThis task type cannot be marked as done."); + return; + } + System.out.println("----------------------------------"); + System.out.println("\nTask completed"); + System.out.println(task); + System.out.println("--------------------------------------"); + } else { + System.out.println("\nInvalid task number."); + } + } + + /** + * Deletes a task from the task list. + * + * @param taskIndex the index of the task to be deleted + */ + public void deleteTask(final int taskIndex) { + if (taskIndex >= 0 && taskIndex < tasks.size()) { + Task task = tasks.remove(taskIndex); + System.out.println("\nNoted. I've removed this task:"); + System.out.println(" " + task); + System.out.println("\nNow you have " + tasks.size() + " tasks in the list."); + System.out.println("____________________________________________________________"); + } else { + System.out.println("Invalid task number."); + } + } + + /** + * Returns a copy of all tasks in the task list. + * + * @return a copy of all tasks in the task list + */ + public List getAllTasks() { + return new ArrayList<>(tasks); + } + + /** + * Lists deadline tasks on a specific datetime. + * + * @param datetime the datetime to filter deadline tasks + */ + public void listTasksOn(final LocalDateTime datetime) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MMM yyyy HH:mm"); + System.out.println("\nDeadline Tasks on " + datetime.format(formatter) + ":"); + + boolean found = false; + for (Task task : tasks) { + if (task instanceof Deadline) { + LocalDateTime taskDatetime = ((Deadline) task).getBy(); + if (taskDatetime.isEqual(datetime)) { + System.out.println(task); + found = true; + } + } + } + + if (!found) { + System.out.println("No deadline tasks found for this date and time."); + } + } + + /** + * Lists event tasks occurring on a specific date. + * + * @param date the date to filter event tasks + */ + public void listTasksOn(final LocalDate date) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd MMM yyyy"); + System.out.println("\nEvent Tasks on " + date.format(formatter) + ":"); + + boolean found = false; + for (Task task : tasks) { + if (task instanceof Event) { + LocalDate startDate = ((Event) task).getStart(); + LocalDate endDate = ((Event) task).getEnd(); + if ((date.isEqual(startDate) || date.isAfter(startDate)) + && (date.isEqual(endDate) || date.isBefore(endDate))) { + System.out.println(task); + found = true; + } + } + } + + if (!found) { + System.out.println("No event tasks found for this date."); + } + } + + /** + * Searches tasks by keyword and prints the matching tasks. + * + * @param keyword the keyword to search for + */ + public void findTasks(final String keyword) { + System.out.println("____________________________________________________________"); + System.out.println("\nHere are the matching tasks in your list:"); + + int matchCount = 0; + for (int i = 0; i < tasks.size(); i++) { + Task task = tasks.get(i); + if (task.getDescription().toLowerCase().contains(keyword.toLowerCase())) { + System.out.println((i + 1) + "." + task); + matchCount++; + } + } + + if (matchCount == 0) { + System.out.println("\nNo matching tasks found."); + } + + System.out.println("____________________________________________________________"); + } + + /** + * Validates and converts a priority string to a Priority enum. + * + * @param priorityString the priority string to be validated and converted + * @return the corresponding Priority enum value + * @throws IllegalArgumentException if the priority string is invalid + */ + public static Priority validateAndConvertPriority(final String priorityString) throws IllegalArgumentException { + try { + return Priority.valueOf(priorityString.toUpperCase()); + } catch (IllegalArgumentException e) { + throw e; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/erii/data/DataStorage.java b/src/main/java/com/erii/data/DataStorage.java new file mode 100644 index 000000000..2a8bdc155 --- /dev/null +++ b/src/main/java/com/erii/data/DataStorage.java @@ -0,0 +1,198 @@ +package com.erii.data; + +import com.erii.core.TaskManager; +import com.erii.core.TaskManager.Task; +import com.erii.user.UserDetails; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.PrintWriter; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +/** + * The DataStorage class is responsible for saving and loading data from files. + * It provides methods to save and load tasks and user details. + */ +public class DataStorage { + private static final String TASKS_FILE = "./data/tasks.txt"; + private static final String USER_DETAILS_FILE = "./data/userDetails.txt"; + + /** + * Save tasks to a file + * + * @param tasks The list of tasks to be saved + */ + public void saveTasks(List tasks) { + try (PrintWriter writer = new PrintWriter(new File(TASKS_FILE))) { + for (Task task : tasks) { + writer.println(taskToFileString(task)); + } + } catch (IOException e) { + System.out.println("An error occurred while saving tasks: " + e.getMessage()); + } + } + + /** + * Load tasks from a file + * + * @param taskManager The task manager instance + * @return The list of loaded tasks + */ + public List loadTasks(TaskManager taskManager) { + List tasks = new ArrayList<>(); + try (Scanner scanner = new Scanner(new File(TASKS_FILE))) { + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + if (line.trim().isEmpty()) continue; + Task task = fileStringToTask(line, taskManager); + if (task != null) { + tasks.add(task); + } + } + } catch (FileNotFoundException e) { + System.out.println("Tasks file not found. Starting with an empty task list."); + } + return tasks; + } + + /** + * Save user details to a file + * + * @param userDetails The user details to be saved + */ + public void saveUserDetails(UserDetails userDetails) { + File file = new File(USER_DETAILS_FILE); + File parentDir = file.getParentFile(); + if (!parentDir.exists()) { + parentDir.mkdirs(); + } + try (PrintWriter writer = new PrintWriter(file)) { + writer.println(userDetails.getUserName()); + writer.println(userDetails.getUserBirthday()); + writer.println(userDetails.getUserGender()); + } catch (IOException e) { + System.out.println("An error occurred while saving user details: " + e.getMessage()); + } + } + + /** + * Load user details from a file + * + * @return The loaded user details + */ + public UserDetails loadUserDetails() { + UserDetails userDetails = new UserDetails(); + try (Scanner scanner = new Scanner(new File(USER_DETAILS_FILE))) { + if (scanner.hasNextLine()) { + userDetails.setUserName(scanner.nextLine()); + } else { + System.out.println("User name not found in file."); + } + if (scanner.hasNextLine()) { + userDetails.setUserBirthday(scanner.nextLine()); + } else { + System.out.println("User birthday not found in file."); + } + if (scanner.hasNextLine()) { + userDetails.setUserGender(scanner.nextLine()); + } else { + System.out.println("User gender not found in file."); + } + } catch (FileNotFoundException e) { + System.out.println("User details file not found. Starting with default user details."); + } + return userDetails; + } + + /** + * Convert a Task object to a string representation + * + * @param task The Task object + * @return The string representation of the task + */ + private String taskToFileString(Task task) { + DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + + String taskType; + if (task instanceof TaskManager.Deadline) { + taskType = "D"; + } else if (task instanceof TaskManager.Event) { + taskType = "E"; + } else if (task instanceof TaskManager.Todo) { + taskType = "T"; + } else { + taskType = "Unknown"; + } + String status = task instanceof TaskManager.Todo && ((TaskManager.Todo) task).isDone() ? "1" : "0"; + String priority = task.getPriority().name(); + String description = task.getDescription(); + String dateInfo = ""; + + if (task instanceof TaskManager.Deadline) { + LocalDateTime by = ((TaskManager.Deadline) task).getBy(); + dateInfo = "|" + by.format(dateTimeFormatter); + } else if (task instanceof TaskManager.Event) { + LocalDate start = ((TaskManager.Event) task).getStart(); + LocalDate end = ((TaskManager.Event) task).getEnd(); + dateInfo = "|" + start.format(dateFormatter) + "|" + end.format(dateFormatter); + } + + return String.join("|", taskType, status, priority, description) + dateInfo; + } + + /** + * Convert a string representation of a task to a Task object + * + * @param line The string representation of the task + * @param taskManager The task manager instance + * @return The Task object + */ + private Task fileStringToTask(String line, TaskManager taskManager) { + String[] parts = line.split("\\|"); + String taskType = parts[0]; + boolean isDone = parts[1].equals("1"); + TaskManager.Priority priority = TaskManager.Priority.valueOf(parts[2]); + String description = parts[3]; + + DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + + switch (taskType) { + case "T": + TaskManager.Todo todo = taskManager.new Todo("Todo", description, priority); + todo.setDone(isDone); + return todo; + case "D": + try { + LocalDateTime byDate = LocalDateTime.parse(parts[4], dateTimeFormatter); + TaskManager.Deadline deadline = taskManager.new Deadline("Deadline", description, byDate, priority); + deadline.setDone(isDone); + return deadline; + } catch (DateTimeParseException e) { + System.out.println("Error parsing the deadline date: " + e.getMessage()); + return null; + } + case "E": + try { + LocalDate startDate = LocalDate.parse(parts[4], dateFormatter); + LocalDate endDate = LocalDate.parse(parts[5], dateFormatter); + TaskManager.Event event = taskManager.new Event("Event", description, startDate, endDate, priority); + event.setDone(isDone); + return event; + } catch (DateTimeParseException e) { + System.out.println("Error parsing event dates: " + parts[4] + " to " + parts[5]); + return null; + } + default: + return null; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/erii/exception/DateTimeNotAfterCurrentTimeException.java b/src/main/java/com/erii/exception/DateTimeNotAfterCurrentTimeException.java new file mode 100644 index 000000000..252ceddbe --- /dev/null +++ b/src/main/java/com/erii/exception/DateTimeNotAfterCurrentTimeException.java @@ -0,0 +1,8 @@ +package com.erii.exception; + +public class DateTimeNotAfterCurrentTimeException extends RuntimeException { + public DateTimeNotAfterCurrentTimeException(String message) { + super(message); + } +} + diff --git a/src/main/java/com/erii/ui/ControlPanel.java b/src/main/java/com/erii/ui/ControlPanel.java new file mode 100644 index 000000000..69e6f98ad --- /dev/null +++ b/src/main/java/com/erii/ui/ControlPanel.java @@ -0,0 +1,316 @@ +package com.erii.ui; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.Scanner; + +import com.erii.user.UserDetails; +import com.erii.core.TaskManager; +import com.erii.data.DataStorage; +import com.erii.util.DateValidator; +import com.erii.util.DateTimeValidator; +import com.erii.exception.DateTimeNotAfterCurrentTimeException; + +/** + * The ControlPanel class represents the user interface control panel for managing tasks. + * It provides options for listing tasks, adding tasks, marking tasks as done, deleting tasks, + * and searching for tasks. It interacts with the TaskManager, DataStorage, and UserDetails classes. + */ +public class ControlPanel { + private TaskManager taskManager; + private DataStorage storage; + private UserDetails userDetails; + + /** + * Constructs a ControlPanel object with the specified task manager, data storage, and user details. + * + * @param taskManager the task manager to be used + * @param storage the data storage to be used + * @param userDetails the user details to be used + */ + public ControlPanel(TaskManager taskManager, DataStorage storage, UserDetails userDetails) { + this.taskManager = taskManager; + this.storage = storage; + this.userDetails = userDetails; + } + + /** + * Starts the control panel and handles user input. + */ + public void start() { + try (Scanner scanner = new Scanner(System.in)) { + menu(); + + while (scanner.hasNextLine()) { + String choice = scanner.nextLine().trim(); + + switch (choice) { + case "1": + listTasks(); + break; + case "2": + System.out.println("\nPlease enter the task description and priority (e.g., slain a dragon /S):"); + String inputAddTask = scanner.nextLine().trim(); + addTodoTask(inputAddTask); + break; + case "3": + System.out.println("\nPlease enter the deadline task description, deadline date and priority (e.g., submit report /by 2021-09-30 18:30 /SS):"); + String inputAddDeadline = scanner.nextLine().trim(); + addDeadlineTask(inputAddDeadline); + break; + case "4": + System.out.println("\nPlease enter the event description, start date, end date and priority (e.g., project meeting /from 2021-09-30 /to 2021-10-01 /S):"); + String inputAddEvent = scanner.nextLine().trim(); + addEventTask(inputAddEvent); + break; + case "5": + System.out.println("\nPlease enter the task number to mark as done:"); + String inputMark = scanner.nextLine().trim(); + markTaskAsDone(inputMark); + break; + case "6": + System.out.println("\nChoose the task you want to delete: "); + String inputDelete = scanner.nextLine().trim(); + deleteTask(inputDelete); + break; + case "7": + searchByDate(scanner); + break; + case "8": + System.out.println("\nEnter a keyword to search for tasks:"); + String keyword = scanner.nextLine().trim(); + taskManager.findTasks(keyword); + break; + case "X": + System.out.println("\nSaving changes..."); + System.out.println("----------------------------------"); + storage.saveUserDetails(userDetails); + System.out.println("\nChanges saved. Exiting."); + System.out.println("----------------------------------"); + System.out.println("\nThank you for using Erii. さよăȘら!"); + scanner.close(); + return; + default: + System.out.println("\nUnknown command. Please try again."); + break; + } + + menu(); + } + } + } + + /** + * Displays the menu options. + */ + private static void menu() { + System.out.println("\nHow may I assist you today?"); + System.out.println("1. List tasks"); + System.out.println("2. Add a task"); + System.out.println("3. Add a deadline task"); + System.out.println("4. Add an event task"); + System.out.println("5. Mark a task as done"); + System.out.println("6. Delete a task"); + System.out.println("7. List tasks on a specific date"); + System.out.println("8. Search for a task by keyword"); + System.out.println("X. Exit"); + System.out.print("Enter the symbol corresponding to your choice: \n"); + } + + /** + * Lists all tasks. + */ + private void listTasks() { + taskManager.listTasks(); + } + + /** + * Adds a todo task with the given input. + * + * @param input the input string containing the task description and priority + */ + private void addTodoTask(String input) { + String[] parts = input.split(" ?/ ?"); + if (parts.length < 2 || parts[1].isEmpty()) { + System.out.println("\n\"Incorrect format. Please ensure the task description is followed by '/' and a priority value (e.g., 'slain a dragon /SS').\""); + return; + } + String description = parts[0]; + TaskManager.Priority priority; + try { + priority = TaskManager.Priority.valueOf(parts[1].trim().toUpperCase()); + } catch (IllegalArgumentException e) { + System.out.println("\nInvalid priority. Please enter a valid priority value (SS, S, A, B, C, D, E)."); + return; + } + taskManager.addTask(taskManager.new Todo("Todo", description, priority)); + storage.saveTasks(taskManager.getAllTasks()); + } + + /** + * Adds a deadline task with the given input. + * + * @param input the input string containing the task description, deadline date, and priority + */ + private void addDeadlineTask(String input) { + String[] parts = input.split(" ?/by | ?/ ?"); + if (parts.length < 3) { + System.out.println("\nIncorrect format. Please follow the correct input format 'description /by yyyy-MM-dd HH:mm /priority'."); + return; + } + String description = parts[0]; + String dateTimeString = parts[1]; + LocalDateTime by; + try { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + by = LocalDateTime.parse(dateTimeString, formatter); + } catch (DateTimeParseException e) { + System.out.println("\nInvalid date and time. Please enter in yyyy-MM-dd HH:mm format."); + return; + } + try { + DateTimeValidator.validateDateTimeIsAfterCurrentTime(by); + } catch (DateTimeNotAfterCurrentTimeException e) { + System.out.println("\nInvalid date and time. Please enter a date and time after the current date and time."); + return; + } + TaskManager.Priority priority; + try { + priority = TaskManager.Priority.valueOf(parts[2].trim().toUpperCase()); + taskManager.addTask(taskManager.new Deadline("Deadline", description, by, priority)); + storage.saveTasks(taskManager.getAllTasks()); + } catch (IllegalArgumentException e) { + System.out.println("\nInvalid priority. Please enter a valid priority value (SS, S, A, B, C, D, E)."); + return; + } + } + + /** + * Adds an event task with the given input. + * + * @param input the input string containing the task description, start date, end date, and priority + */ + private void addEventTask(String input) { + String[] parts = input.split(" ?/from | ?/to | ?/"); + if (parts.length < 4) { + System.out.println("\nIncorrect format. Please ensure the task description is followed by '/from', a start date, '/to', an end date, and then a priority value."); + return; + } + String description = parts[0]; + String startDateString = parts[1]; + String endDateString = parts[2]; + TaskManager.Priority priority; + + try { + DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + LocalDate startDate = LocalDate.parse(startDateString, dateFormatter); + LocalDate endDate = LocalDate.parse(endDateString, dateFormatter); + DateValidator.validateDateIsAfterCurrentTime(startDate); + if(!endDate.isAfter(startDate)) { + throw new DateTimeNotAfterCurrentTimeException("\nThe end date must be after the start date."); + } + priority = TaskManager.Priority.valueOf(parts[3].trim().toUpperCase()); + taskManager.addTask(taskManager.new Event("Event", description, startDate, endDate, priority)); + storage.saveTasks(taskManager.getAllTasks()); + } catch (DateTimeParseException e) { + System.out.println("\nInvalid date format. Please enter the date in yyyy-MM-dd format."); + return; + } catch (DateTimeNotAfterCurrentTimeException e) { + System.out.println(e.getMessage()); + return; + } catch (IllegalArgumentException e) { + System.out.println("\nInvalid priority. Please enter a valid priority value (SS, S, A, B, C, D, E)."); + return; + } + } + + + /** + * Marks a task as done with the given input. + * + * @param input the input string containing the task number1 + */ + private void markTaskAsDone(String input) { + try { + int taskNumber = Integer.parseInt(input)-1; + if (taskNumber < 0 || taskNumber >= taskManager.listSize()) { + System.out.println("\nTask number is out of range. Please enter a valid task number."); + System.out.println("\nCurrent number of tasks: " + taskManager.listSize()); + return; + } + taskManager.markTaskAsDone(taskNumber); + storage.saveTasks(taskManager.getAllTasks()); + } catch (NumberFormatException e) { + System.out.println("\nPlease enter a valid task number."); + } + } + + /** + * Deletes a task with the given input. + * + * @param input the input string containing the task number + */ + private void deleteTask(String input) { + try { + int taskNumber = Integer.parseInt(input) - 1; + if (taskNumber < 0 || taskNumber >= taskManager.listSize()) { + System.out.println("\nTask number is out of range. Please enter a valid task number."); + System.out.println("\nCurrent number of tasks: " + taskManager.listSize()); + return; + } + taskManager.deleteTask(taskNumber); + storage.saveTasks(taskManager.getAllTasks()); + } catch (NumberFormatException e) { + System.out.println("\nPlease enter a valid task number."); + } + } + + /** + * Lists tasks on a specific date. + * + * @param date the date to list tasks on + */ + private void searchByDate(Scanner scanner) { + + System.out.println("\nPlease select the type of task to search:"); + System.out.println("1. Deadline Task"); + System.out.println("2. Event Task"); + System.out.print("Your choice (1/2): "); + String choice = scanner.nextLine().trim(); + + switch (choice) { + case "1": // Deadline task + System.out.println("\nPlease enter the date and time in yyyy-MM-dd HH:mm format to list deadline tasks."); + System.out.println("For example, 2021-09-30 18:30."); + break; + case "2": // Event task + System.out.println("\nPlease enter the date in yyyy-MM-dd format to list event tasks."); + System.out.println("For example, 2021-09-30."); + break; + default: + System.out.println("\nInvalid choice. Please enter 1 or 2."); + return; + } + + String dateString = scanner.nextLine().trim(); + + try { + if ("1".equals(choice)) { + LocalDateTime date = LocalDateTime.parse(dateString, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")); + taskManager.listTasksOn(date); + return; + } else { + LocalDate date = LocalDate.parse(dateString, DateTimeFormatter.ofPattern("yyyy-MM-dd")); + taskManager.listTasksOn(date); + return; + } + } catch (DateTimeParseException e) { + System.out.println("\nInvalid date format. Please enter the date in the correct format."); + } catch (DateTimeNotAfterCurrentTimeException e) { + System.out.println("\nInvalid date. Please enter a date after the current date."); + } + } + +} diff --git a/src/main/java/com/erii/user/UserDetails.java b/src/main/java/com/erii/user/UserDetails.java new file mode 100644 index 000000000..3a0e013c3 --- /dev/null +++ b/src/main/java/com/erii/user/UserDetails.java @@ -0,0 +1,147 @@ +package com.erii.user; + +import java.util.Scanner; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +/** + * The UserDetails class represents the details of a user. + * It contains information such as the user's name, birthday, and gender. + */ +public class UserDetails { + private String userName = ""; + private String userBirthday = ""; + private String userGender = ""; + private Scanner scanner = new Scanner(System.in); + + /** + * Constructs a new UserDetails instance. + */ + public UserDetails() { + // Constructor to initialize the UserDetails instance + } + + /** + * Sets the user name. + * + * @param userName the user name to set + */ + public void setUserName(String userName) { + this.userName = userName; + } + + /** + * Sets the user birthday. + * + * @param userBirthday the user birthday to set + */ + public void setUserBirthday(String userBirthday) { + this.userBirthday = userBirthday; + } + + /** + * Sets the user gender. + * + * @param userGender the user gender to set + */ + public void setUserGender(String userGender) { + this.userGender = userGender; + } + + /** + * Gets the user name. + * + * @return the user name + */ + public String getUserName() { + return this.userName; + } + + /** + * Gets the user birthday. + * + * @return the user birthday + */ + public String getUserBirthday() { + return this.userBirthday; + } + + /** + * Gets the user gender. + * + * @return the user gender + */ + public String getUserGender() { + return this.userGender; + } + + /** + * Prompts the user to input their name. + */ + public void inputName() { + System.out.println("\nPlease enter your full name (First Name Last Name): "); + String name; + + while (true) { + name = scanner.nextLine().trim(); + if (name.split("\\s+").length >= 2) { + this.userName = name; + break; + } else { + System.out.println("\nInvalid name. Please enter both your first name and last name."); + } + } + } + + /** + * Prompts the user to input their birthday. + */ + public void inputBirthday() { + System.out.println("\nPlease enter your birthday (DD/MM/YYYY): "); + String birthday; + Pattern datePattern = Pattern.compile("^\\d{2}/\\d{2}/\\d{4}$"); + + while (true) { + birthday = scanner.nextLine().trim(); + Matcher matcher = datePattern.matcher(birthday); + if (matcher.matches()) { + this.userBirthday = birthday; + break; + } else { + System.out.println("\nInvalid format. Please enter your birthday in DD/MM/YYYY format."); + } + } + } + + /** + * Prompts the user to input their gender. + */ + public void inputGender() { + System.out.println("\nPlease enter your gender: "); + System.out.println("1. Male"); + System.out.println("2. Female"); + System.out.println("3. Other"); + String gender = ""; + + while (true) { + String input = scanner.nextLine().trim(); + switch (input) { + case "1": + gender = "Male"; + break; + case "2": + gender = "Female"; + break; + case "3": + gender = "Other"; + break; + default: + System.out.println("\nInvalid option selected. Please enter 1, 2, or 3."); + continue; + } + this.userGender = gender; + break; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/erii/util/DateTimeValidator.java b/src/main/java/com/erii/util/DateTimeValidator.java new file mode 100644 index 000000000..6a73bab2d --- /dev/null +++ b/src/main/java/com/erii/util/DateTimeValidator.java @@ -0,0 +1,22 @@ +package com.erii.util; + +import java.time.LocalDateTime; +import com.erii.exception.DateTimeNotAfterCurrentTimeException; + +public class DateTimeValidator { + + /** + * Validates that the given date and time are after the current system date and time. + * + * @param userInputDateTime The date and time to be validated. + * @throws DateTimeNotAfterCurrentTimeException If the userInputDateTime is not after the current time. + */ + public static void validateDateTimeIsAfterCurrentTime(LocalDateTime userInputDateTime) { + LocalDateTime currentTime = LocalDateTime.now(); + + if (!userInputDateTime.isAfter(currentTime)) { + throw new DateTimeNotAfterCurrentTimeException("\nThe provided date and time must be after the current time."); + } + } + +} diff --git a/src/main/java/com/erii/util/DateValidator.java b/src/main/java/com/erii/util/DateValidator.java new file mode 100644 index 000000000..c1ee52ba1 --- /dev/null +++ b/src/main/java/com/erii/util/DateValidator.java @@ -0,0 +1,22 @@ +package com.erii.util; + +import java.time.LocalDate; + +import com.erii.exception.DateTimeNotAfterCurrentTimeException; + +public class DateValidator { + + /** + * Validates that the given date is in the correct format. + * + * @param date The date to be validated. + * @return true if the date is in the correct format, false otherwise. + */ + public static void validateDateIsAfterCurrentTime(LocalDate userInputDateTime) { + LocalDate currentTime = LocalDate.now(); + + if (!userInputDateTime.isAfter(currentTime)) { + throw new DateTimeNotAfterCurrentTimeException("\nThe provided date must be after the current date."); + } + } +} diff --git a/text-ui-test/EXPECTED.TXT b/text-ui-test/EXPECTED.TXT index 657e74f6e..cd11f60cc 100644 --- a/text-ui-test/EXPECTED.TXT +++ b/text-ui-test/EXPECTED.TXT @@ -1,7 +1,46 @@ Hello from - ____ _ -| _ \ _ _| | _____ -| | | | | | | |/ / _ \ -| |_| | |_| | < __/ -|____/ \__,_|_|\_\___| + + _____ _____ _____ _____ + /\ \ /\ \ /\ \ /\ \ + /::\ \ /::\ \ /::\ \ /::\ \ + /::::\ \ /::::\ \ \:::\ \ \:::\ \ + /::::::\ \ /::::::\ \ \:::\ \ \:::\ \ + /:::/\:::\ \ /:::/\:::\ \ \:::\ \ \:::\ \ + /:::/__\:::\ \ /:::/__\:::\ \ \:::\ \ \:::\ \ + /::::\ \:::\ \ /::::\ \:::\ \ /::::\ \ /::::\ \ + /::::::\ \:::\ \ /::::::\ \:::\ \ ____ /::::::\ \ ____ /::::::\ \ + /:::/\:::\ \:::\ \ /:::/\:::\ \:::\____\ /\ \ /:::/\:::\ \ /\ \ /:::/\:::\ \ +/:::/__\:::\ \:::\____\/:::/ \:::\ \:::| |/::\ \/:::/ \:::\____\/::\ \/:::/ \:::\____\ +\:::\ \:::\ \::/ /\::/ |::::\ /:::|____|\:::\ /:::/ \::/ /\:::\ /:::/ \::/ / + \:::\ \:::\ \/____/ \/____|:::::\/:::/ / \:::\/:::/ / \/____/ \:::\/:::/ / \/____/ + \:::\ \:::\ \ |:::::::::/ / \::::::/ / \::::::/ / + \:::\ \:::\____\ |::|\::::/ / \::::/____/ \::::/____/ + \:::\ \::/ / |::| \::/____/ \:::\ \ \:::\ \ + \:::\ \/____/ |::| ~| \:::\ \ \:::\ \ + \:::\ \ |::| | \:::\ \ \:::\ \ + \:::\____\ \::| | \:::\____\ \:::\____\ + \::/ / \:| | \::/ / \::/ / + \/____/ \|___| \/____/ \/____/ + +Initializing Kassel Academy... +Welcome back, SIYI LIU + +Here are the tasks in your list: +____________________________________________________________ + +How may I assist you today? +1. List tasks +2. Add a task +3. Add a deadline task +4. Add an event task +5. Mark a task as done +6. Delete a task +7. List tasks on a specific date +8. Search for a task by keyword +X. Exit +Enter the symbol corresponding to your choice: +1 + +Here are the tasks in your list: +____________________________________________________________