diff --git a/docs/diagrams/Diagrams.pptx b/docs/diagrams/Diagrams.pptx index 015062ee1802..066315017744 100644 Binary files a/docs/diagrams/Diagrams.pptx and b/docs/diagrams/Diagrams.pptx differ diff --git a/docs/images/UiClassDiagram.png b/docs/images/UiClassDiagram.png index 3db1531b6fa1..6ce7a27bc08f 100644 Binary files a/docs/images/UiClassDiagram.png and b/docs/images/UiClassDiagram.png differ diff --git a/src/main/java/seedu/agendum/commons/events/ui/JumpToListRequestEvent.java b/src/main/java/seedu/agendum/commons/events/ui/JumpToListRequestEvent.java new file mode 100644 index 000000000000..0446602c06a2 --- /dev/null +++ b/src/main/java/seedu/agendum/commons/events/ui/JumpToListRequestEvent.java @@ -0,0 +1,25 @@ +package seedu.agendum.commons.events.ui; + +import seedu.agendum.commons.events.BaseEvent; +import seedu.agendum.model.task.Task; + +//@@author A0148031R +/** + * Indicates a request to jump to the list of tasks + */ +public class JumpToListRequestEvent extends BaseEvent { + + public final Task targetTask; + public final boolean hasMultipleTasks; + + public JumpToListRequestEvent(Task task, boolean hasMultipleTasks) { + this.targetTask = task; + this.hasMultipleTasks = hasMultipleTasks; + } + + @Override + public String toString() { + return this.getClass().getSimpleName(); + } + +} \ No newline at end of file diff --git a/src/main/java/seedu/agendum/logic/commands/MarkCommand.java b/src/main/java/seedu/agendum/logic/commands/MarkCommand.java index 3027bacb3022..e918e751c274 100644 --- a/src/main/java/seedu/agendum/logic/commands/MarkCommand.java +++ b/src/main/java/seedu/agendum/logic/commands/MarkCommand.java @@ -25,7 +25,7 @@ public class MarkCommand extends Command { + "(The id must be a positive number)\n" + "Example: " + COMMAND_WORD + " 1 3 5-6"; - public static final String MESSAGE_MARK_TASK_SUCCESS = "Marked Task(s): %1$s"; + public static final String MESSAGE_MARK_TASK_SUCCESS = "Marked Task(s)!"; public static final String MESSAGE_DUPLICATE = "Hey, the task already exists"; public ArrayList targetIndexes; @@ -63,8 +63,7 @@ public CommandResult execute() { return new CommandResult(MESSAGE_DUPLICATE); } - return new CommandResult(String.format(MESSAGE_MARK_TASK_SUCCESS, - CommandResult.tasksToString(tasksToMark, targetIndexes))); + return new CommandResult(MESSAGE_MARK_TASK_SUCCESS); } private boolean isAnyIndexInvalid(UnmodifiableObservableList lastShownList) { diff --git a/src/main/java/seedu/agendum/logic/commands/RenameCommand.java b/src/main/java/seedu/agendum/logic/commands/RenameCommand.java index adc855d248d2..c8eb30866d79 100644 --- a/src/main/java/seedu/agendum/logic/commands/RenameCommand.java +++ b/src/main/java/seedu/agendum/logic/commands/RenameCommand.java @@ -21,7 +21,7 @@ public class RenameCommand extends Command { + COMMAND_FORMAT + "\n" + "Example: " + COMMAND_WORD + " 2 Watch Star Trek"; - public static final String MESSAGE_SUCCESS = "Task #%1$s renamed: %2$s"; + public static final String MESSAGE_SUCCESS = "Task renamed: %1$s"; public static final String MESSAGE_DUPLICATE_TASK = "Hey, the task already exists"; public int targetIndex = -1; @@ -60,7 +60,7 @@ public CommandResult execute() { } catch (TaskNotFoundException e) { assert false : "The target task cannot be missing"; } - return new CommandResult(String.format(MESSAGE_SUCCESS, targetIndex, newTaskName)); + return new CommandResult(String.format(MESSAGE_SUCCESS, newTaskName)); } diff --git a/src/main/java/seedu/agendum/logic/commands/ScheduleCommand.java b/src/main/java/seedu/agendum/logic/commands/ScheduleCommand.java index 949a9323e9b7..ab5f90fb4ed3 100644 --- a/src/main/java/seedu/agendum/logic/commands/ScheduleCommand.java +++ b/src/main/java/seedu/agendum/logic/commands/ScheduleCommand.java @@ -27,7 +27,7 @@ public class ScheduleCommand extends Command { + "(The id must be a positive number)\n" + "Example: " + COMMAND_WORD + " 2 from 7am to 9am"; - public static final String MESSAGE_SUCCESS = "Rescheduled Task #%1$s: %2$s"; + public static final String MESSAGE_SUCCESS = "Task rescheduled: %1$s"; public static final String MESSAGE_DUPLICATE_TASK = "This task already exists!"; public int targetIndex = -1; @@ -70,7 +70,7 @@ public CommandResult execute() { assert false : "The target task cannot be missing"; } - return new CommandResult(String.format(MESSAGE_SUCCESS, targetIndex, updatedTask)); + return new CommandResult(String.format(MESSAGE_SUCCESS, updatedTask)); } //@author diff --git a/src/main/java/seedu/agendum/logic/commands/UnmarkCommand.java b/src/main/java/seedu/agendum/logic/commands/UnmarkCommand.java index c3663b06e669..8c5fd4ae081e 100644 --- a/src/main/java/seedu/agendum/logic/commands/UnmarkCommand.java +++ b/src/main/java/seedu/agendum/logic/commands/UnmarkCommand.java @@ -25,7 +25,7 @@ public class UnmarkCommand extends Command { + "(The id must be a positive number)\n" + "Example: " + COMMAND_WORD + " 11-13 15"; - public static final String MESSAGE_UNMARK_TASK_SUCCESS = "Unmarked Task(s): %1$s"; + public static final String MESSAGE_UNMARK_TASK_SUCCESS = "Unmarked Task(s)!"; public static final String MESSAGE_DUPLICATE = "Hey, the task already exists"; public ArrayList targetIndexes; @@ -63,8 +63,7 @@ public CommandResult execute() { return new CommandResult(MESSAGE_DUPLICATE); } - return new CommandResult(String.format(MESSAGE_UNMARK_TASK_SUCCESS, - CommandResult.tasksToString(tasksToUnmark, targetIndexes))); + return new CommandResult(MESSAGE_UNMARK_TASK_SUCCESS); } private boolean isAnyIndexInvalid(UnmodifiableObservableList lastShownList) { diff --git a/src/main/java/seedu/agendum/model/task/ReadOnlyTask.java b/src/main/java/seedu/agendum/model/task/ReadOnlyTask.java index 9a1a55709b70..815b89d9debe 100644 --- a/src/main/java/seedu/agendum/model/task/ReadOnlyTask.java +++ b/src/main/java/seedu/agendum/model/task/ReadOnlyTask.java @@ -13,6 +13,8 @@ public interface ReadOnlyTask { boolean isCompleted(); boolean isUpcoming(); boolean isOverdue(); + boolean isEvent(); + boolean hasDeadline(); boolean hasTime(); Optional getStartDateTime(); Optional getEndDateTime(); diff --git a/src/main/java/seedu/agendum/model/task/Task.java b/src/main/java/seedu/agendum/model/task/Task.java index fca8114e6cbc..8c5ddd4d2e58 100644 --- a/src/main/java/seedu/agendum/model/task/Task.java +++ b/src/main/java/seedu/agendum/model/task/Task.java @@ -99,6 +99,16 @@ public boolean hasTime() { return (getStartDateTime().isPresent() || getEndDateTime().isPresent()); } + @Override + public boolean isEvent() { + return getStartDateTime().isPresent(); + } + + @Override + public boolean hasDeadline() { + return !getStartDateTime().isPresent() && getEndDateTime().isPresent(); + } + @Override public Optional getStartDateTime() { return Optional.ofNullable(startDateTime); diff --git a/src/main/java/seedu/agendum/model/task/UniqueTaskList.java b/src/main/java/seedu/agendum/model/task/UniqueTaskList.java index 91802f3f027f..8c08a2f07b27 100644 --- a/src/main/java/seedu/agendum/model/task/UniqueTaskList.java +++ b/src/main/java/seedu/agendum/model/task/UniqueTaskList.java @@ -3,7 +3,9 @@ import javafx.collections.FXCollections; import javafx.collections.ObservableList; import seedu.agendum.commons.util.CollectionUtil; +import seedu.agendum.commons.core.EventsCenter; import seedu.agendum.commons.core.LogsCenter; +import seedu.agendum.commons.events.ui.JumpToListRequestEvent; import seedu.agendum.commons.exceptions.DuplicateDataException; import java.util.*; @@ -60,10 +62,13 @@ public void add(Task toAdd) throws DuplicateTaskException { if (contains(toAdd)) { logger.fine("[TASK LIST] --- Duplicate Task: " + toAdd.getDetailedText()); + EventsCenter.getInstance().post(new JumpToListRequestEvent(toAdd, false)); throw new DuplicateTaskException(); } internalList.add(toAdd); + EventsCenter.getInstance().post(new JumpToListRequestEvent(toAdd, false)); + logger.fine("[TASK LIST] --- Added a Task: " + toAdd.getDetailedText()); } @@ -107,10 +112,12 @@ public boolean update(ReadOnlyTask toUpdate, Task updatedTask) if (contains(updatedTask)) { logger.fine("[TASK LIST] --- Duplicate Task: " + toUpdate.getDetailedText()); + EventsCenter.getInstance().post(new JumpToListRequestEvent(updatedTask, true)); throw new DuplicateTaskException(); } internalList.set(taskIndex, updatedTask); + EventsCenter.getInstance().post(new JumpToListRequestEvent(updatedTask, true)); logger.fine("[TASK LIST] --- Updated Task: " + toUpdate.getDetailedText() + " updated to " + updatedTask.getDetailedText()); diff --git a/src/main/java/seedu/agendum/ui/CommandBox.java b/src/main/java/seedu/agendum/ui/CommandBox.java index 7278f5e154d8..979dd62b8a92 100644 --- a/src/main/java/seedu/agendum/ui/CommandBox.java +++ b/src/main/java/seedu/agendum/ui/CommandBox.java @@ -33,6 +33,7 @@ public class CommandBox extends UiPart { private static final String FIND_COMMAND = "find "; private static final String HELP_COMMAND = "help"; private static final String RESULT_FEEDBACK = "Result: "; + private static final String ERROR = "error"; private static final String FIND_COMMAND_REMINDER_MESSAGE = "Showing search results now, press ESC to go back and" + " view all tasks"; @@ -184,7 +185,7 @@ private void restoreCommandText() { * Sets the command box style to indicate an error */ private void setStyleToIndicateIncorrectCommand() { - commandTextField.getStyleClass().add("error"); + commandTextField.getStyleClass().add(ERROR); } } diff --git a/src/main/java/seedu/agendum/ui/CompletedTasksPanel.java b/src/main/java/seedu/agendum/ui/CompletedTasksPanel.java index b017e9168e99..9218216934b8 100644 --- a/src/main/java/seedu/agendum/ui/CompletedTasksPanel.java +++ b/src/main/java/seedu/agendum/ui/CompletedTasksPanel.java @@ -1,12 +1,19 @@ package seedu.agendum.ui; +import javafx.animation.PauseTransition; import javafx.application.Platform; import javafx.collections.ObservableList; +import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.scene.control.Control; import javafx.scene.control.ListCell; import javafx.scene.control.ListView; +import javafx.scene.control.MultipleSelectionModel; +import javafx.scene.control.SelectionMode; +import javafx.scene.input.MouseEvent; +import javafx.util.Duration; import seedu.agendum.model.task.ReadOnlyTask; +import seedu.agendum.model.task.Task; //@@author A0148031R /** @@ -15,6 +22,7 @@ public class CompletedTasksPanel extends TasksPanel { private static final String FXML = "CompletedTasksPanel.fxml"; private static ObservableList mainTaskList; + private MultipleSelectionModel selectionModel; @FXML private ListView completedTasksListView; @@ -29,12 +37,38 @@ protected void setConnections(ObservableList taskList) { mainTaskList = taskList; completedTasksListView.setItems(taskList.filtered(task -> task.isCompleted())); completedTasksListView.setCellFactory(listView -> new CompletedTasksListViewCell()); + configure(); + } + + private void configure() { + selectionModel = completedTasksListView.getSelectionModel(); + completedTasksListView.setSelectionModel(null); + completedTasksListView.addEventFilter(MouseEvent.MOUSE_PRESSED, new EventHandler() { + @Override + public void handle(MouseEvent event) { + event.consume(); + } + }); } - public void scrollTo(int index) { + public void scrollTo(Task task, boolean hasMultipleTasks) { Platform.runLater(() -> { + + int index = mainTaskList.indexOf(task) - mainTaskList.filtered(t -> !t.isCompleted()).size(); completedTasksListView.scrollTo(index); - completedTasksListView.getSelectionModel().clearAndSelect(index); + completedTasksListView.setSelectionModel(selectionModel); + + if(hasMultipleTasks) { + completedTasksListView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); + completedTasksListView.getSelectionModel().select(index); + } else { + completedTasksListView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); + completedTasksListView.getSelectionModel().clearAndSelect(index); + } + + PauseTransition delay = new PauseTransition(Duration.seconds(5)); + delay.setOnFinished(event -> completedTasksListView.getSelectionModel().clearSelection(index)); + delay.play(); }); } diff --git a/src/main/java/seedu/agendum/ui/FloatingTasksPanel.java b/src/main/java/seedu/agendum/ui/FloatingTasksPanel.java index fab2fc102cee..ce4bf2e97fb6 100644 --- a/src/main/java/seedu/agendum/ui/FloatingTasksPanel.java +++ b/src/main/java/seedu/agendum/ui/FloatingTasksPanel.java @@ -1,12 +1,19 @@ package seedu.agendum.ui; +import javafx.animation.PauseTransition; import javafx.application.Platform; import javafx.collections.ObservableList; +import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.scene.control.Control; import javafx.scene.control.ListCell; import javafx.scene.control.ListView; +import javafx.scene.control.MultipleSelectionModel; +import javafx.scene.control.SelectionMode; +import javafx.scene.input.MouseEvent; +import javafx.util.Duration; import seedu.agendum.model.task.ReadOnlyTask; +import seedu.agendum.model.task.Task; //@@author A0148031R /** @@ -15,6 +22,7 @@ public class FloatingTasksPanel extends TasksPanel { private static final String FXML = "FloatingTasksPanel.fxml"; private static ObservableList mainTaskList; + private MultipleSelectionModel selectionModel; @FXML private ListView floatingTasksListView; @@ -29,12 +37,39 @@ protected void setConnections(ObservableList taskList) { mainTaskList = taskList; floatingTasksListView.setItems(taskList.filtered(task -> !task.isCompleted() && !task.hasTime())); floatingTasksListView.setCellFactory(listView -> new FloatingTasksListViewCell()); + configure(); + } + + private void configure() { + selectionModel = floatingTasksListView.getSelectionModel(); + floatingTasksListView.setSelectionModel(null); + floatingTasksListView.addEventFilter(MouseEvent.MOUSE_PRESSED, new EventHandler() { + @Override + public void handle(MouseEvent event) { + event.consume(); + } + }); } - public void scrollTo(int index) { + public void scrollTo(Task task, boolean hasMultipleTasks) { Platform.runLater(() -> { + + int index = mainTaskList.indexOf(task) - + mainTaskList.filtered(t -> (t.hasTime() && !t.isCompleted())).size(); floatingTasksListView.scrollTo(index); - floatingTasksListView.getSelectionModel().clearAndSelect(index); + floatingTasksListView.setSelectionModel(selectionModel); + + if(hasMultipleTasks) { + floatingTasksListView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); + floatingTasksListView.getSelectionModel().select(index); + } else { + floatingTasksListView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); + floatingTasksListView.getSelectionModel().clearAndSelect(index); + } + + PauseTransition delay = new PauseTransition(Duration.seconds(4)); + delay.setOnFinished(event -> floatingTasksListView.getSelectionModel().clearSelection(index)); + delay.play(); }); } @@ -53,6 +88,7 @@ protected void updateItem(ReadOnlyTask task, boolean empty) { setText(null); } else { setGraphic(TaskCard.load(task, mainTaskList.indexOf(task) + 1).getLayout()); +// scrollTo(); } } } diff --git a/src/main/java/seedu/agendum/ui/MainWindow.java b/src/main/java/seedu/agendum/ui/MainWindow.java index d0f0794d6385..39b2f097932d 100644 --- a/src/main/java/seedu/agendum/ui/MainWindow.java +++ b/src/main/java/seedu/agendum/ui/MainWindow.java @@ -34,7 +34,8 @@ public class MainWindow extends UiPart { private static final String ICON = "/images/agendum_icon.png"; private static final String FXML = "MainWindow.fxml"; - public static final String LIST_COMMAND = "list"; + private static final String LIST_COMMAND = "list"; + private static final String UNDO_COMMAND = "undo"; private Logic logic; @@ -123,7 +124,7 @@ private void configure(String appTitle, String toDoListName, Config config, User * Set shortcut key for help menu item */ private void setAccelerators() { - helpMenuItem.setAccelerator(KeyCombination.valueOf("F5")); + helpMenuItem.setAccelerator(new KeyCodeCombination(KeyCode.H, KeyCombination.CONTROL_DOWN)); } /** @@ -132,14 +133,15 @@ private void setAccelerators() { private void configureHelpWindowToggle() { scene.addEventFilter(KeyEvent.KEY_PRESSED, new EventHandler() { KeyCombination toggleHelpWindow = new KeyCodeCombination(KeyCode.H, KeyCombination.CONTROL_DOWN); - + KeyCombination undo = new KeyCodeCombination(KeyCode.Z, KeyCombination.CONTROL_DOWN); @Override public void handle(KeyEvent evt) { if (toggleHelpWindow.match(evt) && messagePlaceHolder.getChildren().size() == 0) { openHelpWindow(); } else if (toggleHelpWindow.match(evt) && messagePlaceHolder.getChildren().size() != 0) { closeHelpWindow(); - + } else if(undo.match(evt)) { + logic.execute(UNDO_COMMAND); } } }); @@ -203,16 +205,17 @@ public AnchorPane getFloatingTasksPlaceHolder() { return floatingTasksPlaceHolder; } - public TasksPanel getUpcomingTasksPanel() { - return (UpcomingTasksPanel)this.upcomingTasksPanel; + public UpcomingTasksPanel getUpcomingTasksPanel() { + return (UpcomingTasksPanel) this.upcomingTasksPanel; } - - public TasksPanel getCompletedTasksPanel() { - return (CompletedTasksPanel)this.completedTasksPanel; + + public CompletedTasksPanel getCompletedTasksPanel() { + return (CompletedTasksPanel) this.completedTasksPanel; } - - public TasksPanel getFloatingasksPanel() { - return (FloatingTasksPanel)this.floatingTasksPanel; + + public FloatingTasksPanel getFloatingasksPanel() { + return (FloatingTasksPanel) this.floatingTasksPanel; + } /** diff --git a/src/main/java/seedu/agendum/ui/ResultPopUp.java b/src/main/java/seedu/agendum/ui/ResultPopUp.java index f16332785208..53dd1f0e03b5 100644 --- a/src/main/java/seedu/agendum/ui/ResultPopUp.java +++ b/src/main/java/seedu/agendum/ui/ResultPopUp.java @@ -69,15 +69,10 @@ public void postMessage(String message) { show(); PauseTransition delay = new PauseTransition(Duration.seconds(5)); - delay.setOnFinished(event -> reFocusRoot()); + delay.setOnFinished(event -> dialogStage.setOpacity(0)); delay.play(); } - public void reFocusRoot() { - dialogStage.setOpacity(0); - root.requestFocus(); - } - public void show() { dialogStage.setOpacity(1.0); dialogStage.sizeToScene(); diff --git a/src/main/java/seedu/agendum/ui/TaskCard.java b/src/main/java/seedu/agendum/ui/TaskCard.java index 3cbf55b6b12b..1a082fd9f84e 100644 --- a/src/main/java/seedu/agendum/ui/TaskCard.java +++ b/src/main/java/seedu/agendum/ui/TaskCard.java @@ -5,85 +5,130 @@ import java.util.Optional; import javafx.fxml.FXML; +import javafx.geometry.Pos; import javafx.scene.Node; +import javafx.scene.control.Control; import javafx.scene.control.Label; import javafx.scene.layout.HBox; +import javafx.scene.layout.VBox; import javafx.scene.paint.Color; +import javafx.scene.text.Font; +import javafx.scene.text.FontPosture; import seedu.agendum.model.task.ReadOnlyTask; //@@author A0148031R public class TaskCard extends UiPart { - + private static final String FXML = "TaskCard.fxml"; + private static final String OVERDUE_PREFIX = "Overdue\n"; + private static final String COMPLETED_PREFIX = "Completed on "; + private static final String NAME_COLOR = "#3a3d42"; + private static final String TIME_COLOR = "#4172c1"; + private static final String TASK_TIME_PATTERN = "HH:mm EEE, dd MMM"; + private static final String COMPLETED_TIME_PATTERN = "EEE, dd MMM"; + private static final String START_TIME_PREFIX = "from "; + private static final String END_TIME_PREFIX = " to "; + private static final String DEADLINE_PREFIX = "by "; + private static final String EMPTY_PREFIX = ""; @FXML private HBox cardPane; @FXML + private VBox taskVbox; + @FXML private Label name; @FXML private Label id; - @FXML - private Label time; private ReadOnlyTask task; private String displayedIndex; - public TaskCard() {} + public TaskCard() { + } - public static TaskCard load(ReadOnlyTask task, int Index){ + public static TaskCard load(ReadOnlyTask task, int Index) { TaskCard card = new TaskCard(); card.task = task; card.displayedIndex = String.valueOf(Index) + "."; return UiPartLoader.loadUiPart(card); } - - public static TaskCard load(ReadOnlyTask task){ - TaskCard card = new TaskCard(); - card.task = task; - card.displayedIndex = ""; - return UiPartLoader.loadUiPart(card); - } @FXML public void initialize() { - - if(task.isOverdue()) { + + if (task.isOverdue()) { cardPane.setStyle("-fx-background-color: rgb(255, 169, 147)"); - } else if(task.isUpcoming()) { + } else if (task.isUpcoming()) { cardPane.setStyle("-fx-background-color: rgb(255, 229, 86)"); } else { cardPane.setStyle("-fx-background-color: rgba(255,255,255,0.6)"); } - - name.setTextFill(Color.web("#555555")); + name.setTextFill(Color.web(NAME_COLOR)); name.setText(task.getName().fullName); id.setText(displayedIndex); - - if(task.isOverdue()) { - time.setText("Overdue\nScheduled: "+ formatTime()); - } else { - time.setText(formatTime()); + + Label time = new Label(); + time.setMaxHeight(Control.USE_COMPUTED_SIZE); + time.setTextFill(Color.web(TIME_COLOR)); + time.setWrapText(true); + + StringBuilder timeDescription = new StringBuilder(); + timeDescription.append(formatTaskTime(task)); + + if (task.isCompleted()) { + timeDescription.append(formatUpdatedTime(task)); + } + + time.setText(timeDescription.toString()); + + if (task.hasTime() || task.isCompleted()) { + taskVbox.getChildren().add(time); + taskVbox.setAlignment(Pos.CENTER_LEFT); + time.setAlignment(Pos.CENTER_LEFT); + time.setFont(Font.font("Verdana", FontPosture.ITALIC, 11)); } - } - - public String formatTime() { + + public String formatTime(String dateTimePattern, String prefix, Optional dateTime) { + StringBuilder sb = new StringBuilder(); - Optional start = task.getStartDateTime(); - Optional end = task.getEndDateTime(); + DateTimeFormatter format = DateTimeFormatter.ofPattern(dateTimePattern); + sb.append(prefix).append(dateTime.get().format(format)); + + return sb.toString(); + } - DateTimeFormatter startFormat = DateTimeFormatter.ofPattern("HH:mm EEE, dd MMM"); + public String formatTaskTime(ReadOnlyTask task) { + + StringBuilder timeStringBuilder = new StringBuilder(); - if (start.isPresent()) { - sb.append("from ").append(start.get().format(startFormat)); + if (task.isOverdue()) { + timeStringBuilder.append(OVERDUE_PREFIX); } - if (end.isPresent()) { - sb.append(sb.length() > 0 ? " to " : "by "); - sb.append(end.get().format(startFormat)); + + if (task.isEvent()) { + String startTime = formatTime(TASK_TIME_PATTERN, START_TIME_PREFIX, task.getStartDateTime()); + String endTime = formatTime(TASK_TIME_PATTERN, END_TIME_PREFIX, task.getEndDateTime()); + timeStringBuilder.append(startTime); + timeStringBuilder.append(endTime); + } else if (task.hasDeadline()) { + String deadline = formatTime(TASK_TIME_PATTERN, DEADLINE_PREFIX, task.getEndDateTime()); + timeStringBuilder.append(deadline); } - return sb.toString().replace("AM", "am").replace("PM", "pm"); + return timeStringBuilder.toString(); + } + + public String formatUpdatedTime(ReadOnlyTask task) { + StringBuilder timeStringBuilder = new StringBuilder(); + if (task.hasTime()) { + timeStringBuilder.append("\n"); + } + timeStringBuilder.append(COMPLETED_PREFIX); + timeStringBuilder.append(formatTime(COMPLETED_TIME_PATTERN, EMPTY_PREFIX, + Optional.ofNullable(task.getLastUpdatedTime()))); + return timeStringBuilder.toString(); } public HBox getLayout() { @@ -92,7 +137,7 @@ public HBox getLayout() { @Override public void setNode(Node node) { - cardPane = (HBox)node; + cardPane = (HBox) node; } @Override diff --git a/src/main/java/seedu/agendum/ui/UiManager.java b/src/main/java/seedu/agendum/ui/UiManager.java index 4dc3674c013f..57c4e93cbefb 100644 --- a/src/main/java/seedu/agendum/ui/UiManager.java +++ b/src/main/java/seedu/agendum/ui/UiManager.java @@ -2,7 +2,6 @@ import com.google.common.eventbus.Subscribe; import javafx.application.Platform; -import javafx.geometry.Insets; import javafx.scene.control.Alert; import javafx.scene.control.Alert.AlertType; import javafx.scene.image.Image; @@ -13,6 +12,7 @@ import seedu.agendum.commons.core.LogsCenter; import seedu.agendum.commons.events.storage.DataLoadingExceptionEvent; import seedu.agendum.commons.events.storage.DataSavingExceptionEvent; +import seedu.agendum.commons.events.ui.JumpToListRequestEvent; import seedu.agendum.commons.events.ui.CloseHelpWindowRequestEvent; import seedu.agendum.commons.events.ui.ShowHelpRequestEvent; import seedu.agendum.commons.util.StringUtil; @@ -104,7 +104,7 @@ private void showFatalErrorDialogAndShutdown(String title, Throwable e) { private void handleDataLoadingExceptionEvent(DataLoadingExceptionEvent event) { logger.info(LogsCenter.getEventHandlingLogMessage(event)); showFileOperationAlertAndWait("Could not load data", "Could not load data from file", event.exception); - } + } //@@author @Subscribe @@ -120,6 +120,18 @@ private void handleShowHelpEvent(ShowHelpRequestEvent event) { mainWindow.handleHelp(); } + @Subscribe + private void handleJumpToListRequestEvent(JumpToListRequestEvent event) { + logger.info(LogsCenter.getEventHandlingLogMessage(event)); + if(event.targetTask.isCompleted()) { + mainWindow.getCompletedTasksPanel().scrollTo(event.targetTask, event.hasMultipleTasks); + } else if(event.targetTask.hasTime()) { + mainWindow.getUpcomingTasksPanel().scrollTo(event.targetTask, event.hasMultipleTasks); + } else { + mainWindow.getFloatingasksPanel().scrollTo(event.targetTask, event.hasMultipleTasks); + } + } + @Subscribe public void handleCloseHelpWindowRequest(CloseHelpWindowRequestEvent event) { logger.info(LogsCenter.getEventHandlingLogMessage(event)); diff --git a/src/main/java/seedu/agendum/ui/UpcomingTasksPanel.java b/src/main/java/seedu/agendum/ui/UpcomingTasksPanel.java index d8d12397726b..8dd4f14cf292 100644 --- a/src/main/java/seedu/agendum/ui/UpcomingTasksPanel.java +++ b/src/main/java/seedu/agendum/ui/UpcomingTasksPanel.java @@ -1,13 +1,20 @@ package seedu.agendum.ui; +import javafx.animation.PauseTransition; import javafx.application.Platform; import javafx.collections.ObservableList; +import javafx.event.EventHandler; import javafx.fxml.FXML; import javafx.scene.control.Control; import javafx.scene.control.ListCell; import javafx.scene.control.ListView; +import javafx.scene.control.MultipleSelectionModel; +import javafx.scene.control.SelectionMode; +import javafx.scene.input.MouseEvent; +import javafx.util.Duration; import seedu.agendum.model.task.ReadOnlyTask; +import seedu.agendum.model.task.Task; //@@author A0148031R /** @@ -16,6 +23,7 @@ public class UpcomingTasksPanel extends TasksPanel { private static final String FXML = "UpcomingTasksPanel.fxml"; private static ObservableList mainTaskList; + private MultipleSelectionModel selectionModel; @FXML private ListView upcomingTasksListView; @@ -30,12 +38,38 @@ protected void setConnections(ObservableList taskList) { mainTaskList = taskList; upcomingTasksListView.setItems(taskList.filtered(task -> task.hasTime() && !task.isCompleted())); upcomingTasksListView.setCellFactory(listView -> new upcomingTasksListViewCell()); + configure(); + } + + private void configure() { + selectionModel = upcomingTasksListView.getSelectionModel(); + upcomingTasksListView.setSelectionModel(null); + upcomingTasksListView.addEventFilter(MouseEvent.MOUSE_PRESSED, new EventHandler() { + @Override + public void handle(MouseEvent event) { + event.consume(); + } + }); } - public void scrollTo(int index) { + public void scrollTo(Task task, boolean hasMultipleTasks) { Platform.runLater(() -> { + + int index = mainTaskList.indexOf(task); upcomingTasksListView.scrollTo(index); - upcomingTasksListView.getSelectionModel().clearAndSelect(index); + upcomingTasksListView.setSelectionModel(selectionModel); + + if(hasMultipleTasks) { + upcomingTasksListView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); + upcomingTasksListView.getSelectionModel().select(index); + } else { + upcomingTasksListView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE); + upcomingTasksListView.getSelectionModel().clearAndSelect(index); + } + + PauseTransition delay = new PauseTransition(Duration.seconds(5)); + delay.setOnFinished(event -> upcomingTasksListView.getSelectionModel().clearSelection(index)); + delay.play(); }); } diff --git a/src/main/resources/images/completedTasksPanel.png b/src/main/resources/images/completedTasksPanel.png new file mode 100644 index 000000000000..a2daa979517d Binary files /dev/null and b/src/main/resources/images/completedTasksPanel.png differ diff --git a/src/main/resources/images/floatingTasksPanel.png b/src/main/resources/images/floatingTasksPanel.png new file mode 100644 index 000000000000..19155b10c5bf Binary files /dev/null and b/src/main/resources/images/floatingTasksPanel.png differ diff --git a/src/main/resources/images/upcomingTasksPanel.png b/src/main/resources/images/upcomingTasksPanel.png new file mode 100644 index 000000000000..184ba632f723 Binary files /dev/null and b/src/main/resources/images/upcomingTasksPanel.png differ diff --git a/src/main/resources/view/CompletedTasksPanel.fxml b/src/main/resources/view/CompletedTasksPanel.fxml index b21f5ef8593b..ac0c7203bcab 100644 --- a/src/main/resources/view/CompletedTasksPanel.fxml +++ b/src/main/resources/view/CompletedTasksPanel.fxml @@ -1,6 +1,8 @@ + + @@ -10,12 +12,17 @@ - + - + + + + + + - + diff --git a/src/main/resources/view/DarkTheme.css b/src/main/resources/view/DarkTheme.css index c81d500995ce..dbb4c5a66a3d 100644 --- a/src/main/resources/view/DarkTheme.css +++ b/src/main/resources/view/DarkTheme.css @@ -1,5 +1,6 @@ +/* @@author A0148031R */ .background { - -fx-background-color: derive(#1d1d1d, 20%); + -fx-background-color: derive(#263238, 20%); } .text-field { @@ -19,33 +20,33 @@ .split-pane:horizontal .split-pane-divider { -fx-border-color: transparent; - -fx-background-color: transparent, derive(#1d1d1d, 10%); + -fx-background-color: transparent; } .split-pane { -fx-border-radius: 1; -fx-border-width: 1; - -fx-background-color: derive(#1d1d1d, 20%); + -fx-background-color: derive(#263238, 20%); } .anchor-pane { - -fx-background-color: derive(#1d1d1d, 20%); + -fx-background-color: derive(#263238, 20%); } .anchor-pane-with-border { - -fx-background-color: derive(#1d1d1d, 20%); + -fx-background-color: derive(#263238, 20%); -fx-border-color: transparent; -fx-border-top-width: 1px; } .stack-pane { - -fx-background-color: derive(#1d1d1d, 20%); + -fx-background-color: derive(#263238, 20%); -fx-border-color: transparent; -fx-border-top-width: 1px; } .status-bar { - -fx-background-color: derive(#1d1d1d, 20%); + -fx-background-color: derive(#263238, 20%); -fx-border-color: transparent; -fx-text-fill: white; } @@ -64,7 +65,7 @@ } .status-bar-with-border { - -fx-background-color: derive(#1d1d1d, 30%); + -fx-background-color: derive(#263238, 30%); -fx-border-color: transparent; -fx-border-width: 1px; } @@ -74,17 +75,17 @@ } .grid-pane { - -fx-background-color: derive(#1d1d1d, 30%); - -fx-border-color: derive(#1d1d1d, 30%); + -fx-background-color: derive(#263238, 30%); + -fx-border-color: derive(#263238, 30%); -fx-border-width: 1px; } .grid-pane .anchor-pane { - -fx-background-color: derive(#1d1d1d, 20%); + -fx-background-color: derive(#263238, 20%); } .context-menu { - -fx-background-color: derive(#1d1d1d, 50%); + -fx-background-color: derive(#263238, 50%); } .context-menu .label { @@ -92,7 +93,7 @@ } .menu-bar { - -fx-background-color: derive(#1d1d1d, 20%); + -fx-background-color: derive(#263238, 20%); } .menu-bar .label { @@ -116,7 +117,7 @@ -fx-border-color: #e2e2e2; -fx-border-width: 2; -fx-background-radius: 0; - -fx-background-color: #1d1d1d; + -fx-background-color: #263238; -fx-font-family: "Segoe UI", Helvetica, Arial, sans-serif; -fx-font-size: 11pt; -fx-text-fill: #d8d8d8; @@ -129,7 +130,7 @@ .button:pressed, .button:default:hover:pressed { -fx-background-color: white; - -fx-text-fill: #1d1d1d; + -fx-text-fill: #263238; } .button:focused { @@ -142,7 +143,7 @@ .button:disabled, .button:default:disabled { -fx-opacity: 0.4; - -fx-background-color: #1d1d1d; + -fx-background-color: #263238; -fx-text-fill: white; } @@ -156,11 +157,11 @@ } .dialog-pane { - -fx-background-color: #1d1d1d; + -fx-background-color: #263238; } .dialog-pane > *.button-bar > *.container { - -fx-background-color: #1d1d1d; + -fx-background-color: #263238; } .dialog-pane > *.label.content { @@ -170,7 +171,7 @@ } .dialog-pane:header *.header-panel { - -fx-background-color: derive(#1d1d1d, 25%); + -fx-background-color: derive(#263238, 25%); } .dialog-pane:header *.header-panel *.label { diff --git a/src/main/resources/view/FloatingTasksPanel.fxml b/src/main/resources/view/FloatingTasksPanel.fxml index 28c0833a34ce..7ac9a40bd5a3 100644 --- a/src/main/resources/view/FloatingTasksPanel.fxml +++ b/src/main/resources/view/FloatingTasksPanel.fxml @@ -1,20 +1,28 @@ + + + - + - + + + + + + - + diff --git a/src/main/resources/view/MainWindow.fxml b/src/main/resources/view/MainWindow.fxml index 8283222a495d..7d73c8c55691 100644 --- a/src/main/resources/view/MainWindow.fxml +++ b/src/main/resources/view/MainWindow.fxml @@ -46,7 +46,7 @@ - + @@ -57,7 +57,7 @@ - + @@ -65,7 +65,7 @@ - + diff --git a/src/main/resources/view/TaskCard.fxml b/src/main/resources/view/TaskCard.fxml index 57ef97345db5..34d6ddc4da63 100644 --- a/src/main/resources/view/TaskCard.fxml +++ b/src/main/resources/view/TaskCard.fxml @@ -7,7 +7,6 @@ - @@ -26,29 +25,13 @@ diff --git a/src/main/resources/view/TasksPanel.css b/src/main/resources/view/TasksPanel.css index 1b2f444e04f2..6c5cd43f43ef 100644 --- a/src/main/resources/view/TasksPanel.css +++ b/src/main/resources/view/TasksPanel.css @@ -1,11 +1,11 @@ /* @@author A0148031R */ .all-pane { - -fx-background-color: #F39C12; + -fx-background-color: #FFA000; -fx-background-radius: 10; } .completed-pane { - -fx-background-color: #03C9A9; + -fx-background-color: #727a87; -fx-background-radius: 10; } @@ -20,31 +20,29 @@ } .list-cell { + -fx-background-color: transparent; -fx-background-radius: 10; - -fx-background-color: transparent; } .list-cell:empty { -fx-background-color: transparent; } +.list-cell:filled:selected:focused, .list-cell:filled:selected { + -fx-background-color: #4DD0E1; + -fx-text-fill: red; +} + .cell_big_label { -fx-font-size: 14pt; -fx-opacity: 0.9; } .cell_small_label { - -fx-font-size: 11pt; - -fx-text-fill: #555555; + -fx-text-fill: #3a3d42; -fx-opacity: 0.9; } -.cell_time_label { - -fx-text-fill: #5284f2; - -fx-font-family: "Segoe UI Light"; - -fx-opacity: 0.9; -} - .hbox { -fx-background-radius: 10; } diff --git a/src/main/resources/view/UpcomingTasksPanel.fxml b/src/main/resources/view/UpcomingTasksPanel.fxml index edf43b71ec85..cfd8a42c76ed 100644 --- a/src/main/resources/view/UpcomingTasksPanel.fxml +++ b/src/main/resources/view/UpcomingTasksPanel.fxml @@ -1,19 +1,28 @@ + + + + - + - + + + + + + - + diff --git a/src/test/java/guitests/AddCommandTest.java b/src/test/java/guitests/AddCommandTest.java index 725f32fec5e0..b0047e226722 100644 --- a/src/test/java/guitests/AddCommandTest.java +++ b/src/test/java/guitests/AddCommandTest.java @@ -44,7 +44,7 @@ private void assertAddSuccess(TestTask taskToAdd, TestTask... currentList) { //confirm the new card contains the right data if (!taskToAdd.isCompleted() && !taskToAdd.hasTime()) { - TaskCardHandle addedCard = doItAnytimePanel.navigateToTask(taskToAdd.getName().fullName); + TaskCardHandle addedCard = floatingTasksPanel.navigateToTask(taskToAdd.getName().fullName); assertMatching(taskToAdd, addedCard); } diff --git a/src/test/java/guitests/HelpWindowTest.java b/src/test/java/guitests/HelpWindowTest.java index 509ad9169549..06a15fef9a17 100644 --- a/src/test/java/guitests/HelpWindowTest.java +++ b/src/test/java/guitests/HelpWindowTest.java @@ -13,12 +13,6 @@ public class HelpWindowTest extends ToDoListGuiTest { @Test public void openHelpWindow() { - doItAnytimePanel.clickOnListView(); - - assertHelpWindowOpen(mainMenu.openHelpWindowUsingAccelerator()); - - assertHelpWindowOpen(mainMenu.openHelpWindowUsingMenu()); - assertHelpWindowOpen(commandBox.runHelpCommand()); } diff --git a/src/test/java/guitests/RenameCommandTest.java b/src/test/java/guitests/RenameCommandTest.java index 2b59b32f2190..1aaa0a81e7aa 100644 --- a/src/test/java/guitests/RenameCommandTest.java +++ b/src/test/java/guitests/RenameCommandTest.java @@ -61,8 +61,7 @@ private void assertRenameSuccess(int targetIndexOneIndexed, final TestTask[] cur assertAllPanelsMatch(expectedList); //confirm the result message is correct - assertResultMessage(String.format(RenameCommand.MESSAGE_SUCCESS, - Integer.toString(targetIndexOneIndexed), newTaskName)); + assertResultMessage(String.format(RenameCommand.MESSAGE_SUCCESS, newTaskName)); } catch (IllegalValueException e) { e.printStackTrace(); diff --git a/src/test/java/guitests/ToDoListGuiTest.java b/src/test/java/guitests/ToDoListGuiTest.java index a19cdb168aa0..750af9fdb52e 100644 --- a/src/test/java/guitests/ToDoListGuiTest.java +++ b/src/test/java/guitests/ToDoListGuiTest.java @@ -40,8 +40,8 @@ public abstract class ToDoListGuiTest { */ protected MainGuiHandle mainGui; protected MainMenuHandle mainMenu; - protected UpcomingTasksHandle doItSoonPanel; - protected FloatingTasksPanelHandle doItAnytimePanel; + protected UpcomingTasksHandle upcomingTasksPanel; + protected FloatingTasksPanelHandle floatingTasksPanel; protected CompletedTasksPanelHandle completedTasksPanel; protected ResultDisplayHandle resultDisplay; protected CommandBoxHandle commandBox; @@ -62,8 +62,8 @@ public void setup() throws Exception { FxToolkit.setupStage((stage) -> { mainGui = new MainGuiHandle(new GuiRobot(), stage); mainMenu = mainGui.getMainMenu(); - doItSoonPanel = mainGui.getDoItSoonPanel(); - doItAnytimePanel = mainGui.getDoItAnytimePanel(); + upcomingTasksPanel = mainGui.getDoItSoonPanel(); + floatingTasksPanel = mainGui.getDoItAnytimePanel(); completedTasksPanel = mainGui.getCompletedTasksPanel(); resultDisplay = mainGui.getResultDisplay(); commandBox = mainGui.getCommandBox(); @@ -109,8 +109,8 @@ public void assertMatching(ReadOnlyTask task, TaskCardHandle card) { * Asserts the size of the task list is equal to the given number. */ protected void assertListSize(int size) { - int numberOfTasks = doItSoonPanel.getNumberOfTasks() - + doItAnytimePanel.getNumberOfTasks() + int numberOfTasks = upcomingTasksPanel.getNumberOfTasks() + + floatingTasksPanel.getNumberOfTasks() + completedTasksPanel.getNumberOfTasks(); assertEquals(size, numberOfTasks); } @@ -130,8 +130,8 @@ protected void assertAllPanelsMatch(TestTask[] expectedList) { TestTask[] expectedDoItSoonTasks = TestUtil.getDoItSoonTasks(expectedList); TestTask[] expectedDoItAnytimeTasks = TestUtil.getDoItAnytimeTasks(expectedList); TestTask[] expectedDoneTasks = TestUtil.getDoneTasks(expectedList); - assertTrue(doItSoonPanel.isListMatching(expectedDoItSoonTasks)); - assertTrue(doItAnytimePanel.isListMatching(expectedDoItAnytimeTasks)); + assertTrue(upcomingTasksPanel.isListMatching(expectedDoItSoonTasks)); + assertTrue(floatingTasksPanel.isListMatching(expectedDoItAnytimeTasks)); assertTrue(completedTasksPanel.isListMatching(expectedDoneTasks)); } } diff --git a/src/test/java/guitests/guihandles/FloatingTasksPanelHandle.java b/src/test/java/guitests/guihandles/FloatingTasksPanelHandle.java index a1c4f905434c..d481b2cf2033 100644 --- a/src/test/java/guitests/guihandles/FloatingTasksPanelHandle.java +++ b/src/test/java/guitests/guihandles/FloatingTasksPanelHandle.java @@ -87,7 +87,7 @@ public boolean isListMatching(int startPosition, ReadOnlyTask... tasks) throws I for (int i = 0; i < tasks.length; i++) { final int scrollTo = i + startPosition; guiRobot.interact(() -> getListView().scrollTo(scrollTo)); - guiRobot.sleep(200); + guiRobot.sleep(500); if (!TestUtil.compareCardAndTask(getTaskCardHandle(startPosition + i), tasks[i])) { return false; } diff --git a/src/test/java/guitests/guihandles/MainMenuHandle.java b/src/test/java/guitests/guihandles/MainMenuHandle.java index b305bbb62257..336002d146d4 100644 --- a/src/test/java/guitests/guihandles/MainMenuHandle.java +++ b/src/test/java/guitests/guihandles/MainMenuHandle.java @@ -20,27 +20,11 @@ public GuiHandle clickOn(String... menuText) { Arrays.stream(menuText).forEach((menuItem) -> guiRobot.clickOn(menuItem)); return this; } - - //@@author A0148031R - public HelpWindowHandle openHelpWindowUsingMenu() { - clickOn("Help", "F5"); - return new HelpWindowHandle(guiRobot, primaryStage); - } - - public HelpWindowHandle openHelpWindowUsingAccelerator() { - useAcceleratorToOpenHelpWindow(); - return new HelpWindowHandle(guiRobot, primaryStage); - } public MainGuiHandle closeHelpWindowUsingAccelerator() { useAcceleratorToCloseHelpWindow(); return new MainGuiHandle(guiRobot, primaryStage); } - - private void useAcceleratorToOpenHelpWindow() { - guiRobot.push(new KeyCodeCombination(KeyCode.F5)); - guiRobot.sleep(500); - } private void useAcceleratorToCloseHelpWindow() { guiRobot.push(new KeyCodeCombination(KeyCode.ESCAPE)); diff --git a/src/test/java/guitests/guihandles/TaskCardHandle.java b/src/test/java/guitests/guihandles/TaskCardHandle.java index 8a26f91c5826..7318a37189e3 100644 --- a/src/test/java/guitests/guihandles/TaskCardHandle.java +++ b/src/test/java/guitests/guihandles/TaskCardHandle.java @@ -16,10 +16,18 @@ public class TaskCardHandle extends GuiHandle { private static final String NAME_FIELD_ID = "#name"; private static final String INDEX_FIELD_ID = "#id"; private static final String TIME_FIELD_ID = "#time"; + private static final String TASK_TIME_PATTERN = "HH:mm EEE, dd MMM"; + private static final String COMPLETED_TIME_PATTERN = "EEE, dd MMM"; + private static final String OVERDUE_PREFIX = "Overdue\n"; + private static final String COMPLETED_PREFIX = "Completed on "; + private static final String START_TIME_PREFIX = " from "; + private static final String END_TIME_PREFIX = " to "; + private static final String DEADLINE_PREFIX = "by "; + private static final String EMPTY_PREFIX = ""; private Node node; - public TaskCardHandle(GuiRobot guiRobot, Stage primaryStage, Node node){ + public TaskCardHandle(GuiRobot guiRobot, Stage primaryStage, Node node) { super(guiRobot, primaryStage, null); this.node = node; } @@ -40,20 +48,70 @@ public String getTime() { return getTextFromLabel(TIME_FIELD_ID); } - public boolean isSameTask(ReadOnlyTask task){ - // the completion status will be checked by which panel it belongs in - return getName().equals(task.getName().fullName) - && getTime().equals(formatTime(task)); + public boolean isSameTask(ReadOnlyTask task) { + + String name = task.getName().fullName; + if(!task.hasTime()) { + return getName().equals(name); + } + + StringBuilder timeDescription = new StringBuilder(); + timeDescription.append(formatTaskTime(task)); + if (task.isCompleted()) { + timeDescription.append(formatUpdatedTime(task)); + return getName().equals(name) && getTime().equals(timeDescription); + } else { + return getName().equals(name) && getTime().equals(timeDescription); + } + } + + public String formatTime(String dateTimePattern, String prefix, Optional dateTime) { + + StringBuilder sb = new StringBuilder(); + DateTimeFormatter format = DateTimeFormatter.ofPattern(dateTimePattern); + sb.append(prefix).append(dateTime.get().format(format)); + + return sb.toString(); + } + + public String formatTaskTime(ReadOnlyTask task) { + + StringBuilder timeStringBuilder = new StringBuilder(); + + if (task.isOverdue()) { + timeStringBuilder.append(OVERDUE_PREFIX); + } + + if (task.isEvent()) { + String startTime = formatTime(TASK_TIME_PATTERN, START_TIME_PREFIX, task.getStartDateTime()); + String endTime = formatTime(TASK_TIME_PATTERN, END_TIME_PREFIX, task.getEndDateTime()); + timeStringBuilder.append(startTime); + timeStringBuilder.append(endTime); + } else if (task.hasDeadline()) { + String deadline = formatTime(TASK_TIME_PATTERN, DEADLINE_PREFIX, task.getEndDateTime()); + timeStringBuilder.append(deadline); + } + + return timeStringBuilder.toString(); + } + + public String formatUpdatedTime(ReadOnlyTask task) { + StringBuilder timeStringBuilder = new StringBuilder(); + if (task.hasTime()) { + timeStringBuilder.append("\n"); + } + timeStringBuilder.append(COMPLETED_PREFIX); + timeStringBuilder.append(formatTime(COMPLETED_TIME_PATTERN, EMPTY_PREFIX, + Optional.ofNullable(task.getLastUpdatedTime()))); + return timeStringBuilder.toString(); } - @Override public boolean equals(Object obj) { - if(obj instanceof TaskCardHandle) { + if (obj instanceof TaskCardHandle) { TaskCardHandle handle = (TaskCardHandle) obj; - return getName().equals(handle.getName()) - && getTaskIndex().equals(handle.getTaskIndex()) - && getTime().equals(handle.getTime()); + return getName().equals(handle.getName()) && getTaskIndex().equals(handle.getTaskIndex()) + && getTime().equals(handle.getTime()); } return super.equals(obj); } @@ -63,22 +121,22 @@ public String toString() { return getTaskIndex() + " " + getName() + "Time: " + getTime(); } - //@@author A0148031R - private String formatTime(ReadOnlyTask task) { - StringBuilder sb = new StringBuilder(); - Optional start = task.getStartDateTime(); - Optional end = task.getEndDateTime(); - - DateTimeFormatter startFormat = DateTimeFormatter.ofPattern("HH:mm EEE, dd MMM"); + public String formatTime(ReadOnlyTask task, String dateTimePattern, String prefix, + Optional dateTime) { - if (start.isPresent()) { - sb.append("from ").append(start.get().format(startFormat)); - } - if (end.isPresent()) { - sb.append(sb.length() > 0 ? " to " : "by "); - sb.append(end.get().format(startFormat)); + StringBuilder sb = new StringBuilder(); + DateTimeFormatter format = DateTimeFormatter.ofPattern(dateTimePattern); + + if (task.isCompleted()) { + sb.append(dateTime.get().format(format)); + } else if (dateTime.isPresent() && task.getStartDateTime().isPresent()) { + sb.append(prefix).append(dateTime.get().format(format)); + } else if (dateTime.isPresent()) { + sb.append(DEADLINE_PREFIX).append(dateTime.get().format(format)); + } else { + sb.append(EMPTY_PREFIX); } - return sb.toString().replace("AM", "am").replace("PM", "pm"); + return sb.toString().toLowerCase(); } } diff --git a/src/test/java/seedu/agendum/logic/LogicManagerTest.java b/src/test/java/seedu/agendum/logic/LogicManagerTest.java index 16ca7f06552e..f755d4e0f39b 100644 --- a/src/test/java/seedu/agendum/logic/LogicManagerTest.java +++ b/src/test/java/seedu/agendum/logic/LogicManagerTest.java @@ -453,14 +453,9 @@ public void executeMarkMarksCorrectSingleTaskAsCompleted() throws Exception { model.resetData(new ToDoList()); helper.addToModel(model, threeTasks); - // prepare for message - List markedTaskVisibleIndices = helper.generateNumberList(1); - List markedTasks = helper.generateReadOnlyTaskList(threeTasks.get(0)); - String tasksAsString = CommandResult.tasksToString(markedTasks, markedTaskVisibleIndices); - // test boundary value (first task in the list) assertCommandBehavior("mark 1", - String.format(MarkCommand.MESSAGE_MARK_TASK_SUCCESS, tasksAsString), + MarkCommand.MESSAGE_MARK_TASK_SUCCESS, expectedTDL, expectedTDL.getTaskList()); } @@ -479,15 +474,9 @@ public void executeMarkMarksCorrectRangeOfTasks() throws Exception { model.resetData(new ToDoList()); helper.addToModel(model, fourTasks); - // prepare for message - List markedTaskVisibleIndices = helper.generateNumberList(3, 4); - List markedTasks = helper.generateReadOnlyTaskList( - fourTasks.get(2), fourTasks.get(3)); - String tasksAsString = CommandResult.tasksToString(markedTasks, markedTaskVisibleIndices); - // test boundary value (up to last task in the list) assertCommandBehavior("mark 3-4", - String.format(MarkCommand.MESSAGE_MARK_TASK_SUCCESS, tasksAsString), + MarkCommand.MESSAGE_MARK_TASK_SUCCESS, expectedTDL, expectedTDL.getTaskList()); } @@ -506,14 +495,8 @@ public void executeMarkMarksCorrectMultipleTasks() throws Exception { // prepare model helper.addToModel(model, fourTasks); - // prepare for message - List markedTaskVisibleIndices = helper.generateNumberList(2, 3, 4); - List markedTasks = helper.generateReadOnlyTaskList( - fourTasks.get(1), fourTasks.get(2), fourTasks.get(3)); - String tasksAsString = CommandResult.tasksToString(markedTasks, markedTaskVisibleIndices); - assertCommandBehavior("mark 2,3 4", - String.format(MarkCommand.MESSAGE_MARK_TASK_SUCCESS, tasksAsString), + MarkCommand.MESSAGE_MARK_TASK_SUCCESS, expectedTDL, expectedTDL.getTaskList()); } @@ -544,14 +527,9 @@ public void executeUnmarkUnmarksCorrectSingleTaskFromCompleted() throws Exceptio model.resetData(new ToDoList()); helper.addToModel(model, threeTasks); - // prepare for message - List unmarkedTaskVisibleIndices = helper.generateNumberList(3); - List unmarkedTasks = helper.generateReadOnlyTaskList(threeTasks.get(2)); - String tasksAsString = CommandResult.tasksToString(unmarkedTasks, unmarkedTaskVisibleIndices); - // test boundary value - last task in the list assertCommandBehavior("unmark 3", - String.format(UnmarkCommand.MESSAGE_UNMARK_TASK_SUCCESS, tasksAsString), + UnmarkCommand.MESSAGE_UNMARK_TASK_SUCCESS, expectedTDL, expectedTDL.getTaskList()); } @@ -574,14 +552,8 @@ public void executeUnmarkUnmarksCorrectRangeOfTasks() throws Exception { model.resetData(new ToDoList()); helper.addToModel(model, fourTasks); - // prepare for message - List unmarkedTaskVisibleIndices = helper.generateNumberList(3, 4); - List unmarkedTasks = helper.generateReadOnlyTaskList( - fourTasks.get(2), fourTasks.get(3)); - String tasksAsString = CommandResult.tasksToString(unmarkedTasks, unmarkedTaskVisibleIndices); - assertCommandBehavior("unmark 3-4", - String.format(UnmarkCommand.MESSAGE_UNMARK_TASK_SUCCESS, tasksAsString), + UnmarkCommand.MESSAGE_UNMARK_TASK_SUCCESS, expectedTDL, expectedTDL.getTaskList()); } @@ -602,14 +574,8 @@ public void executeUnmarkUnmarksCorrectMultipleTasks() throws Exception { // prepare model helper.addToModel(model, fourTasks); - // prepare for message - List unmarkedTaskVisibleIndices = helper.generateNumberList(2, 3, 4); - List unmarkedTasks = helper.generateReadOnlyTaskList( - fourTasks.get(1), fourTasks.get(2), fourTasks.get(3)); - String tasksAsString = CommandResult.tasksToString(unmarkedTasks, unmarkedTaskVisibleIndices); - assertCommandBehavior("unmark 2,3 4", - String.format(UnmarkCommand.MESSAGE_UNMARK_TASK_SUCCESS, tasksAsString), + String.format(UnmarkCommand.MESSAGE_UNMARK_TASK_SUCCESS), expectedTDL, expectedTDL.getTaskList()); } @@ -682,7 +648,7 @@ public void executeRenameRenamesCorrectTask() throws Exception { //boundary value: use the last task assertCommandBehavior("rename 3 " + newTaskName, - String.format(RenameCommand.MESSAGE_SUCCESS, "3", newTaskName), + String.format(RenameCommand.MESSAGE_SUCCESS, newTaskName), expectedTDL, expectedTDL.getTaskList()); } @@ -762,7 +728,7 @@ public void executeScheduleScheduleCorrectTask() throws Exception { helper.addToModel(model, threeTasks); assertCommandBehavior("schedule 3 from Sep 9 9:10 to Oct 10 10:10", - String.format(ScheduleCommand.MESSAGE_SUCCESS, "3", eventTask), + String.format(ScheduleCommand.MESSAGE_SUCCESS, eventTask), expectedTDL, expectedTDL.getTaskList()); } diff --git a/src/test/java/seedu/agendum/testutil/TestTask.java b/src/test/java/seedu/agendum/testutil/TestTask.java index 2a27462ea7f5..41178c480799 100644 --- a/src/test/java/seedu/agendum/testutil/TestTask.java +++ b/src/test/java/seedu/agendum/testutil/TestTask.java @@ -94,6 +94,16 @@ public boolean isOverdue() { public boolean hasTime() { return (getStartDateTime().isPresent() || getEndDateTime().isPresent()); } + + @Override + public boolean isEvent() { + return getStartDateTime().isPresent(); + } + + @Override + public boolean hasDeadline() { + return !getStartDateTime().isPresent() && getEndDateTime().isPresent(); + } @Override public Optional getStartDateTime() {