diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..c995aa5ce --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "java.debug.settings.onBuildFailureProceed": true +} \ No newline at end of file diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md deleted file mode 100644 index 8e359a014..000000000 --- a/CONTRIBUTORS.md +++ /dev/null @@ -1,9 +0,0 @@ -# Contributors - -Display | Name | Github Profile | Homepage ----|:---:|:---:|:---: -![](https://avatars0.githubusercontent.com/u/22460123?s=100) | Jeffry Lum | [Github](https://github.com/j-lum/) | [Homepage](https://se.kasugano.moe) -![](https://avatars0.githubusercontent.com/u/1673303?s=100) | Damith C. Rajapakse | [Github](https://github.com/damithc/) | [Homepage](https://www.comp.nus.edu.sg/~damithch/) -# I would like to join this list. How can I help the project - -For more information, please refer to our [contributor's guide](https://oss-generic.github.io/process/). diff --git a/README.md b/README.md index 8715d4d91..39dbda449 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,187 @@ -# Duke project template +# Incy - The British Task Manager -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. +## Introduction +Welcome to Incy, your friendly neighborhood task manager! Incy is a command-line application designed to help you stay organized and manage your tasks with ease. Whether you need to keep track of simple to-dos, important deadlines, or upcoming events, Incy has got you covered. -## Setting up in Intellij +## Getting Started +### Prerequisites +Before you start using Incy, make sure you have the following: +- Java Development Kit (JDK) installed on your computer +- Basic understanding of command-line interfaces -Prerequisites: JDK 11, update Intellij to the most recent version. +### Installation +1. Visit the Incy repository on GitHub: [Incy Repository](https://github.com/IncyBot/ip) +2. Click on the "Code" button and select "Download ZIP" to download the source code as a ZIP file. +3. Extract the ZIP file to a directory of your choice. +4. Open a terminal or command prompt and navigate to the directory where you extracted the source code. -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: +### Running Incy +1. In the terminal, compile the Java source files by running the following command: ``` - Hello from - ____ _ - | _ \ _ _| | _____ - | | | | | | | |/ / _ \ - | |_| | |_| | < __/ - |____/ \__,_|_|\_\___| + javac *.java ``` +2. Once the compilation is successful, you can run Incy using the following command: + ``` + java Incy + ``` +3. Incy will greet you with a friendly message and display the command prompt, ready for you to start managing your tasks. + +## Features +Incy offers a range of features to help you stay on top of your tasks: + +### Adding Tasks +Incy supports three types of tasks: to-dos, deadlines, and events. Here's how you can add each type of task: + +#### To-Do +To add a to-do task, use the following command: +``` +todo [description] +``` +Replace `[description]` with a brief description of your to-do task. + +Example: +``` +todo Buy groceries +``` + +#### Deadline +To add a deadline task, use the following command: +``` +deadline [description] /by [date/time] +``` +Replace `[description]` with a brief description of your deadline task, and `[date/time]` with the due date and time of the deadline. + +Example: +``` +deadline Submit project report /by 2023-06-30 17:00 +``` + +#### Event +To add an event task, use the following command: +``` +event [description] /from [start time] /to [end time] +``` +Replace `[description]` with a brief description of your event task, `[start time]` with the start date and time of the event, and `[end time]` with the end date and time of the event. + +Example: +``` +event Team meeting /from 2023-07-01 14:00 /to 2023-07-01 16:00 +``` + +### Listing Tasks +To view all your tasks, simply use the `list` command: +``` +list +``` +Incy will display a numbered list of all your tasks, along with their details such as task type, description, and due date/time (if applicable). + +### Marking Tasks as Done +When you complete a task, you can mark it as done using the `mark` command followed by the task index: +``` +mark [index] +``` +Replace `[index]` with the number corresponding to the task you want to mark as done. + +Example: +``` +mark 2 +``` + +### Unmarking Tasks +If you accidentally marked a task as done or need to reopen a task, you can use the `unmark` command followed by the task index: +``` +unmark [index] +``` +Replace `[index]` with the number corresponding to the task you want to unmark. + +Example: +``` +unmark 3 +``` + +### Deleting Tasks +To remove a task from your list, use the `delete` command followed by the task index: +``` +delete [index] +``` +Replace `[index]` with the number corresponding to the task you want to delete. + +Example: +``` +delete 1 +``` + +### Finding Tasks +If you have a long list of tasks and want to quickly find specific tasks, you can use the `find` command followed by a keyword: +``` +find [keyword] +``` +Replace `[keyword]` with the word or phrase you want to search for in your task descriptions. + +Example: +``` +find project +``` +Incy will display a list of tasks that contain the specified keyword in their descriptions. + +### Listing Tasks by Date +To view tasks scheduled for a specific date, use the `list by` command followed by the date: +``` +list by [date] +``` +Replace `[date]` with the desired date in the format `yyyy-MM-dd`. + +Example: +``` +list by 2023-06-30 +``` +Incy will display a list of tasks scheduled for the specified date. + +### Exiting Incy +When you're done managing your tasks and want to exit Incy, simply type `bye`: +``` +bye +``` +Incy will save your tasks and bid you farewell. + +## Data Persistence +Incy automatically saves your tasks to a file named `incy_tasks.txt` located in the `data` folder within the project directory. This ensures that your tasks are preserved even after you exit the application. + +When you start Incy, it loads the tasks from the `incy_tasks.txt` file, allowing you to pick up where you left off. + +If the `data` folder or the `incy_tasks.txt` file doesn't exist, Incy will create them automatically when you add your first task. + +## Error Handling +Incy is designed to handle common errors gracefully. If you enter an invalid command or provide incorrect input, Incy will display an appropriate error message and prompt you to try again. + +If the `incy_tasks.txt` file becomes corrupted or contains invalid data, Incy will skip the corrupted lines and load only the valid tasks. + +## Customization +Incy's source code is well-structured and modular, making it easy to customize and extend its functionality. The main classes in the project are: + +- `Incy`: The entry point of the application, handling user input and interaction. +- `TaskManager`: Manages the task list and provides methods for adding, marking, unmarking, deleting, and listing tasks. +- `TaskFactory`: Responsible for creating task objects based on user input and file data. +- `Task`: An abstract base class representing a generic task. +- `Todo`, `Deadline`, `Event`: Concrete classes extending the `Task` class, representing specific types of tasks. +- `IncyException`: A custom exception class for handling Incy-specific errors. +- `Constants`: Contains constant values used throughout the application. + +Feel free to explore the source code and make modifications to suit your specific needs. + +## Troubleshooting +If you encounter any issues while using Incy, consider the following troubleshooting steps: + +1. Make sure you have Java Development Kit (JDK) installed and properly set up on your computer. +2. Verify that you are running Incy from the correct directory where the source code files are located. +3. Check that you have the necessary permissions to read from and write to the `data` folder and `incy_tasks.txt` file. +4. If you encounter any error messages, carefully read the message and refer to the relevant section in this user guide for guidance. + +If the issue persists, feel free to open an issue on the Incy GitHub repository, providing detailed information about the problem you encountered. + +## Conclusion +Incy is a user-friendly and efficient task manager designed to simplify your life. With its intuitive commands and seamless data persistence, Incy helps you stay organized and on top of your tasks. + +So, go ahead and give Incy a try! Let it be your trusted companion in tackling your tasks and achieving your goals. + +Happy task managing with Incy! \ No newline at end of file diff --git a/docs/README.md b/docs/README.md index 8077118eb..39dbda449 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,29 +1,187 @@ -# User Guide +# Incy - The British Task Manager -## Features +## Introduction +Welcome to Incy, your friendly neighborhood task manager! Incy is a command-line application designed to help you stay organized and manage your tasks with ease. Whether you need to keep track of simple to-dos, important deadlines, or upcoming events, Incy has got you covered. -### Feature-ABC +## Getting Started +### Prerequisites +Before you start using Incy, make sure you have the following: +- Java Development Kit (JDK) installed on your computer +- Basic understanding of command-line interfaces -Description of the feature. +### Installation +1. Visit the Incy repository on GitHub: [Incy Repository](https://github.com/IncyBot/ip) +2. Click on the "Code" button and select "Download ZIP" to download the source code as a ZIP file. +3. Extract the ZIP file to a directory of your choice. +4. Open a terminal or command prompt and navigate to the directory where you extracted the source code. -### Feature-XYZ +### Running Incy +1. In the terminal, compile the Java source files by running the following command: + ``` + javac *.java + ``` +2. Once the compilation is successful, you can run Incy using the following command: + ``` + java Incy + ``` +3. Incy will greet you with a friendly message and display the command prompt, ready for you to start managing your tasks. -Description of the feature. +## Features +Incy offers a range of features to help you stay on top of your tasks: -## Usage +### Adding Tasks +Incy supports three types of tasks: to-dos, deadlines, and events. Here's how you can add each type of task: -### `Keyword` - Describe action +#### To-Do +To add a to-do task, use the following command: +``` +todo [description] +``` +Replace `[description]` with a brief description of your to-do task. + +Example: +``` +todo Buy groceries +``` + +#### Deadline +To add a deadline task, use the following command: +``` +deadline [description] /by [date/time] +``` +Replace `[description]` with a brief description of your deadline task, and `[date/time]` with the due date and time of the deadline. + +Example: +``` +deadline Submit project report /by 2023-06-30 17:00 +``` + +#### Event +To add an event task, use the following command: +``` +event [description] /from [start time] /to [end time] +``` +Replace `[description]` with a brief description of your event task, `[start time]` with the start date and time of the event, and `[end time]` with the end date and time of the event. + +Example: +``` +event Team meeting /from 2023-07-01 14:00 /to 2023-07-01 16:00 +``` -Describe the action and its outcome. +### Listing Tasks +To view all your tasks, simply use the `list` command: +``` +list +``` +Incy will display a numbered list of all your tasks, along with their details such as task type, description, and due date/time (if applicable). -Example of usage: +### Marking Tasks as Done +When you complete a task, you can mark it as done using the `mark` command followed by the task index: +``` +mark [index] +``` +Replace `[index]` with the number corresponding to the task you want to mark as done. -`keyword (optional arguments)` +Example: +``` +mark 2 +``` -Expected outcome: +### Unmarking Tasks +If you accidentally marked a task as done or need to reopen a task, you can use the `unmark` command followed by the task index: +``` +unmark [index] +``` +Replace `[index]` with the number corresponding to the task you want to unmark. -Description of the outcome. +Example: +``` +unmark 3 +``` + +### Deleting Tasks +To remove a task from your list, use the `delete` command followed by the task index: +``` +delete [index] +``` +Replace `[index]` with the number corresponding to the task you want to delete. +Example: ``` -expected output +delete 1 ``` + +### Finding Tasks +If you have a long list of tasks and want to quickly find specific tasks, you can use the `find` command followed by a keyword: +``` +find [keyword] +``` +Replace `[keyword]` with the word or phrase you want to search for in your task descriptions. + +Example: +``` +find project +``` +Incy will display a list of tasks that contain the specified keyword in their descriptions. + +### Listing Tasks by Date +To view tasks scheduled for a specific date, use the `list by` command followed by the date: +``` +list by [date] +``` +Replace `[date]` with the desired date in the format `yyyy-MM-dd`. + +Example: +``` +list by 2023-06-30 +``` +Incy will display a list of tasks scheduled for the specified date. + +### Exiting Incy +When you're done managing your tasks and want to exit Incy, simply type `bye`: +``` +bye +``` +Incy will save your tasks and bid you farewell. + +## Data Persistence +Incy automatically saves your tasks to a file named `incy_tasks.txt` located in the `data` folder within the project directory. This ensures that your tasks are preserved even after you exit the application. + +When you start Incy, it loads the tasks from the `incy_tasks.txt` file, allowing you to pick up where you left off. + +If the `data` folder or the `incy_tasks.txt` file doesn't exist, Incy will create them automatically when you add your first task. + +## Error Handling +Incy is designed to handle common errors gracefully. If you enter an invalid command or provide incorrect input, Incy will display an appropriate error message and prompt you to try again. + +If the `incy_tasks.txt` file becomes corrupted or contains invalid data, Incy will skip the corrupted lines and load only the valid tasks. + +## Customization +Incy's source code is well-structured and modular, making it easy to customize and extend its functionality. The main classes in the project are: + +- `Incy`: The entry point of the application, handling user input and interaction. +- `TaskManager`: Manages the task list and provides methods for adding, marking, unmarking, deleting, and listing tasks. +- `TaskFactory`: Responsible for creating task objects based on user input and file data. +- `Task`: An abstract base class representing a generic task. +- `Todo`, `Deadline`, `Event`: Concrete classes extending the `Task` class, representing specific types of tasks. +- `IncyException`: A custom exception class for handling Incy-specific errors. +- `Constants`: Contains constant values used throughout the application. + +Feel free to explore the source code and make modifications to suit your specific needs. + +## Troubleshooting +If you encounter any issues while using Incy, consider the following troubleshooting steps: + +1. Make sure you have Java Development Kit (JDK) installed and properly set up on your computer. +2. Verify that you are running Incy from the correct directory where the source code files are located. +3. Check that you have the necessary permissions to read from and write to the `data` folder and `incy_tasks.txt` file. +4. If you encounter any error messages, carefully read the message and refer to the relevant section in this user guide for guidance. + +If the issue persists, feel free to open an issue on the Incy GitHub repository, providing detailed information about the problem you encountered. + +## Conclusion +Incy is a user-friendly and efficient task manager designed to simplify your life. With its intuitive commands and seamless data persistence, Incy helps you stay organized and on top of your tasks. + +So, go ahead and give Incy a try! Let it be your trusted companion in tackling your tasks and achieving your goals. + +Happy task managing with Incy! \ No newline at end of file diff --git a/src/main/java/Constants.java b/src/main/java/Constants.java new file mode 100644 index 000000000..bcba3489b --- /dev/null +++ b/src/main/java/Constants.java @@ -0,0 +1,48 @@ +/** + * The Constants class holds constant values used throughout the application. + */ + +public class Constants { + public static final String ANSI_RESET = "\u001B[0m"; + public static final String ANSI_BLACK = "\u001B[30m"; + public static final String ANSI_RED = "\u001B[31m"; + public static final String ANSI_GREEN = "\u001B[32m"; + public static final String ANSI_YELLOW = "\u001B[33m"; + public static final String ANSI_BLUE = "\u001B[34m"; + public static final String ANSI_PURPLE = "\u001B[35m"; + public static final String ANSI_CYAN = "\u001B[36m"; + public static final String ANSI_WHITE = "\u001B[37m"; + + public static final String ANSI_BLACK_BACKGROUND = "\u001B[40m"; + public static final String ANSI_RED_BACKGROUND = "\u001B[41m"; + public static final String ANSI_GREEN_BACKGROUND = "\u001B[42m"; + public static final String ANSI_YELLOW_BACKGROUND = "\u001B[43m"; + public static final String ANSI_BLUE_BACKGROUND = "\u001B[44m"; + public static final String ANSI_PURPLE_BACKGROUND = "\u001B[45m"; + public static final String ANSI_CYAN_BACKGROUND = "\u001B[46m"; + public static final String ANSI_WHITE_BACKGROUND = "\u001B[47m"; + + public static final String LINE_STRING_TOP = ANSI_GREEN + "____________________________________________________________\n\n" ; + public static final String LINE_STRING_BOTTOM = ANSI_GREEN + "____________________________________________________________\n" + ANSI_BLUE ; + + public static final Integer MAX_TASKS = 100; + + public static final String DATA_FOLDER = "data"; + public static final String DATA_FILE = "incy_tasks.txt"; + + public static final String LOGO = " ▄▄ ▄▄▀▀ \n" + // + " ▄▄▀ ▄▀▀▀▀▀▀▀▀▀ \n" + // + " ▄▀▀▀ ▄▀▀▀▀▀▀▀▀▀ ▄\n" + // + " ▀▀▀▀▄ ▄▀▀▀▀▀▀▀▀ ▄▀▄▀▀\n" + // + " ▀▀▀▀▀▀▀▀▀▀▀ ▄▀▀▀▀ \n" + // + " ▀▀▀▀▀▀▀▀▀▀▀▀▀▄ ▄▀▀▀▄▀▀▀▀ \n" + // + " ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄▀▀▀▀▀▀▀ \n" + // + " ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀▀▀ \n" + // + " ▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ \n" + // + " ▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▄▄▀▀▀▄▄ \n" + // + "▀▀▀▀▀ ▀▀▀▀▀▀▀▀▄▄▀▀▀▀▀▀▀▀▀▀ \n" + // + " ▀▀▀ ▄▄▀▀▀▀▀▀▀▀▀▀▀▀▀▀ \n" + // + " ▀▀▀▀▀▀▀▀▀▀▀▀▀▀ \n" + // + " ▀ ▀▀▀▀▀ ▀ \n" + // + "\n"; +} diff --git a/src/main/java/Deadline.java b/src/main/java/Deadline.java new file mode 100644 index 000000000..5434e3bf3 --- /dev/null +++ b/src/main/java/Deadline.java @@ -0,0 +1,47 @@ +/** + * The Deadline class represents a task with a deadline. + * It extends the Task class and adds a deadline date and time. + */ + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class Deadline extends Task { + private LocalDateTime by; + + /** + * Constructs a new Deadline object with the given description and deadline. + * @param description The task description + * @param by The deadline date and time in the format "yyyy-MM-dd HHmm" + */ + public Deadline(String description, String by) { + super(description); + this.by = LocalDateTime.parse(by, DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm")); + } + + /** + * Gets the deadline date and time. + * @return The deadline date and time + */ + public LocalDateTime getBy() { + return by; + } + + /** + * Returns a string representation of the Deadline task. + * @return The string representation + */ + @Override + public String toString() { + return "[D]" + super.getStatusIcon() + " " + description + " (by: " + by.format(DateTimeFormatter.ofPattern("MMM dd yyyy, hh:mm a")) + ")"; + } + + /** + * Returns a string representation of the Deadline task suitable for writing to a file. + * @return The string representation + */ + @Override + public String toFileString() { + return "D | " + (isDone ? "1" : "0") + " | " + description + " | " + by.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm")); + } +} \ No newline at end of file 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..15d71a6eb --- /dev/null +++ b/src/main/java/Event.java @@ -0,0 +1,59 @@ +/** + * The Event class represents a task with a start and end time. + * It extends the Task class and adds start and end date and time properties. + */ + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +public class Event extends Task { + private LocalDateTime start; + private LocalDateTime end; + + /** + * Constructs a new Event object with the given description, start time, and end time. + * @param description The task description + * @param start The start date and time in the format "yyyy-MM-dd HHmm" + * @param end The end date and time in the format "yyyy-MM-dd HHmm" + */ + public Event(String description, String start, String end) { + super(description); + this.start = LocalDateTime.parse(start, DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm")); + this.end = LocalDateTime.parse(end, DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm")); + } + + + /** + * Gets the start date and time. + * @return The start date and time + */ + public LocalDateTime getStart() { + return start; + } + + /** + * Gets the end date and time. + * @return The end date and time + */ + public LocalDateTime getEnd() { + return end; + } + + /** + * Returns a string representation of the Event task. + * @return The string representation + */ + @Override + public String toString() { + return "[E]" + super.getStatusIcon() + " " + description + " (from: " + start.format(DateTimeFormatter.ofPattern("MMM dd yyyy, hh:mm a")) + " to: " + end.format(DateTimeFormatter.ofPattern("MMM dd yyyy, hh:mm a")) + ")"; + } + + /** + * Returns a string representation of the Event task suitable for writing to a file. + * @return The string representation + */ + @Override + public String toFileString() { + return "E | " + (isDone ? "1" : "0") + " | " + description + " | " + start.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm")) + " | " + end.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HHmm")); + } +} \ No newline at end of file diff --git a/src/main/java/Incy.java b/src/main/java/Incy.java new file mode 100644 index 000000000..a2708c3c2 --- /dev/null +++ b/src/main/java/Incy.java @@ -0,0 +1,101 @@ +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Scanner; + +/** + * The Incy class is the main entry point of the application. + * It handles user input, manages tasks, and interacts with the TaskManager class. + */ + +public class Incy { + /** + * The main method of the application. + * It initializes the TaskManager, loads tasks from file, processes user input, + * saves tasks to file, and handles the application's lifecycle. + * + * @param args The command-line arguments (not used) + */ + public static void main(String[] args) { + Scanner scanner = new Scanner(System.in); + TaskManager taskManager = new TaskManager(); + + ensureDataFolderExists(); + taskManager.loadTasksFromFile(); + + printWelcomeMessage(); + + while (true) { + String input = scanner.nextLine(); + if ("bye".equalsIgnoreCase(input)) { + break; + } + processInput(input, taskManager); + } + + taskManager.saveTasksToFile(); + printGoodbyeMessage(); + scanner.close(); + } + + /** + * Ensures that the data folder exists, creating it if necessary. + */ + + private static void ensureDataFolderExists() { + Path dataFolderPath = Paths.get(Constants.DATA_FOLDER); + if (!Files.exists(dataFolderPath)) { + try { + Files.createDirectory(dataFolderPath); + } catch (IOException e) { + System.err.println("Failed to create data folder: " + e.getMessage()); + } + } + } + + /** + * Prints the welcome message to the console. + */ + + private static void printWelcomeMessage() { + System.out.println(Constants.LINE_STRING_TOP + Constants.ANSI_CYAN + "Oi bruv! I'm\n" + Constants.LOGO + Constants.ANSI_CYAN + "Wotcha need from me today?\n" + Constants.LINE_STRING_BOTTOM); + } + + /** + * Prints the goodbye message to the console. + */ + + private static void printGoodbyeMessage() { + System.out.println(Constants.LINE_STRING_TOP + Constants.ANSI_CYAN + "Cya later mate!\n" + Constants.LINE_STRING_BOTTOM); + } + + /** + * Processes the user input and delegates the appropriate action to the TaskManager. + * + * @param input The user input string + * @param taskManager The TaskManager instance + */ + + private static void processInput(String input, TaskManager taskManager) { + try { + if ("list".equalsIgnoreCase(input)) { + taskManager.handleListCommand(); + } else if (input.startsWith("mark ")) { + taskManager.handleMarkCommand(input, true); + } else if (input.startsWith("unmark ")) { + taskManager.handleMarkCommand(input, false); + } else if (input.startsWith("delete ")) { + taskManager.handleDeleteCommand(input); + } else if (input.startsWith("list by ")) { + taskManager.handleListByDateCommand(input); + } else if (input.startsWith("find ")) { + taskManager.handleFindCommand(input); + } else { + taskManager.handleAddTask(input); + } + } catch (IncyException e) { + System.out.println(Constants.LINE_STRING_TOP + Constants.ANSI_RED + e.getMessage() + "\n" + Constants.LINE_STRING_BOTTOM); + } + } +} diff --git a/src/main/java/IncyException.java b/src/main/java/IncyException.java new file mode 100644 index 000000000..f774afd76 --- /dev/null +++ b/src/main/java/IncyException.java @@ -0,0 +1,14 @@ +/** + * The IncyException class represents an exception that occurs within the Incy application. + */ + +public class IncyException extends Exception { + /** + * Constructs a new IncyException with the specified message. + * + * @param message The exception message + */ + public IncyException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/src/main/java/Task.java b/src/main/java/Task.java new file mode 100644 index 000000000..e216ca958 --- /dev/null +++ b/src/main/java/Task.java @@ -0,0 +1,55 @@ +/** + * The Task class is an abstract base class representing a task. + * It provides common properties and methods for tasks. + */ + +public abstract class Task { + protected String description; + protected boolean isDone; + + /** + * Constructs a new Task object with the given description. + * @param description The task description + */ + Task(String description) { + this.description = description; + this.isDone = false; + } + + /** + * Gets the task description. + * @return The task description + */ + public String getDescription() { + return description; + } + + /** + * Gets a string representing the task status icon (done or not done). + * @return The task status icon string + */ + String getStatusIcon() { + return (isDone ? "[X]" : "[ ]"); + } + + /** + * Sets the task as done or not done. + * @param done A boolean indicating whether the task is done or not + */ + public void setDone(boolean done) { + isDone = done; + } + + /** + * Returns a string representation of the task. + * @return The string representation + */ + @Override + public abstract String toString(); + + /** + * Returns a string representation of the task suitable for writing to a file. + * @return The string representation + */ + public abstract String toFileString(); +} \ No newline at end of file diff --git a/src/main/java/TaskFactory.java b/src/main/java/TaskFactory.java new file mode 100644 index 000000000..afded27a2 --- /dev/null +++ b/src/main/java/TaskFactory.java @@ -0,0 +1,141 @@ +/** + * The TaskFactory class is responsible for creating Task objects from user input + * and handling the parsing of task data from file. + */ + +import java.time.format.DateTimeParseException; + +public class TaskFactory { + /** + * Creates a Task object based on the user input. + * + * @param input The user input string containing the task type and details + * @return The created Task object, or null if the input is invalid + * @throws IncyException If the task type or format is invalid + */ + static Task createTask(String input) throws IncyException { + String[] parts = input.split(" ", 2); + String command = parts[0]; + String taskInfo = parts.length > 1 ? parts[1] : ""; + + switch (command.toLowerCase()) { + case "todo": + if (taskInfo.isEmpty()) { + throw new IncyException("Oi! You can't have a todo with no description!"); + } + return new Todo(taskInfo); + case "deadline": + return createDeadline(taskInfo); + case "event": + return createEvent(taskInfo); + default: + throw new IncyException("Hol' up bruv, I dun get what that means..., try typin 'todo', 'deadline', or 'event' first, yeah?"); + } + } + + /** + * Creates a Task object from a line in the data file. + * + * @param line The line from the data file containing the task data + * @return The created Task object, or null if the line is invalid + */ + static Task createTaskFromLine(String line) { + String[] parts = line.split(" \\| ", 3); + if (parts.length < 3) { + return null; + } + String typeCode = parts[0]; + boolean isDone = parts[1].equals("1"); + String taskData = parts[2]; + switch (typeCode) { + case "T": + Todo todo = new Todo(taskData); + todo.setDone(isDone); + return todo; + case "D": + return createDeadlineFromLine(taskData, isDone); + case "E": + return createEventFromLine(taskData, isDone); + default: + return null; + } + } + + /** + * Creates a Deadline object from the user input string. + * @param taskInfo The user input string containing the task description and deadline + * @return The created Deadline object, or null if the input is invalid + */ + private static Task createDeadline(String taskInfo) { + String[] deadlineParts = taskInfo.split(" /by ", 2); + if (deadlineParts.length < 2) { + printFormatError("You've mucked up the deadline format. Do it like 'deadline [task] /by [yyyy-MM-dd HHmm]', yeah?"); + return null; + } + try { + return new Deadline(deadlineParts[0], deadlineParts[1]); + } catch (DateTimeParseException e) { + printFormatError("Invalid date format for deadline. Use 'yyyy-MM-dd HHmm' format, mate."); + return null; + } + } + + /** + * Creates an Event object from the user input string. + * @param taskInfo The user input string containing the task description and event details + * @return The created Event object, or null if the input is invalid + */ + private static Task createEvent(String taskInfo) { + String[] eventParts = taskInfo.split(" /from ", 2); + String[] eventTime = eventParts.length > 1 ? eventParts[1].split(" /to ", 2) : new String[0]; + if (eventParts.length < 2 || eventTime.length < 2) { + printFormatError("You've bungled the event format. It's gotta be 'event [task] /from [yyyy-MM-dd HHmm] /to [yyyy-MM-dd HHmm]', innit?"); + return null; + } + try { + return new Event(eventParts[0], eventTime[0], eventTime[1]); + } catch (DateTimeParseException e) { + printFormatError("Invalid date format for event. Use 'yyyy-MM-dd HHmm' format, mate."); + return null; + } + } + + /** + * Creates a Deadline object from a line in the data file. + * @param line The line from the data file representing a Deadline task + * @return The created Deadline object, or null if the line is invalid + */ + private static Deadline createDeadlineFromLine(String line, boolean isDone) { + String[] parts = line.split(" \\| ", 2); + if (parts.length < 2) { + return null; + } + Deadline deadline = new Deadline(parts[0], parts[1]); + deadline.setDone(isDone); + return deadline; + } + + /** + * Creates an Event object from a line in the data file. + * @param line The line from the data file representing an Event task + * @return The created Event object, or null if the line is invalid + */ + private static Event createEventFromLine(String line, boolean isDone) { + String[] parts = line.split(" \\| ", 3); + if (parts.length < 3) { + return null; + } + Event event = new Event(parts[0], parts[1], parts[2]); + event.setDone(isDone); + return event; + } + + /** + * Prints a format error message to the console. + * @param errorMessage The error message to print + */ + static void printFormatError(String errorMessage) { + System.out.println(Constants.LINE_STRING_TOP + Constants.ANSI_RED + "Error: " + errorMessage + "\n" + + Constants.LINE_STRING_BOTTOM); + } +} diff --git a/src/main/java/TaskManager.java b/src/main/java/TaskManager.java new file mode 100644 index 000000000..55e6143c0 --- /dev/null +++ b/src/main/java/TaskManager.java @@ -0,0 +1,231 @@ +/** + * The TaskManager class manages the list of tasks and handles various commands + * related to tasks, such as listing, marking, deleting, finding, and adding tasks. + */ + +import java.util.ArrayList; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.Scanner; + +public class TaskManager { + private ArrayList tasks = new ArrayList<>(); + + /** + * Handles the "list" command, displaying all tasks in the list. + */ + void handleListCommand() { + System.out.println(Constants.LINE_STRING_BOTTOM); + if (tasks.isEmpty()) { + System.out.println(Constants.ANSI_RED + "Blimey, your list is empty, innit?"); + } else { + int index = 1; + for (Task task : tasks) { + System.out.println(Constants.ANSI_CYAN + index++ + ". " + task); + } + } + System.out.println(Constants.LINE_STRING_BOTTOM); + } + + /** + * Handles the "mark" and "unmark" commands, marking or unmarking a task as done. + * + * @param input The user input string containing the command and task index + * @param markAsDone A flag indicating whether to mark the task as done (true) or undone (false) + * @throws IncyException If the task index is invalid or the list is empty + */ + void handleMarkCommand(String input, boolean markAsDone) throws IncyException { + if (tasks.isEmpty()) { + throw new IncyException("Nah, mate, nothin' to tick off, yer list's empty!"); + } + + int index = Integer.parseInt(input.substring(markAsDone ? 5 : 7)) - 1; + if (!isValidIndex(index)) { + throw new IncyException("Gimme a legit number, will ya? That one's not on."); + } + + tasks.get(index).setDone(markAsDone); + System.out.println(Constants.LINE_STRING_TOP + Constants.ANSI_CYAN + "Banging! This one's sorted!:\n " + tasks.get(index) + "\n" + Constants.LINE_STRING_BOTTOM); + saveTasksToFile(); + } + + /** + * Checks if the given index is a valid index within the tasks list. + * + * @param index The index to check + * @return true if the index is valid, false otherwise + */ + private boolean isValidIndex(int index) { + return index >= 0 && index < tasks.size(); + } + + /** + * Handles the "todo", "deadline", and "event" commands, adding a new task to the list. + * + * @param input The user input string containing the command and task details + * @throws IncyException If the task format is invalid + */ + void handleAddTask(String input) throws IncyException { + Task newTask = TaskFactory.createTask(input); + if (newTask != null) { + tasks.add(newTask); + printTaskAddedMessage(newTask); + saveTasksToFile(); + } + } + + /** + * Handles the "delete" command, removing a task from the list. + * + * @param input The user input string containing the command and task index + * @throws IncyException If the task index is invalid or the list is empty + */ + void handleDeleteCommand(String input) throws IncyException { + if (tasks.isEmpty()) { + throw new IncyException("Oi, nothin' to bin 'ere, yer list's bare!"); + } + + int index = Integer.parseInt(input.substring(7)) - 1; + if (!isValidIndex(index)) { + throw new IncyException("That ain't a legit number, try again with a proper one, yeah?"); + } + + Task deletedTask = tasks.get(index); + removeTaskAt(index); + System.out.println(Constants.LINE_STRING_TOP + Constants.ANSI_CYAN + + "Safe! I've dashed this task:\n" + + " " + deletedTask + "\n" + + "Now you've got " + tasks.size() + " tasks on your plate.\n" + + Constants.LINE_STRING_BOTTOM); + saveTasksToFile(); + } + + /** + * Handles the "find" command, searching for tasks containing a given keyword. + * + * @param input The user input string containing the command and keyword + * @throws IncyException If the keyword is missing + */ + void handleFindCommand(String input) throws IncyException { + if (input.length() <= 5) { + throw new IncyException("Oi, you forgot to tell me what to find, mate!"); + } + String keyword = input.substring(5).trim().toLowerCase(); + System.out.println(Constants.LINE_STRING_TOP); + boolean found = false; + int index = 1; + for (Task task : tasks) { + if (task.getDescription().toLowerCase().contains(keyword)) { + System.out.println(Constants.ANSI_CYAN + " " + index++ + ". " + task); + found = true; + } + } + if (!found) { + System.out.println(Constants.ANSI_RED + "No tasks found with the keyword '" + keyword + "', bruv."); + } + System.out.println(Constants.LINE_STRING_BOTTOM); + } + + /** + * Handles the "list by" command, listing tasks for a specific date. + * + * @param input The user input string containing the command and date + * @throws IncyException If the date format is invalid + */ + void handleListByDateCommand(String input) throws IncyException { + String dateString = input.substring(9).trim(); + LocalDate date; + try { + date = LocalDate.parse(dateString, DateTimeFormatter.ofPattern("yyyy-MM-dd")); + } catch (DateTimeParseException e) { + throw new IncyException("Invalid date format, mate. Use 'yyyy-MM-dd' format."); + } + System.out.println(Constants.LINE_STRING_BOTTOM); + boolean found = false; + for (Task task : tasks) { + if (task instanceof Deadline) { + Deadline deadline = (Deadline) task; + if (deadline.getBy().toLocalDate().equals(date)) { + System.out.println(Constants.ANSI_CYAN + "- " + deadline); + found = true; + } + } else if (task instanceof Event) { + Event event = (Event) task; + if (event.getStart().toLocalDate().equals(date) || event.getEnd().toLocalDate().equals(date)) { + System.out.println(Constants.ANSI_CYAN + "- " + event); + found = true; + } + } + } + if (!found) { + System.out.println(Constants.ANSI_RED + "No tasks found for the specified date, bruv."); + } + System.out.println(Constants.LINE_STRING_BOTTOM); + } + + /** + * Removes the task at the given index from the tasks list. + * + * @param index The index of the task to remove + */ + private void removeTaskAt(int index) { + tasks.remove(index); + } + + /** + * Prints a message indicating that a task has been added to the list. + * + * @param task The task that was added + */ + private void printTaskAddedMessage(Task task) { + System.out.println(Constants.LINE_STRING_TOP + Constants.ANSI_CYAN + + "Sorted! Your task's in the bag, innit mate:\n" + + " " + task + "\n" + + "You're now juggling " + tasks.size() + " tasks on your list, innit.\n" + + Constants.LINE_STRING_BOTTOM); + } + + /** + * Loads tasks from the data file and populates the tasks list. + */ + void loadTasksFromFile() { + Path dataFilePath = Paths.get(Constants.DATA_FOLDER, Constants.DATA_FILE); + if (Files.exists(dataFilePath)) { + try { + Scanner scanner = new Scanner(dataFilePath); + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + Task task = TaskFactory.createTaskFromLine(line); + if (task != null) { + tasks.add(task); + } + } + scanner.close(); + } catch (IOException e) { + TaskFactory.printFormatError("Failed to load tasks from file: " + e.getMessage()); + } + } + } + + /** + * Saves the tasks list to the data file. + */ + void saveTasksToFile() { + Path dataFilePath = Paths.get(Constants.DATA_FOLDER, Constants.DATA_FILE); + try { + FileWriter writer = new FileWriter(dataFilePath.toFile()); + for (Task task : tasks) { + writer.write(task.toFileString() + "\n"); + } + writer.close(); + } catch (IOException e) { + TaskFactory.printFormatError("Failed to save tasks to file: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/main/java/Todo.java b/src/main/java/Todo.java new file mode 100644 index 000000000..90a59e02f --- /dev/null +++ b/src/main/java/Todo.java @@ -0,0 +1,32 @@ +/** + * The Todo class represents a simple todo task. + * It extends the Task class and does not add any additional properties. + */ + +public class Todo extends Task { + /** + * Constructs a new Todo object with the given description. + * @param description The task description + */ + public Todo(String description) { + super(description); + } + + /** + * Returns a string representation of the Todo task. + * @return The string representation + */ + @Override + public String toString() { + return "[T]" + super.getStatusIcon() + " " + description; + } + + /** + * Returns a string representation of the Todo task suitable for writing to a file. + * @return The string representation + */ + @Override + public String toFileString() { + return "T | " + (isDone ? "1" : "0") + " | " + description; + } +} \ No newline at end of file diff --git a/src/main/java/build/Incy.class b/src/main/java/build/Incy.class new file mode 100644 index 000000000..ad4875810 Binary files /dev/null and b/src/main/java/build/Incy.class differ diff --git a/src/main/java/build/Task.class b/src/main/java/build/Task.class new file mode 100644 index 000000000..78809b371 Binary files /dev/null and b/src/main/java/build/Task.class differ