From 2224bd648ece67c0004e06685445b5da7c15b02d Mon Sep 17 00:00:00 2001 From: Koh Jia Xian <39460640+koh-jx@users.noreply.github.com> Date: Thu, 16 Sep 2021 15:17:35 +0800 Subject: [PATCH] Add sorting features Added sorting by completion status and date added, which uses LocalDateTime to compare dates. Also implemented the date added to Storage functions, and tweaked formatting of commands. Edited help command and user guide. --- docs/README.md | 38 +++++++++++++++++-- src/main/java/duke/command/Command.java | 26 ------------- .../java/duke/command/CommandAddDeadline.java | 4 +- .../java/duke/command/CommandAddEvent.java | 4 +- .../java/duke/command/CommandAddTodo.java | 4 +- src/main/java/duke/command/CommandHelp.java | 1 + src/main/java/duke/command/CommandList.java | 28 +++++++++++++- src/main/java/duke/command/CommandSort.java | 36 +++++++++++++----- src/main/java/duke/util/Storage.java | 27 ++++++++----- src/main/java/task/Task.java | 16 +++++++- src/main/java/task/TaskDeadline.java | 8 ++-- src/main/java/task/TaskEvent.java | 8 ++-- src/main/java/task/TaskList.java | 1 + src/main/java/task/TaskTodo.java | 8 ++-- 14 files changed, 145 insertions(+), 64 deletions(-) diff --git a/docs/README.md b/docs/README.md index 13e0cbe9a2..2375cea7f7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -47,11 +47,11 @@ Adds a deadline into your task list. **Example usage:** -`deadline taskname /by DD/MM/YYYY xxxxH` +`deadline taskname /by DD/MM/YYYY xxxx` * `taskname` - Name of deadline * `DD/MM/YYYY` - Date and month can be 1-2 digits long -* `xxxxH` - Time in 24-hour format *[Optional]* +* `xxxx` - Time in 24-hour format *[Optional]* **Expected outcome:** @@ -70,11 +70,11 @@ Adds an event into your task list. **Example usage:** -`event taskname /at DD/MM/YYYY xxxxH` +`event taskname /at DD/MM/YYYY xxxx` * `taskname` - Name of deadline * `DD/MM/YYYY` - Date and month can be 1-2 digits long -* `xxxxH` - Time in 24-hour format *[Optional]* +* `xxxx` - Time in 24-hour format *[Optional]* A confirmation response would be sent by Duke: @@ -161,6 +161,36 @@ There are ___ tasks in your list

+### `Sort` - Sorts your tasks + +Sorts your tasks based on the arguments provided. + +**Example usage (with and without optional arguments):** + +`sort` - Standard sort by name (no arguments) + +`list /date` - Sort by date and time + +`list /done` - Sort by completion status + +`list /name` - Sort by name (Same as no arguments) + +`list /added` - Sort by date in which task was added + +Arguments can be stacked, list will be sorted by the first one first, followed by the second, etc. + +`list /done /date` - Sort by completion status first. For those with the completion status, sort by date and time. + +`list /done /date /name` - Same as above, but for those with the same date and time, sorted in alphabetical order. + +**Expected outcome:** + +This command will overwrite your current list with the new sorted task list. + +A new list of all your tasks (if any) would be sent by Duke. + +

