diff --git a/META-INF/MANIFEST.MF b/META-INF/MANIFEST.MF new file mode 100644 index 000000000..59499bce4 --- /dev/null +++ b/META-INF/MANIFEST.MF @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 + diff --git a/README.md b/README.md index 8715d4d91..a8111be76 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Duke project template +# duke.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. @@ -13,7 +13,7 @@ Prerequisites: JDK 11, update Intellij to the most recent version. 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: +3. After that, locate the `src/main/java/duke.duke.java` file, right-click it, and choose `Run duke.duke.main()` (if the code editor is showing compile errors, try restarting the IDE). If the setup is correct, you should see something like the below as the output: ``` Hello from ____ _ diff --git a/docs/README.md b/docs/README.md index 8077118eb..c6a3b7add 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,28 +2,77 @@ ## Features -### Feature-ABC +### Feature 1: Add Tasks -Description of the feature. +There are 3 types of tasks: **Todo, Event, and Deadline**. -### Feature-XYZ +- Create a Todo item by entering `todo DESCRIPTION` + + - e.g. todo Write User Guide + +- Create an Event item by entering `event DESCRIPTION /at EVENTDATE` + + - e.g. event CS2113 Tutorial /at 04032022 + +- Create a Deadline item by entering `deadline DESCRIPTION /by DUEDATETIME` + + - e.g. Submit IP /by 04032022 0000 -Description of the feature. +### Feature 2: List all Tasks -## Usage +Print a list of all tasks and their statuses. + +`list` + +### Feature 3: Mark/Unmark Tasks + +Mark tasks as completed as you complete them! -### `Keyword` - Describe action +- `mark INDEX` + - e.g. `mark 1` + - e.g. `unmark 2` -Describe the action and its outcome. -Example of usage: +### Feature 4: Delete Tasks -`keyword (optional arguments)` +Remove a task that shouldn't be there! -Expected outcome: +`delete INDEX` -Description of the outcome. +### Feature 5: List all Tasks + +Print a list of all tasks and their statuses. + +`list` + +## Usage +`todo Write User Guide` +`event CS2113 Tutorial /at 04032022` +`Submit IP /by 04032022 0000` + +```Expected Outcome +____________________________________________________________ +Here are the tasks in your list: +1. [T][ ] Write User Guide +2. [E][ ] CS2113 Tutorial (at: 03 Mar 2022) +3. [D][ ] Submit IP (by: 04 Mar 2022 00:00) +____________________________________________________________ +``` + +`mark 2` ``` -expected output +____________________________________________________________ +Nice! I've marked this task as done: +[E][X] CS2113 Tutorial (at: 03 Mar 2022) +____________________________________________________________ ``` + +`delete 2` +``` +Noted. I've removed this task: +[E][X] CS2113 Tutorial (at: 03 Mar 2022) +Now you have 2 tasks in the list +____________________________________________________________ +``` + diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 000000000..c74188174 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-slate \ No newline at end of file diff --git a/ip.zip b/ip.zip new file mode 100644 index 000000000..eaf1f310a Binary files /dev/null and b/ip.zip differ 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/duke/Duke.java b/src/main/java/duke/Duke.java new file mode 100644 index 000000000..047f3835d --- /dev/null +++ b/src/main/java/duke/Duke.java @@ -0,0 +1,39 @@ +package duke; +import duke.command.Command; +import duke.task.*; + +public class Duke { + + private TaskList tasks; + private Storage storage; + private Ui ui; + + public Duke() { + storage = new Storage("list.txt"); + tasks = new TaskList(storage.convertFileToList()); + ui = new Ui(); + } + + public void run() { + ui.showWelcome(); + boolean isExit = false; + while (!isExit) { + try { + ui.showLine(); + String command = ui.getUserInput(); + Command newCommand = Parser.parse(command); + newCommand.execute(tasks, ui, storage); + isExit = newCommand.getIsExit(); + } catch (DukeException e) { + ui.showError(e.getMessage()); + } finally { + ui.showLine(); + } + } + } + + public static void main(String[] args) { + Duke duke = new Duke(); + duke.run(); + } +} \ No newline at end of file diff --git a/src/main/java/duke/DukeException.java b/src/main/java/duke/DukeException.java new file mode 100644 index 000000000..761c3c441 --- /dev/null +++ b/src/main/java/duke/DukeException.java @@ -0,0 +1,7 @@ +package duke; + +public class DukeException extends Exception { + public DukeException(String message) { + super(message); + } +} \ No newline at end of file diff --git a/src/main/java/duke/Parser.java b/src/main/java/duke/Parser.java new file mode 100644 index 000000000..ff422aa0f --- /dev/null +++ b/src/main/java/duke/Parser.java @@ -0,0 +1,83 @@ +package duke; + +import duke.command.AddCommand; +import duke.command.Command; +import duke.command.DeleteCommand; +import duke.command.ExitCommand; +import duke.command.FindCommand; +import duke.command.ListCommand; +import duke.command.MarkCommand; +import duke.task.Deadline; +import duke.task.Event; +import duke.task.Todo; + +public class Parser { + + public static Command parse(String command) throws DukeException { + + String[] initialParse = command.split(" "); + int taskIndexString = 1; + String commandType = initialParse[0]; + String description; + String processedString[]; + int taskIndex; + + switch (commandType) { + case "list": + return new ListCommand(); + case "todo": + if (initialParse.length < 2) { + throw new DukeException("The description of a todo cannot be empty."); + } + description = command.split("todo")[1].trim(); + return new AddCommand(new Todo(description)); + case "deadline": + processedString = command.split("/by"); + return new AddCommand(processDeadline(processedString)); + case "event": + processedString = command.split("/at"); + return new AddCommand(processEvent(processedString)); + case "mark": + taskIndex = Integer.parseInt(initialParse[taskIndexString]) - 1; + return new MarkCommand(taskIndex, true); + case "unmark": + taskIndex = Integer.parseInt(initialParse[taskIndexString]) - 1; + return new MarkCommand(taskIndex, false); + case "delete": + taskIndex = Integer.parseInt(initialParse[taskIndexString]) - 1; + return new DeleteCommand(taskIndex); + case "find": + String searchTerm = initialParse[taskIndexString].trim(); + return new FindCommand(searchTerm); + case "bye": + return new ExitCommand(); + default: + throw new DukeException("Invalid command given"); + } + } + + private static String processTime(String[] processedString, String separator) { + final int TIMEINDEX = 1; + String time = processedString[TIMEINDEX].trim(); + return time; + } + + private static String processDescription(String[] processedString, String separator) { + final int PRETIMEINDEX = 0; + final int DESCRIPTIONINDEX = 1; + String description = processedString[PRETIMEINDEX].split(separator)[DESCRIPTIONINDEX].trim(); + return description; + } + + private static Event processEvent(String[] processedString) { + String at = processTime(processedString, "/at"); + String task = processDescription(processedString, "event"); + return new Event(task, at); + } + + private static Deadline processDeadline(String[] processedString) { + String by = processTime(processedString, "/by"); + String task = processDescription(processedString, "deadline"); + return new Deadline(task, by); + } +} \ No newline at end of file diff --git a/src/main/java/duke/Storage.java b/src/main/java/duke/Storage.java new file mode 100644 index 000000000..1c82dfd88 --- /dev/null +++ b/src/main/java/duke/Storage.java @@ -0,0 +1,100 @@ +package duke; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Scanner; + +import duke.task.Deadline; +import duke.task.Event; +import duke.task.Task; +import duke.task.Todo; + +/** + * Represents the controller to parse and write to a save file for tasks + */ +public class Storage { + private String filePath; + + + public Storage(String filePath) { + this.filePath = filePath; + } + + public void convertListToFile(ArrayList list) { + String text = ""; + for (int i = 0; i < list.size(); i++) { + Task currentTask = list.get(i); + text = text + currentTask.toString() + System.lineSeparator(); + } + try { + FileWriter fw = new FileWriter(filePath); + fw.write(text); + fw.close(); + } catch (IOException e) { + System.out.println(e.getMessage()); + } + } + + public ArrayList convertFileToList() { + ArrayList list = new ArrayList<>(); + File f = new File(filePath); + try { + Scanner s = new Scanner(f); + while (s.hasNext()) { + String currentLine = s.nextLine(); + String[] arrayElements = currentLine.split("\\|"); + String taskType = arrayElements[0].trim(); + Task newTask; + switch (taskType) { + case "T": + newTask = convertTodo(arrayElements); + list.add(newTask); + break; + case "D": + newTask = convertDeadline(arrayElements); + list.add(newTask); + break; + case "E": + newTask = convertEvent(arrayElements); + list.add(newTask); + break; + default: + break; + } + } + return list; + } catch (FileNotFoundException e) { + return list; + } + } + + private String getDescription(String[] arrayElements) { + int descriptionIndex = 2; + return arrayElements[descriptionIndex].trim(); + } + + private boolean getIsDone(String[] arrayElements) { + int booleanIndex = 1; + return arrayElements[booleanIndex].trim().equals("1"); + } + + private String getTime(String[] arrayElements) { + int timeIndex = 3; + return arrayElements[timeIndex].trim(); + } + + private Todo convertTodo(String[] arrayElements) { + return new Todo(getDescription(arrayElements), getIsDone(arrayElements)); + } + + private Deadline convertDeadline(String[] arrayElements) { + return new Deadline(getDescription(arrayElements), getIsDone(arrayElements), getTime(arrayElements)); + } + + private Event convertEvent(String[] arrayElements) { + return new Event(getDescription(arrayElements), getIsDone(arrayElements), getTime(arrayElements)); + } +} \ No newline at end of file diff --git a/src/main/java/duke/TaskList.java b/src/main/java/duke/TaskList.java new file mode 100644 index 000000000..94c07a094 --- /dev/null +++ b/src/main/java/duke/TaskList.java @@ -0,0 +1,41 @@ +package duke; + +import java.util.ArrayList; +import duke.task.Task; + +public class TaskList { + private ArrayList taskList; + public TaskList(ArrayList taskList) { + this.taskList = taskList; + } + + public Task getTask(int index) { + return taskList.get(index); + } + + public ArrayList getTaskList() { + return this.taskList; + } + + public int getSize() { + return taskList.size(); + } + + public void removeTask(Task task) { + taskList.remove(task); + } + + public void addTask(Task task) { + taskList.add(task); + } + + public void markTask(Task task, boolean isDone) { + if(isDone){ + task.setMark(); + } + else{ + task.setUnmark(); + } + } + +} \ No newline at end of file diff --git a/src/main/java/duke/Ui.java b/src/main/java/duke/Ui.java new file mode 100644 index 000000000..4c88a5240 --- /dev/null +++ b/src/main/java/duke/Ui.java @@ -0,0 +1,93 @@ +package duke; + +import java.util.Scanner; +import duke.task.Task; + +public class Ui { + + private Scanner inputScanner; + + public Ui() { + inputScanner = new Scanner(System.in); + } + + public void showWelcome() { + String logo = " ____ _ \n" + + "| _ \\ _ _| | _____ \n" + + "| | | | | | | |/ / _ \\\n" + + "| |_| | |_| | < __/\n" + + "|____/ \\__,_|_|\\_\\___|\n"; + System.out.println("Hello from\n" + logo); + System.out.println("Hello! I'm Duke!\n What can I do for you?"); + } + + + public String getUserInput() { + String userInput = inputScanner.nextLine(); + return userInput; + } + + + public void showLine() { + System.out.println("____________________________________________________________"); + } + + + public void showBye() { + System.out.println("Bye. Hope to see you again soon!"); + } + + public void showError(String message) { + System.out.println(message); + } + + + public void printTask(Task task) { + System.out.println(task.getTask()); + } + + + public void printSize(int size) { + System.out.println("Now you have " + size + " tasks in the list"); + } + + + public void printMarkMessage(boolean isDone) { + if (isDone) { + System.out.println("Nice! I've marked this task as done:"); + } else { + System.out.println("OK, I've marked this task as not done yet:"); + } + } + + public void printAddMessage(Task task, int size) { + System.out.println("Got it. I've added this task:"); + printTask(task); + printSize(size); + } + + public void printRemoveMessage(Task task, int size) { + System.out.println("Noted. I've removed this task:"); + printTask(task); + printSize(size); + } + + public void printMatchingTasks(TaskList tasks, String searchTerm) { + System.out.println("Here are the matching tasks in your list:"); + for (int i = 0; i < tasks.getSize(); i++) { + Task task = tasks.getTask(i); + if (task.getTask().contains(searchTerm)) { + System.out.println(i + 1 + ". " + task.getTask()); + } + } + } + + + public void printTaskList(TaskList tasks) { + System.out.println("Here are the tasks in your list:"); + for (int i = 0; i < tasks.getSize(); i++) { + System.out.println(i + 1 + ". " + tasks.getTask(i).getTask()); + } + } + +} \ No newline at end of file diff --git a/src/main/java/duke/command/AddCommand.java b/src/main/java/duke/command/AddCommand.java new file mode 100644 index 000000000..e5256133d --- /dev/null +++ b/src/main/java/duke/command/AddCommand.java @@ -0,0 +1,21 @@ +package duke.command; + +import duke.Storage; +import duke.TaskList; +import duke.Ui; +import duke.task.Task; + + +public class AddCommand extends Command { + private Task newTask; + + public AddCommand(Task task) { + super(); + this.newTask = task; + } + + public void execute(TaskList tasks, Ui ui, Storage storage) { + tasks.addTask(newTask); + ui.printAddMessage(newTask, tasks.getSize()); + } +} \ No newline at end of file diff --git a/src/main/java/duke/command/Command.java b/src/main/java/duke/command/Command.java new file mode 100644 index 000000000..0625130a1 --- /dev/null +++ b/src/main/java/duke/command/Command.java @@ -0,0 +1,23 @@ +package duke.command; + +import duke.Storage; +import duke.TaskList; +import duke.Ui; + +public abstract class Command { + private boolean isExit; + + public Command() { + this.isExit = false; + } + + public void setIsExit(boolean isExit) { + this.isExit = isExit; + } + + public boolean getIsExit() { + return this.isExit; + } + + public abstract void execute(TaskList tasks, Ui ui, Storage storage); +} diff --git a/src/main/java/duke/command/DeleteCommand.java b/src/main/java/duke/command/DeleteCommand.java new file mode 100644 index 000000000..c7704bb27 --- /dev/null +++ b/src/main/java/duke/command/DeleteCommand.java @@ -0,0 +1,21 @@ +package duke.command; + +import duke.Storage; +import duke.TaskList; +import duke.Ui; +import duke.task.Task; + + +public class DeleteCommand extends Command { + private int taskIndex; + + public DeleteCommand(int index) { + this.taskIndex = index; + } + + public void execute(TaskList tasks, Ui ui, Storage storage) { + Task task = tasks.getTask(taskIndex); + tasks.removeTask(task); + ui.printRemoveMessage(task, tasks.getSize()); + } +} \ No newline at end of file diff --git a/src/main/java/duke/command/ExitCommand.java b/src/main/java/duke/command/ExitCommand.java new file mode 100644 index 000000000..65af65d4a --- /dev/null +++ b/src/main/java/duke/command/ExitCommand.java @@ -0,0 +1,15 @@ +package duke.command; + +import duke.Storage; +import duke.TaskList; +import duke.Ui; + +public class ExitCommand extends Command { + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + ui.showBye(); + storage.convertListToFile(tasks.getTaskList()); + setIsExit(true); + } +} \ No newline at end of file diff --git a/src/main/java/duke/command/FindCommand.java b/src/main/java/duke/command/FindCommand.java new file mode 100644 index 000000000..9f1b7ad87 --- /dev/null +++ b/src/main/java/duke/command/FindCommand.java @@ -0,0 +1,20 @@ +package duke.command; + +import duke.Storage; +import duke.TaskList; +import duke.Ui; + + +public class FindCommand extends Command { + private String searchTerm; + + public FindCommand(String searchTerm) { + super(); + this.searchTerm = searchTerm; + } + + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + ui.printMatchingTasks(tasks, searchTerm); + } +} \ No newline at end of file diff --git a/src/main/java/duke/command/ListCommand.java b/src/main/java/duke/command/ListCommand.java new file mode 100644 index 000000000..fb34fdfac --- /dev/null +++ b/src/main/java/duke/command/ListCommand.java @@ -0,0 +1,13 @@ +package duke.command; + +import duke.Storage; +import duke.TaskList; +import duke.Ui; + + +public class ListCommand extends Command { + @Override + public void execute(TaskList tasks, Ui ui, Storage storage) { + ui.printTaskList(tasks); + } +} \ No newline at end of file diff --git a/src/main/java/duke/command/MarkCommand.java b/src/main/java/duke/command/MarkCommand.java new file mode 100644 index 000000000..d362ea35e --- /dev/null +++ b/src/main/java/duke/command/MarkCommand.java @@ -0,0 +1,24 @@ +package duke.command; + +import duke.Storage; +import duke.TaskList; +import duke.Ui; +import duke.task.Task; + +public class MarkCommand extends Command { + private int taskIndex; + private boolean isDone; + + + public MarkCommand(int index, boolean isDone) { + this.taskIndex = index; + this.isDone = isDone; + } + + public void execute(TaskList tasks, Ui ui, Storage storage) { + Task task = tasks.getTask(taskIndex); + tasks.markTask(task, isDone); + ui.printMarkMessage(isDone); + ui.printTask(task); + } +} \ No newline at end of file diff --git a/src/main/java/duke/task/Deadline.java b/src/main/java/duke/task/Deadline.java new file mode 100644 index 000000000..4e6d9c5d3 --- /dev/null +++ b/src/main/java/duke/task/Deadline.java @@ -0,0 +1,19 @@ +package duke.task; + +public class Deadline extends Task { + protected String dueDate; + + public Deadline(String description, String dueDate){ + super(description); + this.dueDate = dueDate; + } + + public Deadline(String description, boolean isTaskDone, String dueDate) { + super(description, isTaskDone); + this.dueDate = dueDate; + } + + public String getDescription(){ + return "[D]" + super.getDescription() + " (by: " + dueDate + ")"; + } +} diff --git a/src/main/java/duke/task/Event.java b/src/main/java/duke/task/Event.java new file mode 100644 index 000000000..7b61d79af --- /dev/null +++ b/src/main/java/duke/task/Event.java @@ -0,0 +1,18 @@ +package duke.task; + +public class Event extends Task { + protected String eventDate; + + public Event(String description, String eventDate){ + super(description); + this.eventDate = eventDate; + } + public Event(String description, boolean isTaskDone, String eventDate) { + super(description, isTaskDone); + this.eventDate = eventDate; + } + public String getDescription(){ + return "[E]" + super.getDescription() + " (by: " + eventDate + ")"; + } + +} diff --git a/src/main/java/duke/task/Task.java b/src/main/java/duke/task/Task.java new file mode 100644 index 000000000..0b9e9a1f0 --- /dev/null +++ b/src/main/java/duke/task/Task.java @@ -0,0 +1,45 @@ +package duke.task; + +public class Task { + + protected String description; + protected boolean isDone; + + public Task(String description){ + this.description = description; + this.isDone = false; + } + + public Task(String description, boolean isTaskDone){ + this.description = description; + this.isDone = isTaskDone; + } + + public String getTask() { + return showStatus() + this.description; + } + public String getDescription(){ + return showStatus() + description; + } + public void setDescription(String input){ + description = input; + } + public boolean getTaskStatus(){ + return isDone; + } + public void setMark(){ + this.isDone = true; + } + public void setUnmark(){ + this.isDone = false; + } + public String showStatus(){ + if(isDone==true){ + return("[X] "); + } + else{ + return("[ ] "); + } + } + +} diff --git a/src/main/java/duke/task/Todo.java b/src/main/java/duke/task/Todo.java new file mode 100644 index 000000000..229214562 --- /dev/null +++ b/src/main/java/duke/task/Todo.java @@ -0,0 +1,15 @@ +package duke.task; + +public class Todo extends Task { + + public Todo(String description){ + super(description); + } + public Todo(String description, boolean isTaskDone){ + super(description); + } + public String getDescription(){ + return "[T]" + super.getDescription(); + } + +} diff --git a/text-ui-test/runtest.bat b/text-ui-test/runtest.bat index 087374464..7eb6d3cdd 100644 --- a/text-ui-test/runtest.bat +++ b/text-ui-test/runtest.bat @@ -15,7 +15,7 @@ IF ERRORLEVEL 1 ( REM no error here, errorlevel == 0 REM run the program, feed commands from input.txt file and redirect the output to the ACTUAL.TXT -java -classpath ..\bin Duke < input.txt > ACTUAL.TXT +java -classpath ..\bin duke.duke < input.txt > ACTUAL.TXT REM compare the output to the expected output FC ACTUAL.TXT EXPECTED.TXT