+ ### `help` - Display list of commands In-built command to display the list of possible commands and arguments within the app. diff --git a/src/main/java/duke/command/Command.java b/src/main/java/duke/command/Command.java index cdaca304e7..707dc82555 100644 --- a/src/main/java/duke/command/Command.java +++ b/src/main/java/duke/command/Command.java @@ -39,30 +39,4 @@ public String toString() { return commandName + " - " + description + '\n' + argString + '\n'; } - - protected static String getCommand(String str) - throws IllegalArgumentException{ - int index = getCommandArgumentSplitIndex(str); - return str.substring(0, index); - } - - protected static String getArgument(String str) - throws IllegalArgumentException { - - // Ensure validity; has a command and an argument - int index = getCommandArgumentSplitIndex(str); - return str.substring(index).trim(); - } - - private static int getCommandArgumentSplitIndex(String str) - throws IllegalArgumentException { - // Ensure validity; has a command and an argument - int index = str.indexOf(' '); - - if (index == -1) { - throw new IllegalArgumentException(Ui.MESSAGE_INVALID_ARG); - } - - return index; - } } diff --git a/src/main/java/duke/command/CommandAddDeadline.java b/src/main/java/duke/command/CommandAddDeadline.java index 98628db54c..4c282f185c 100644 --- a/src/main/java/duke/command/CommandAddDeadline.java +++ b/src/main/java/duke/command/CommandAddDeadline.java @@ -1,5 +1,6 @@ package duke.command; +import java.time.LocalDateTime; import java.time.format.DateTimeParseException; import duke.ui.Ui; @@ -43,7 +44,8 @@ public String execute() { input[0], DukeParser.getDate(input[1]), input[2], - false)); + false, + LocalDateTime.now())); } catch (DateTimeParseException e) { return Ui.MESSAGE_INVALID_DATE; } diff --git a/src/main/java/duke/command/CommandAddEvent.java b/src/main/java/duke/command/CommandAddEvent.java index d3206f9f90..45abd5cecd 100644 --- a/src/main/java/duke/command/CommandAddEvent.java +++ b/src/main/java/duke/command/CommandAddEvent.java @@ -1,5 +1,6 @@ package duke.command; +import java.time.LocalDateTime; import java.time.format.DateTimeParseException; import duke.ui.Ui; @@ -43,7 +44,8 @@ public String execute() { input[0], DukeParser.getDate(input[1]), input[2], - false)); + false, + LocalDateTime.now())); } catch (DateTimeParseException e) { return Ui.MESSAGE_INVALID_DATE; } diff --git a/src/main/java/duke/command/CommandAddTodo.java b/src/main/java/duke/command/CommandAddTodo.java index 06ae03739f..197d9bbe95 100644 --- a/src/main/java/duke/command/CommandAddTodo.java +++ b/src/main/java/duke/command/CommandAddTodo.java @@ -3,6 +3,8 @@ import task.TaskList; import task.TaskTodo; +import java.time.LocalDateTime; + /** * Command to add a to-do. */ @@ -33,6 +35,6 @@ public CommandAddTodo(TaskList taskList, String desc) { */ @Override public String execute() { - return taskList.add(new TaskTodo(desc, false)); + return taskList.add(new TaskTodo(desc, false, LocalDateTime.now())); } } diff --git a/src/main/java/duke/command/CommandHelp.java b/src/main/java/duke/command/CommandHelp.java index 4d67adbe0c..0d175fb2ba 100644 --- a/src/main/java/duke/command/CommandHelp.java +++ b/src/main/java/duke/command/CommandHelp.java @@ -33,6 +33,7 @@ private String displayHelp() { + new CommandDone(null, 0) + '\n' + new CommandDelete(null, 0) + '\n' + new CommandList(null, null) + '\n' + + new CommandSort(null, null) + '\n' + new CommandHelp() + '\n' + new CommandExit(); } diff --git a/src/main/java/duke/command/CommandList.java b/src/main/java/duke/command/CommandList.java index 2db5f8a5ac..80c1feb418 100644 --- a/src/main/java/duke/command/CommandList.java +++ b/src/main/java/duke/command/CommandList.java @@ -89,7 +89,8 @@ private ArrayList> listStringToFilter(String stringToParse) switch (command) { case ("name"): - results.add(task -> task.getDescription().contains(arg)); + results.add(task -> task.getDescription() + .toLowerCase().contains(arg.toLowerCase())); break; case ("date"): LocalDate date = DukeParser.getDate(arg); @@ -102,4 +103,29 @@ private ArrayList> listStringToFilter(String stringToParse) return results; } + + private String getCommand(String str) + throws IllegalArgumentException{ + int index = getCommandArgumentSplitIndex(str); + return str.substring(0, index); + } + + private String getArgument(String str) + throws IllegalArgumentException { + + // Ensure validity; has a command and an argument + int index = getCommandArgumentSplitIndex(str); + return str.substring(index).trim(); + } + + private int getCommandArgumentSplitIndex(String str) + throws IllegalArgumentException { + // Ensure validity; has a command and an argument + int index = str.indexOf(' '); + if (index == -1) { + throw new IllegalArgumentException(Ui.MESSAGE_INVALID_ARG); + } + + return index; + } } diff --git a/src/main/java/duke/command/CommandSort.java b/src/main/java/duke/command/CommandSort.java index 48c7b4995a..0753729cf5 100644 --- a/src/main/java/duke/command/CommandSort.java +++ b/src/main/java/duke/command/CommandSort.java @@ -25,12 +25,14 @@ public class CommandSort extends Command { * @param sortFilters Un-parsed list of filters. */ public CommandSort(TaskList taskList, String sortFilters) { - this.commandName = "list /name /date DD/MM/YYYY"; - this.description = "Toggles completion of task. Order of arguments does not matter"; + this.commandName = "sort /name /date"; + this.description = "Sorts list based on arguments provided. Having no arguments would default to" + + " sorting by /name. If there is more than 1 argument, the list will be sorted by the first." + + "followed by the second, etc..."; this.arguments = new String[]{ - "/name Optional argument to search for particular name", - "/date Optional date argument in DAY/MONTH/YEAR, " - + "to search for tasks on a particular date" + "/name Optional argument to sort by name", + "/date Optional argument to sort by date", + "/done Optional argument to sort by completion status" }; this.taskList = taskList; @@ -87,6 +89,12 @@ private ArrayList> sortStringToFilter(String stringToParse) case ("date"): results.add(createDateTimeComparator()); break; + case ("done"): + results.add(createDoneComparator()); + break; + case ("added"): + results.add(createAddedComparator()); + break; default: throw new IllegalArgumentException(Ui.MESSAGE_INVALID_ARG); } @@ -96,15 +104,23 @@ private ArrayList> sortStringToFilter(String stringToParse) } private Comparator createNameComparator() { - return Comparator.comparing(Task::getDescription); + return Comparator.comparing(t -> t.getDescription().toLowerCase()); } private Comparator createDateTimeComparator() { - return (o1, o2) -> { - int compareDate = o1.getDate().compareTo(o2.getDate()); + return (t1, t2) -> { + int compareDate = t1.getDate().compareTo(t2.getDate()); return compareDate == 0 - ? o1.getTime().compareTo(o2.getTime()) - : o1.getDate().compareTo(o2.getDate()); + ? t1.getTime().compareTo(t2.getTime()) + : t1.getDate().compareTo(t2.getDate()); }; } + + private Comparator createDoneComparator() { + return Comparator.comparing(Task::getDone); + } + + private Comparator createAddedComparator() { + return Comparator.comparing(Task::getAdded); + } } \ No newline at end of file diff --git a/src/main/java/duke/util/Storage.java b/src/main/java/duke/util/Storage.java index 7d650952ae..80b4e965d1 100644 --- a/src/main/java/duke/util/Storage.java +++ b/src/main/java/duke/util/Storage.java @@ -6,6 +6,7 @@ import java.io.IOException; import java.text.ParseException; import java.time.LocalDate; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Scanner; @@ -95,18 +96,25 @@ private static Task stringToTask(String task) throws ParseException { try { switch (taskType) { case "T": + // Create new To-do assert args.length == 3: "Invalid loaded task"; - return new TaskTodo(args[2], args[1].equals("1")); + return new TaskTodo(args[2], args[1].equals("1"), LocalDateTime.parse(args[3])); case "D": - assert args.length == 4 || args.length == 5: "Invalid loaded task"; - return args.length == 4 - ? new TaskDeadline(args[2], LocalDate.parse(args[3]), null, !args[1].equals("0")) - : new TaskDeadline(args[2], LocalDate.parse(args[3]), args[4], !args[1].equals("0")); + // Create new Deadline + assert args.length == 5 || args.length == 6: "Invalid loaded task"; + return args.length == 5 + ? new TaskDeadline(args[2], LocalDate.parse(args[3]), null, + !args[1].equals("0"), LocalDateTime.parse(args[4])) + : new TaskDeadline(args[2], LocalDate.parse(args[3]), args[4], + !args[1].equals("0"), LocalDateTime.parse(args[5])); case "E": - assert args.length == 4 || args.length == 5: "Invalid loaded task"; - return args.length == 4 - ? new TaskEvent(args[2], LocalDate.parse(args[3]), null, !args[1].equals("0")) - : new TaskEvent(args[2], LocalDate.parse(args[3]), args[4], !args[1].equals("0")); + // Create new Event + assert args.length == 5 || args.length == 6: "Invalid loaded task"; + return args.length == 5 + ? new TaskEvent(args[2], LocalDate.parse(args[3]), null, + !args[1].equals("0"), LocalDateTime.parse(args[4])) + : new TaskEvent(args[2], LocalDate.parse(args[3]), args[4], + !args[1].equals("0"), LocalDateTime.parse(args[5])); default: throw new ParseException(Ui.MESSAGE_INVALID_ARG + Ui.MESSAGE_FILE_NOT_READ, 0); } @@ -115,3 +123,4 @@ private static Task stringToTask(String task) throws ParseException { } } } + diff --git a/src/main/java/task/Task.java b/src/main/java/task/Task.java index 6e0f4128b5..722c5d6a3b 100644 --- a/src/main/java/task/Task.java +++ b/src/main/java/task/Task.java @@ -1,7 +1,7 @@ package task; import java.time.LocalDate; -import java.time.format.DateTimeParseException; +import java.time.LocalDateTime; import duke.ui.Ui; @@ -11,6 +11,7 @@ public abstract class Task { protected final String description; protected boolean isDone; + protected LocalDateTime dateTimeAdded; /** * Constructor. @@ -18,9 +19,10 @@ public abstract class Task { * @param input Description of task. * @param isDone Whether the task is complete. */ - public Task(String input, boolean isDone) { + public Task(String input, boolean isDone, LocalDateTime dateTimeAdded) { description = input; this.isDone = isDone; + this.dateTimeAdded = dateTimeAdded; } /** @@ -42,6 +44,16 @@ public String getDescription() { return description; } + public boolean getDone() { + return isDone; + } + + public LocalDateTime getAdded() { + return dateTimeAdded; + } + + + public abstract LocalDate getDate(); public abstract String getTime(); diff --git a/src/main/java/task/TaskDeadline.java b/src/main/java/task/TaskDeadline.java index 36745cd3ce..5ddbb1b844 100644 --- a/src/main/java/task/TaskDeadline.java +++ b/src/main/java/task/TaskDeadline.java @@ -3,6 +3,7 @@ import duke.ui.Ui; import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.format.DateTimeParseException; import java.util.Optional; @@ -21,9 +22,9 @@ public class TaskDeadline extends Task { * @param time Time of task (Optional argument), saved as "" otherwise. * @param done Completion status. */ - public TaskDeadline(String description, LocalDate date, String time, boolean done) + public TaskDeadline(String description, LocalDate date, String time, boolean done, LocalDateTime dateTimeAdded) throws DateTimeParseException { - super(description, done); + super(description, done, dateTimeAdded); this.by = date; this.time = Optional.ofNullable(time) .map(String::strip) @@ -60,7 +61,8 @@ public String saveString() { + (this.isDone ? "1" : "0") + '\t' + this.description + '\t' + this.by + '\t' - + this.time; + + this.time + '\t' + + this.dateTimeAdded; } /** diff --git a/src/main/java/task/TaskEvent.java b/src/main/java/task/TaskEvent.java index 011f2d959e..02d2dac546 100644 --- a/src/main/java/task/TaskEvent.java +++ b/src/main/java/task/TaskEvent.java @@ -1,6 +1,7 @@ package task; import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.format.DateTimeParseException; import java.util.Optional; @@ -19,8 +20,8 @@ public class TaskEvent extends Task { * @param time Time of Event. Optional, "" otherwise. * @param done Completion status. */ - public TaskEvent(String description, LocalDate date, String time, boolean done) { - super(description, done); + public TaskEvent(String description, LocalDate date, String time, boolean done, LocalDateTime dateTimeAdded) { + super(description, done, dateTimeAdded); this.at = date; this.time = Optional.ofNullable(time) .map(String::strip) @@ -57,7 +58,8 @@ public String saveString() { + (this.isDone ? "1" : "0") + '\t' + this.description + '\t' + this.at + '\t' - + this.time; + + this.time + '\t' + + this.dateTimeAdded; } /** diff --git a/src/main/java/task/TaskList.java b/src/main/java/task/TaskList.java index a353f91b26..4996f0bf4d 100644 --- a/src/main/java/task/TaskList.java +++ b/src/main/java/task/TaskList.java @@ -125,5 +125,6 @@ public void sort(ArrayList> filters) { for (int i = filters.size() - 1; i >= 0; i--) { tasks.sort(filters.get(i)); } + Storage.saveList(tasks); } } diff --git a/src/main/java/task/TaskTodo.java b/src/main/java/task/TaskTodo.java index 7161fe170b..7d395efa50 100644 --- a/src/main/java/task/TaskTodo.java +++ b/src/main/java/task/TaskTodo.java @@ -1,6 +1,7 @@ package task; import java.time.LocalDate; +import java.time.LocalDateTime; /** * To-do task event. @@ -13,8 +14,8 @@ public class TaskTodo extends Task { * @param description Description of task. * @param done Completion status. */ - public TaskTodo(String description, boolean done) { - super(description, done); + public TaskTodo(String description, boolean done, LocalDateTime dateTimeAdded) { + super(description, done, dateTimeAdded); } /** @@ -39,7 +40,8 @@ public String toString() { public String saveString() { return "T" + '\t' + (this.isDone ? "1" : "0") + '\t' - + this.description; + + this.description + '\t' + + this.dateTimeAdded; } /**