By: AY1920S1-CS2103T-T10-3      Since: Sep 2019      Licence: MIT

1. Setting up

Refer to the guide here.

2. Design

2.1. Architecture

ArchitectureDiagram
Figure 1. Architecture Diagram

The Architecture Diagram given above explains the high-level design of the App. Given below is a quick overview of each component.

The .puml files used to create diagrams in this document can be found in the diagrams folder. Refer to the Using PlantUML guide to learn how to create and edit diagrams.

Main has two classes called Main and MainApp. It is responsible for,

  • At app launch: Initializes the components in the correct sequence, and connects them up with each other.

  • At shut down: Shuts down the components and invokes cleanup method where necessary.

Commons represents a collection of classes used by multiple other components. The following class plays an important role at the architecture level:

  • Item : Used by classes to represent a task, event, reminder or any combination of the three.

  • Task : Used by classes to store, access and modify details regarding tasks.

  • Events : Used by classes to store, access and modify details regarding events.

  • Reminders : Used by classes to store, access and modify details regarding reminders.

  • LogsCenter : Used by many classes to write log messages to the App’s log file.

ItemClassDiagram
Figure 2. Class Diagram of the Item
  • An Item can contain an task, event or reminder. However it must contain at least one of the three.

  • The ItemBuilder class ensures the validation of the above rule when build() is called..

  • An Item is immutable in order to support thread safety.

  • An Item is created via the ItemBuilder class.

  • Setter methods of Item create a new Item through ItemBuilder to ensure immutability.

The rest of the App consists of four components.

  • UI: The UI of the App.

  • Logic: The command executor.

  • Model: Holds the data of the App in-memory.

  • Storage: Reads data from, and writes data to, the hard disk.

Each of the four components

  • Defines its API in an interface with the same name as the Component.

  • Exposes its functionality using a {Component Name}Manager class.

For example, the Logic component (see the class diagram given below) defines it’s API in the Logic.java interface and exposes its functionality using the LogicManager.java class.

How the architecture components interact with each other

The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command delete 1.

ArchitectureSequenceDiagram
Figure 3. Component interactions for delete 1 command

The sections below give more details of each component.

2.2. UI component

UiClassDiagram
Figure 4. Structure of the UI Component

API : Ui.java

The UI consists of a MainWindow that is made up of parts e.g.CommandBox, ResultDisplay, TaskListPanel etc. All these, including the MainWindow, inherit from the abstract UiPart class.

The UI component uses JavaFx UI framework. The layout of these UI parts are defined in matching .fxml files that are in the src/main/resources/view folder. For example, the layout of the MainWindow is specified in MainWindow.fxml

The UI component,

  • Executes user commands using the Logic component.

  • Listens for changes to Model data so that the UI can be updated with the modified data.

2.3. Logic component

LogicComponentUML
Figure 5. Structure of the Logic Component

API : Logic.java

  1. Logic uses the ElisaParser class to parse the user command.

  2. This results in a Command object which is executed by the LogicManager.

  3. The command execution can affect the ItemModel (e.g. adding an Item).

  4. The result of the command execution is encapsulated as a CommandResult object which is passed back to the Ui.

  5. In addition, the CommandResult object can also instruct the Ui to perform certain actions, such as displaying help to the user.

  6. More instructions for the Ui can be given through implementing ScrollCommand

2.4. Model component

500
Figure 6. Structure of the Model Component

The ItemModel,

  • stores a UserPref object that represents the user’s preferences.

  • contains the ItemStorage that stores all the data for ELISA.

  • exposes four observable lists that can be viewed by the Ui and will cause an update in the Ui when it is updated.

2.4.1. Design Consideration

The original implementation was to have one single observable list and modifying it whenever the view changes. We decided against it as we believe that this will result in O(n) time complexity for switching the different views as we need to iterate through all the items to find the relevant items.

Using the four visualization list, we only need to change the pointer when we want to change the view of the viewing panel making it an O(1) time complexity solution. However, this makes it more complicated to maintain the different lists.

2.5. Storage component

StorageClassDiagram
Figure 7. Structure of the Storage Component

API : Storage.java

The Storage component,

  • can save UserPref objects in json format and read it back.

  • can save the Item Storage data in json format and read it back.

2.6. Common classes

Classes used by multiple components are in the seedu.addressbook.commons package.

3. Implementation

This section describes some noteworthy details on how certain features are implemented.

3.1. Add Task/Event feature

Task, Events and Reminders are all Items and can be added using the same command. Adding of Items is facilitated by ItemModel#add(Item).

3.1.1. Implementation

A Task with a deadline flag -d will be considered an Event. A Task with a reminder flag -r will be considered a Reminder.
The following activity diagram shows the how a task can be added, depending on the flags present:

200
Figure 8. Activity Diagram of adding a Task

This shows how we can easily add Task, Event and Reminder with a single command. However, in this section, we will only show how Task and Event is added. Adding of Reminders is shown in a separate section as it includes other steps.

3.1.2. Internal workings of the command

Given below is an example usage scenario of how add behaves at each step:

Step 1. The user enters the command "task shower -d 1.hour.later".
Step 2. The LogicManager creates an AddressBookParser to parse the user input.
Step 3. AddressBookParser creates a AddTaskCommandParser which parses the input and returns an AddCommand.
Step 4. LogicManager will execute the AddCommand. AddCommand will then invoke ItemModel#add(Item), which adds Task to its TaskList and Event to its EventList.
Step 5. AddCommand will also trigger a change in view by calling ItemModel#setVisualList(taskList) Step 6. Upon the successful execution of AddCommand, a CommandResult is returned to the LogicManager, which will then be returned to the Ui to render the appropriate view.

The figures below shows the sequence diagram on what happens from a simple execution of task shower -d 1.min.later user command:

AddCommandPart 1
Figure 9. Call execute in LogicManager to create an AddTaskCommand

This diagram shows how execute is carried out in the Logic component. The following diagram shows how the same command is continued onto the Model component:

AddCommandPart 2
Figure 10. LogicManager executes the AddTaskCommand and returns CommandResult

This shows how execute(model) affects the Model component. It then returns a CommandResult r, which is the result of calling LogicManager#execute("task shower -d 1.hour.later").

3.1.3. Design considerations

The design considerations for the classes are shown below:

Alternatives:

Pros:

Cons:

1. Placing all fields into an Item object and retrieving the specific fields when needed.

Easy to implement. Reduce dependencies between classes as everything is in one class. Editing can be done all in one object.

Does not separate out the different functionalities of Task, Event and Reminder.

2. Having separate classes for Task, Event, Reminder

Reduce dependencies as well as having functionalities separated.

Some attributes and methods overlap. Repetition of code for same functionality. Have to add all three objects individually. Editing of an item would require searching, obtaining and individually editing all 3 objects.

3. (Current) Having a general Item class which comprise of Optional<> fields Task, Event, Reminder

Similar fields such as description and priority can be placed in Item. This makes adding an Item more convenient. Related task/event/reminder can have access to each other.

Increase coupling and dependency amongst Task, Event, Reminder classes.

As of now, these are the considered designs and the current design seems to work well for our purpose. However, there could be better designs which are unexplored that could mitigate our cons and we welcome them.

This is end of the section of adding a Task and Event. As mentioned above, adding of Reminder will be shown in a separate section due it having extra features. Do look out for it if you’re interested.

3.2. Rescheduling of recurring Events automatically

This section talks about how the autoReschedule function is implemented. This feature aims to provide users with greater convenience when scheduling events that occur periodically (eg. weekly deadlines, monthly appointments).

3.2.1. Implementation

To reschedule a task, we need a deadline as we need to be able to calculate the next date. Recall that any Task with a deadline is considered an Event. As such, only Events can be rescheduled.

To automatically reschedule an Event, when creating the Event, include the -auto flag along with its reschedule period (eg -auto day for daily rescheduling)
The accepted parameters for -auto is day, week, month and the format of 10.min.later.

The following diagram shows the process of adding an Event with -auto flag:

Activity diagram of AutoReschedule

100

In the diagram, when we add the Event initially, we would check the start time of the Event and update it accordingly. However, this is not the only place where rescheduling occurs.

3 places where rescheduling can occur:

1) When the event is created, as shown in the diagram above.
2) While the app is running, the Event’s start time will be continuously updated when it has passed.
This is done using Timer and TimerTask, using Timer#scheduleAtFixedRate().
3) When the app is started and Events are loaded from the storage. The stored Event time might already be over, as such the time has to be updated to the latest upcoming one.

To illustrate how they work, first we need to know what classes are involved before we can understand the sequence of actions carried out.
The classes involved in the above rescheduling are:

  • AutoReschedulePeriod — Represents the period of every reschedule (eg day/week/month)

  • RescheduleTask — Represents the action to perform when rescheduling its associated event.

  • AutoRescheduleManager — Manages all the rescheduling tasks. There is only one of such manager.

To better understand its underlying structure, we can look at the class diagram below:

100
Figure 11. Class Diagram of classes involved in AutoReschedule function

3.2.2. Internal workings of the command

Now we are ready to look at the sequence of actions. Given below is an example usage scenario of how add behaves at each step:

Step 1. The user enters the command event CS2103T Quiz -d 23/09/2019 2359 -auto week.
Step 2. The Event is created, following the sequence of steps in the section Adding Task/Event. However there are now some extra steps from Step 3 onwards that occur concurrently from the object creation of Event.
Step 3a. The presence of the -auto week creates an AutoReschedulePeriod, which is stored in the Event created. This can be seen in the Class Diagram above.
Step 3b. If the start time of this Event is already over, the Event’s start time will be modified to show the next start time, using this Event’s AutoReschedulePeriod. Step 4. When LogicManager#execute(model) is called, the presence of AutoReschedulePeriod in the Event triggers the creation of a RescheduleTask, which represents the task of rescheduling this Event.
Step 5. This RescheduleTask is added to an AutoRescheduleManager, which manages all RescheduleTasks.
Step 6. When the start time of this Event has passed, AutoRescheduleManager will call RescheduleTask#run(), and this updates the Event start time, which will be reflected in the Ui.

The following diagrams show how the command event Quiz -d 10.hour.later -auto week is executed from the Logic component. The first diagram shows the adding of an Event, which may appear familiar as it has a sequence similar to the adding of task in Section 3.1, “Add Task/Event feature”. However, there are some minor differences due to the presence of -auto which should be noted.

AutoRescheduleSequence 1
Figure 12. Call execute in LogicManager and create an AddEventCommand

As mentioned, the key points to take note of in the diagram above is Event#setAutoReschedule(true) and Event#setReschedulePeriod(period).
The significance of these methods will be shown in the continuing diagram below:

100
Figure 13. LogicManager executing AddEventCommand and create task for AutoRescheduleManager

From the above diagram, we can see that the presence of AutoReschedulePeriod in Event results in the creation of RescheduleTask which would be queued into the Timer managed by AutoRescheduleManager.

3.2.3. Design considerations

The design considerations for the classes are shown below:

Alternative 1: Creating a AutoRescheduleManager for every RescheduleTask
Pros: Easy for the Timer in AutoRescheduleManager to keep track of its TimerTask.
Cons: There could potentially be many Timer threads.
Alternative 2: (Current) Singleton pattern for AutoRescheduleManager
Pros: Ensure that only one instance can be instantiated as there should only be one manager for all the RescheduleTask. If there are multiple managers, it would be hard to keep track of all of them and it would be difficult to coordinate all the tasks.
Cons: Difficult to create tests for AutoRescheduleManager. Could have many hidden dependencies, which makes code harder to maintain.

3.3. Game feature

This section talks about how the game function is implemented. This feature aims to encourage users to take a break by playing the traditional Nokia (phone) game: Snake.

3.3.1. Implementation

The game screen appears after the user enters the command game into the command box. A separate scene handled by a separate thread is created to run the game so that Elisa’s scenes and threads are not overloaded. The following activity diagram shows how the game screen is launched.

500
Figure 14. Activity diagram for game mode

3.3.2. Internal workings of the Game

Given below is an example usage scenario of how add behaves at each step:

<LOGIC>
Step 1. The user enters the command "game".
Step 2. The LogicManager creates an ElisaParser to parse the user input.
Step 3. ElisaParser creates a GameCommandParser to parse the user input.
Step 4. LogicManager will execute the GameCommand. GameCommand will create a GameCommandResult.
Step 5. MainWindow will call its own method startgame().

<GAME>
Step 6. startgame() calls the method resetgame(), which creates a Grid and GameLoop.
Step 7. startgame() calls the method gameCheck on the canvas to check the keys that are pressed during the game.
Step 8. startgame() creates a new scene and sets primaryStage’s scene to this new scene.
Step 9. startgame() creates a new thread to run the game.

The figure below shows the sequence diagram on what happens after the startgame() method is called.

500
Figure 15. Sequence Diagram for game creation

3.3.3. Game considerations

The considerations for the choice of game is shown below:

Alternatives:

Pros:

Cons:

1. Minesweeper

It is a well-known popular desktop game.

It is difficult to understand the implied rules to this game and this game requires a long time to complete.

2. Sudoku

It is a well-known popular pen-and-paper game.

It is difficult to understand the implied rules to this game and this game requires a long time to complete.

3. (Current) Snake

It is a well-known popular Nokia (phone) game. The rules are simple to understand. The duration for each game is short.

It is addictive when users try to break their high score.

3.3.4. Design considerations

The design considerations for the placement of the game is shown below:

Alternatives:

Pros:

Cons:

1. Placing the game in one of the tabs (beside the Calendar) such that show g will switch tab to the game tab.

Users are able to see the chatbox while in the game.

Requires users to use the mouse (away from CLI) to switch between typing in the command box and hitting the keys on the keyboard.

2. (Current) Creating a separate scene such that the original scene (with ELISA) is hidden when game mode is entered.

Allows users to hit the keys on the keyboard without typing into the command box.

Users are unable to see the chatbox from Elisa.

3.4. [Implemented] Undo/Redo Feature

3.4.1. Current Implementation Logic

The undo function uses the revert command method without using states and history, unlike the proposed method. This is because an issue was encountered with referencing lists and firing reminders multiple times when the state history method was used.

In this implementation, the commands that can be undone; that is, all the commands except UndoCommand, ExitCommand, UpCommand and DownCommand now extend from an abstract class UndoableCommand, which is a subclass of Command. Subclasses of UndoableCommand must implement a method reverse(ItemModel model), which should do the exact opposite of the execute(ItemModel model) in that Command.

The command execution history is stored in a stack, which is maintained in ElisaCommandHistory.

The activity diagram below shows the flow of the undo command.

][

Below is a possible usage scenario and the app behaviour.

Step 1. The user executes task eat. A task with description "eat" is added and then the command is pushed into the commands stack.

][

Step 2. The user realises that adding the task was a mistake, and decides to undo by entering undo into ELISA. The undo command will pop the AddTaskCommand from the stack and reverse the effects of that command, in this case by deleting the task "eat" from the TaskList.

][

Step 3. After successful execution of the UndoCommand a confirmation message is displayed in the chat box.

Of course, the undo feature has its counterpart, the redo command. The commands to be redone are stored in an additional stack within ElisaCommandHistory, and when the redo is done, it executes the command again, which reapplies the most recent change. Every time a new UndoableCommand is executed, the redo stack is cleared. That is, the redo stack is only non empty when the latest executed Command(s) is/are UndoCommand(s).

The activity diagram below shows the flow of the redo command.

][

3.5. [Previous] Undo/Redo feature

3.5.1. Previous Implementation [Has since been refactored]

The undo/redo mechanism is facilitated by ElisaStateHistory. It stores a stack of type ElisaState, which keeps track of the app data with a deep copy of the ItemStorage and the current displayed list with a deep copy of VisualizeList. Additionally, it implements the following operations:

  • ElisaStateHistory#push() — Saves the current ELISA state in its history.

  • ElisaStateHistory#pop() — Removes and returns the latest state as long as there is more than 1 item in the stack. This 1 item is the original application state that is saved on startup.

  • ElisaStateHistory#size() — Returns the number of states in the stack.

Given below is an example usage scenario and how the undo mechanism behaves at each step.

Step 1. The user launches the application for the first time. The ElisaStateHistory will be initialized with the initial ELISA state

][

Step 2. The user executes task eat command to add a task with a description "eat". Upon execution of any command except undo and show, the Logic calls ItemModel#updateState() to save the latest state to ElisaStateHistory.

][

Step 3. The user executes task jogging to add another task with description "jogging". This command also calls ItemModel#updateState(), causing another modified ELISA state to be saved into the ElisaStateHistory.

][
If a command fails its execution, it will not call ItemModel#updateState(), so the ELISA state will not be saved.

Step 4. The user now decides that adding the task "jogging" was a mistake, and decides to undo that action by executing the undo command. The undo command will call ElisaStateHistory#popCommand(), which will delete the last added state, and Logic will update the application state to the one at the top of the stack after command execution.

][
If the size of ElisaStateHistory is 1, that is, only containing the initial state, then there are no previous Elisa states to restore. The undo command checks for this case within its execute() method. If so, it will return an error to the user rather than attempting to perform the undo.

The following sequence diagram shows how the undo operation works:

UndoStateSequence

3.5.2. Design Considerations

Aspect: How undo & redo executes
  • Alternative 1 (initial choice): Saves the entire Elisa state.

    • Pros: Easy to implement.

    • Cons: May have performance issues in terms of memory usage, especially when a large number of items are added.

    • Another Con found after implementation: Reminders fire multiple times due to storing multiple references to items

  • Alternative 2 (current choice): Individual command knows how to undo/redo by itself.

    • Pros: Will use less memory (e.g. for delete, just save the item being deleted).

    • Cons: We must ensure that the implementation of each individual command are correct.

3.6. Priority Mode

3.6.1. Implementation

The priority mode is used to aid the user in focusing on the most pressing task that they have especially when they have many tasks in their list. As priority mode is only for clearing of tasks, the priority mode can only be activated at the task pane of the application.

The priority mode is mainly controlled in the ItemModelManager and the following are the methods it uses within the ItemModelManager:

  • ItemModelManager#togglePriorityMode() - Toggle the priority mode depending on whether it is on or off.

  • ItemModelManager#toggleOnPriorityMode() - Helper function to toggle on the priority mode.

  • ItemModelManager#toggleOffPriorityMode() - Helper function to toggle off the priority mode.

There are two variants to the priority mode, a normal priority mode and a focus mode. The focus mode is more restrictive than the normal priority mode, preventing the user from doing any operations that are not relevant to the task list, such as adding a new event. This is currently implemented by having a separate Parser when ELISA is in focus mode. (Refer to Section 3.6.4, “Design Consideration” for more details)

There are two ways to trigger priority mode, a normal priority mode that is controlled fully by the user and a scheduled priority mode that is triggered by the user but is scheduled to turn off after a specific amount of time. In addition to the above three methods, the scheduled priority mode also uses the following method:

  • ItemModelManager#startTimer(LocalDateTime) - Starts a timer to turn off the priority mode.

3.6.2. Example run of priority mode

In this section, we will show a run of the priority mode and a overview of the mechanism at each step. In particular, we will be showing how the ScheduledPriorityCommand works as it has a more complicated implementation than the normal PriorityCommand.

  1. The user opens his Task panel and types in priority 30.min.later.

  2. The incomplete tasks are added to a PriorityQueue where they are ranked by their priority.

  3. Once all the items are added into the PriorityQueue, ELISA will peek the first task from the queue and present it to the user.

  4. The user can type done 1 when he is done with the current task to retrieve the next task. This carries on until there is no more undone task left to do in the PriorityQueue. This is shown in the activity diagram below.

300
Figure 16. Activity diagram for priority mode
  1. ELISA will automatically disable the priority mode after 30 minutes and show all the task that the user have in his task list currently.

3.6.3. Internal working of the command

The figure below shows the sequence diagram on what happens from a simple execution of the priority 30.min.later command. We will go through the internal mechanism of the execution of the ScheduledPriorityCommand.

PriorityMode
Figure 17. Sequence diagram for priority mode
  1. When the user types in the command, the LogicManager takes in the command as a string and pass it to the ELISAParser

  2. The ELISAParser parses the string and determine whether the command is that of a normal PriorityCommand or a ScheduledPriorityCommand. In this case, a new ScheduledPriorityCommand is created and is passed back to the LogicManager.

The following steps (except step 4) are also applicable to PriorityCommand.
  1. Within the LogicManager, the ScheduledPriorityCommand#execute() method is called and the command is executed.

  2. The ScheduledPriorityCommand calls the ItemModel#scheduleOffPriorityMethod() which creates a new Timer object and a new TimerTask object. The TimerTask object will be scheduled to fire off at a specific time, which in this case is 30 minutes later (as defined by the user).

  3. The SchedulePriorityCommand then calls ItemModel#togglePriorityMode() which calls the private method ItemModel#toggleOnPriorityMode() (since the current state of the priority mode is false).

  4. This creates a new TaskList which will have the task with the highest priority added to it. This TaskList will be displayed to the user.

  5. A CommandResult is passed to the ScheduledPriorityCommand and then back to the LogicManager to be passed into the Ui, informing the user that the priority mode is activate.

A normal PriorityCommand will end at this point and will only be deactivated by the user’s input of priority again.
300
Figure 18. Sequence diagram for the scheduled turning off of priority mode
  1. As the Timer within the ItemModelManager is still running on a separate thread, it will trigger the TimerTask#run() when the user defined time is reached.

  2. The TimerTask will call ItemModelManager#toggleOffPriorityMode() which will cancel the Timer and destroy the Timer. This is to ensure proper cleanup of the thread.

  3. All the items are added back into the TaskList and shown to the user. The priority mode is deactivated.

3.6.4. Design Consideration

Aspect: How to restrict commands for focus mode

  • Alternative 1: Storing a boolean within the ItemModelManager to check if the application is in focus mode or normal mode. Commands that are not allowed to be called in focus mode will check against this boolean to determine if the command is allowed.

Pros Cons

This implementation will contain the changes within the class of the Command itself and will ensure that they do not interfere with each other. This will make it easier to maintain the code.

This implementation is not scalable as each new Command that is added will need to be checked to see if they are allowed in focus mode. There is also the additional overhead of checking the state of the ItemModelManager at every call of Command#execute().

  • Alternative 2 (Current implementation): Create a new FocusElisaParser that extends from the current ElisaParser but prevent the parsing of commands that are not allowed in focus mode.

Pros Cons

This implementation stops the creation of the Command at the Parser level which will reduce the computational cost to the application.

There might be difficulty in maintaining the Parser#parse() method of the two Parser.

Both methods are not scalable in the long run, but at this moment, alternative 2 is favoured as it prevents the command from even being parsed or created, which saves the computing time. At the same time, it is easier to maintain as one only needs to edit the Parser#parse() method instead of having an if-else loop in all the command that are banned.

Aspect: How to turn off the priority mode after a fixed time

  • Alternative 1: Storing the timer within the ScheduledPriorityCommand.

Pros Cons

Adheres to the SLAP principle with each class having it’s own implementation of the Command#execute(ItemModel). It is easier to maintain the code and prevents overloading the ItemModelManager.

There is no way to end the schedule priority mode prematurely as the timer is kept within the command and so cannot be referenced after the execution of the command.

  • Alternative 2 (Current implementation): Storing the timer within the ItemModelManager.

Pros Cons

The timer can be referenced from the ItemModelManager and so it can be cancelled prematurely if the user chooses to do so.

This implementation will clutter the ItemModelManager further and make it harder for maintaining the code.

Alternative 2 was chosen as we believe that the ability to cancel a scheduled priority mode prematurely is more important than the maintainability of the code at the moment.

3.6.5. Possible extension

At the moment, the user is not able to keep track of the amount of time that he has before the schedule priority mode is over. This can be improved by including a countdown timer in the Ui when the user toggles on the scheduled priority mode.

3.7. Add Task/Event feature

Task, Events and Reminders are all Items and can be added using the same command. Adding of Items is facilitated by ItemModel#add(Item).

3.7.1. Implementation

A Task with a deadline flag -d will be considered an Event. A Task with a reminder flag -r will be considered a Reminder.
The following activity diagram shows the how a task can be added, depending on the flags present:

200
Figure 19. Activity Diagram of adding a Task

This shows how we can easily add Task, Event and Reminder with a single command. However, in this section, we will only show how Task and Event is added. Adding of Reminders is shown in a separate section as it includes other steps.

3.7.2. Internal workings of the command

Given below is an example usage scenario of how add behaves at each step:

Step 1. The user enters the command "task shower -d 1.hour.later".
Step 2. The LogicManager creates an ELISAParser to parse the user input.
Step 3. ELISAParser creates a AddTaskCommandParser which parses the input and returns an AddCommand.
Step 4. LogicManager will execute the AddCommand. AddCommand will then invoke ItemModel#add(Item), which adds Task to its TaskList and Event to its EventList.
Step 5. AddCommand will also trigger a change in view by calling ItemModel#setVisualList(taskList) Step 6. Upon the successful execution of AddCommand, a CommandResult is returned to the LogicManager, which will then be returned to the Ui to render the appropriate view.

The figures below shows the sequence diagram on what happens from a simple execution of task shower -d 1.min.later user command:

AddCommandPart 1
Figure 20. Call execute in LogicManager to create an AddTaskCommand

This diagram shows how execute is carried out in the Logic component. The following diagram shows how the same command is continued onto the Model component:

AddCommandPart 2
Figure 21. LogicManager executes the AddTaskCommand and returns CommandResult

This shows how execute(model) affects the Model component. It then returns a CommandResult r, which is the result of calling LogicManager#execute("task shower -d 1.hour.later").

3.7.3. Design considerations

The design considerations for the classes are shown below:

Alternatives:

Pros:

Cons:

1. Placing all fields into an Item object and retrieving the specific fields when needed.

Easy to implement. Reduce dependencies between classes as everything is in one class. Editing can be done all in one object.

Does not separate out the different functionalities of Task, Event and Reminder.

2. Having separate classes for Task, Event, Reminder

Reduce dependencies as well as having functionalities separated.

Some attributes and methods overlap. Repetition of code for same functionality. Have to add all three objects individually. Editing of an item would require searching, obtaining and individually editing all 3 objects.

3. (Current) Having a general Item class which comprise of Optional<> fields Task, Event, Reminder

Similar fields such as description and priority can be placed in Item. This makes adding an Item more convenient. Related task/event/reminder can have access to each other.

Increase coupling and dependency amongst Task, Event, Reminder classes.

As of now, these are the considered designs and the current design seems to work well for our purpose. However, there could be better designs which are unexplored that could mitigate our cons and we welcome them.

This is end of the section of adding a Task and Event. As mentioned above, adding of Reminder will be shown in a separate section due it having extra features. Do look out for it if you’re interested.

3.8. Rescheduling of recurring Events automatically

This section talks about how the autoReschedule function is implemented. This feature aims to provide users with greater convenience when scheduling events that occur periodically (eg. weekly deadlines, monthly appointments).

3.8.1. Implementation

To reschedule a task, we need a deadline as we need to be able to calculate the next date. Recall that any Task with a deadline is considered an Event. As such, only Events can be rescheduled.

To automatically reschedule an Event, when creating the Event, include the -auto flag along with its reschedule period (eg -auto day for daily rescheduling)
The accepted parameters for -auto is day, week, month and the format of 10.min.later.

The following diagram shows the process of adding an Event with -auto flag:

100
Figure 22. Activity diagram of adding an Event with -auto flag

In the diagram, when we add the Event initially, we would check the start time of the Event and update it accordingly. However, this is not the only place where rescheduling occurs.

3 places where rescheduling can occur:

  1. When the event is created, as shown in the diagram above.

  2. While the app is running, the Event’s start time will be continuously updated when it has passed.
    This is done using Timer and TimerTask, using Timer#scheduleAtFixedRate().

  3. When the app is started and Events are loaded from the storage. The stored Event time might already be over, as such the time has to be updated to the latest upcoming one.

To illustrate how they work, first we need to know what classes are involved before we can understand the sequence of actions carried out.
The classes involved in the above rescheduling are:

  • AutoReschedulePeriod — Represents the period of every reschedule (eg day/week/month)

  • RescheduleTask — Represents the action to perform when rescheduling its associated event.

  • AutoRescheduleManager — Manages all the rescheduling tasks. There is only one of such manager.

To better understand its underlying structure, we can look at the class diagram below:

100
Figure 23. Class Diagram of classes involved in AutoReschedule function

3.8.2. Internal workings of the command

Now we are ready to look at the sequence of actions. Given below is an example usage scenario of how add behaves at each step:

Step 1. The user enters the command event CS2103T Quiz -d 23/09/2019 2359 -auto week.
Step 2. The Event is created, following the sequence of steps in the section Adding Task/Event. However there are now some extra steps from Step 3 onwards that occur concurrently from the object creation of Event.
Step 3a. The presence of the -auto week creates an AutoReschedulePeriod, which is stored in the Event created. This can be seen in the Class Diagram above.
Step 3b. If the start time of this Event is already over, the Event’s start time will be modified to show the next start time, using this Event’s AutoReschedulePeriod. Step 4. When LogicManager#execute(model) is called, the presence of AutoReschedulePeriod in the Event triggers the creation of a RescheduleTask, which represents the task of rescheduling this Event.
Step 5. This RescheduleTask is added to an AutoRescheduleManager, which manages all RescheduleTasks.
Step 6. When the start time of this Event has passed, AutoRescheduleManager will call RescheduleTask#run(), and this updates the Event start time, which will be reflected in the Ui.

The following diagrams show how the command event Quiz -d 10.hour.later -auto week is executed from the Logic component. The first diagram shows the adding of an Event, which may appear familiar as it has a sequence similar to the adding of task in Section 3.1, “Add Task/Event feature”. However, there are some minor differences due to the presence of -auto which should be noted.

AutoRescheduleSequence 1
Figure 24. Call execute in LogicManager and create an AddEventCommand

As mentioned, the key points to take note of in the diagram above is Event#setAutoReschedule(true) and Event#setReschedulePeriod(period).
The significance of these methods will be shown in the continuing diagram below:

AutoRescheduleSequence 2
Figure 25. LogicManager executing AddEventCommand and create task for AutoRescheduleManager

From the above diagram, we can see that the presence of AutoReschedulePeriod in Event results in the creation of RescheduleTask which would be queued into the Timer managed by AutoRescheduleManager.

3.8.3. Design considerations

The design considerations for the classes are shown below:

Alternatives:

Pros:

Cons:

Creating a AutoRescheduleManager for every RescheduleTask

Easy for the Timer in AutoRescheduleManager to keep track of its TimerTask.

There could potentially be many Timer threads.

(Current) Singleton pattern for AutoRescheduleManager

Ensure that only one instance can be instantiated as there should only be one manager for all the RescheduleTask. If there are multiple managers, it would be hard to keep track of all of them and it would be difficult to coordinate all the tasks.

Difficult to create tests for AutoResheduleManager. Could have many hidden dependencies, which makes code harder to maintain.

3.9. Add Reminder feature

Step 1. The user enters the command "reminder John’s Birthday -r 3.day.later".
Step 2. The LogicManager creates an ELISAParser to parse the user input.
Step 3. ELISAParser creates a AddReminderCommandParser which parses the input and returns an ReminderCommand.
Step 4. LogicManager will execute the ReminderCommand. AddCommand will then invoke ItemModel#add(Item), which adds the Item that contains the reminder to the RemindersList and the futureRemindersList.
Step 5. Each time an Item is added to the futureRemindersList, the Items in futureRemindersList is sorted according to the occurrenceDateTime of its Reminder in order of recency.
Step 6. AddCommand will also trigger a change in view by calling ItemModel#setVisualList(taskList)
Step 7. Upon the successful execution of AddCommand, a CommandResult is returned to the LogicManager, which will then be returned to the Ui to render the appropriate view.

When the application is launched, the LogicManager also creates a separate thread using the ScheduledThreadPoolExecutor that constantly runs checkTask every 5 seconds.
CheckTask is a runnable that monitors the ItemModelManager to see if there are any reminders in futureRemindersList that have an occurrenceDateTime after LocalDateTime#now().
If there is, it transfers those reminders to activeRemindersList which is an ObservableList.

Meanwhile, the MainWindow binds a listener activeRemindersList in order to observe if any Items with Reminders have been added to it.
If so, it will add ReminderDialogBox with the appropriate details for the added Items to the resultDisplay.

3.10. Snooze Reminder feature

We can see how snooze is performed through the activity diagram below.

SnoozeActivityDiagram
Figure 26. Activity Diagram to snooze a reminder

From the image above, we can see that there 2 guard conditions.
The first checks whether there is a reminder to snooze (either via an index or recently occurred reminder). If there isn’t, an exception is thrown.
The second checks if the newReminderOccurrenceIsValid (i.e. reminder does not occur in the past). Otherwise, it throws an exception.
If the duration of the reminder is not specified, then the default duration for the snooze is 5 minutes.

3.11. Logging

We are using java.util.logging package for logging. The LogsCenter class is used to manage the logging levels and logging destinations.

  • The logging level can be controlled using the logLevel setting in the configuration file (See Section 3.12, “Configuration”)

  • The Logger for a class can be obtained using LogsCenter.getLogger(Class) which will log messages according to the specified logging level

  • Currently log messages are output through: Console and to a .log file.

Logging Levels

  • SEVERE : Critical problem detected which may possibly cause the termination of the application

  • WARNING : Can continue, but with caution

  • INFO : Information showing the noteworthy actions by the App

  • FINE : Details that is not usually noteworthy but may be useful in debugging e.g. print the actual list instead of just its size

3.12. Configuration

Certain properties of the application can be controlled (e.g user prefs file location, logging level) through the configuration file (default: config.json).

4. Documentation

Refer to the guide here.

5. Testing

Refer to the guide here.

6. Dev Ops

Refer to the guide here.

Appendix A: Product Scope

Target user profile:

  • has a need to manage a large number of tasks

  • needs reminders to take breaks or move on to finish all their work

  • prefers to be more organized with their time and tasks

  • prefer desktop apps over other types of apps

  • prefers typing over mouse input

  • can type fast

  • is reasonably comfortable using CLI apps

Value proposition: manage time and tasks more efficiently than a typical mouse/GUI driven app

Appendix B: User Stories

Priorities: High (must have) - * * *, Medium (nice to have) - * *, Low (unlikely to have) - *

Priority As a …​ I want to …​ So that I can…​

* * *

user

add a new task

record tasks that need to be done 'some day'

* * *

user

mark a task as done

keep track of my remaining tasks

* * *

user

delete a task

remove tasks that I no longer need

* * *

student

add deadline to a task

remember my task deadlines

* * *

user

find upcoming tasks

decide what needs to be done

* * *

user

find a task by description

find only the tasks that are relevant to me at that point in time

* * *

new user

view more information about a command

learn how to use various commands

* * *

forgetful student

be reminded of deadlines

remember to complete them before they are due

* * *

user

type my commands in the text

use the app without needing the mouse

* * *

user

use the undo function

reverse any changes I made by mistake

* *

busy student

see my reminders as notifications

be reminded of them even in other applications

* *

user with many tasks

sort tasks by priority

identify which tasks require my immediate attention

* *

student

turn on priority mode

focus on only one pressing issue at a time

* *

user

have a software that saves after every action

will not lose information even if I close the program by accident

* *

user

look at a summary of all deadlines in the calendar

see when I am free

* *

user

edit the date of a deadline

fix my mistakes if I type the wrong command

*

stressed student

ask ELISA to tell a joke

feel less stressed when my assistant has a sense of humour

*

user

colour code my calendar events

easily categorise and differentiate between them

{More to be added}

Appendix C: Use Cases

(For all use cases below, the System is ELISA and the Actor is the user, unless specified otherwise)

Use Case 001: Marking a task as done

MSS

  1. User enters the command to show the task list.

  2. ELISA shows the task list to the user.

  3. User marks the task as done by using the index of the task.

  4. ELISA updates the task list.

  5. ELISA shows the updated task list to the user.

    Use case ends.

Extensions

  • 2a. The task list is empty.

    Use case ends.

  • 3a. The given index is invalid.

    • 3a1. ELISA shows an error message.

      Use case resumes at step 2.

Use Case 002: Adding a task

MSS

  1. User creates a new task with a description.

  2. ELISA informs the user that the task has been added.

    Use case ends.

Extensions

  • 1a. User can add deadline.

    • 1a1. ELISA informs the user that a deadline has been added to that task.

      Use case ends

  • 1b. User can add a reminder date.

    • 1b1. ELISA informs the user that a reminder has been added to that task.

      Use case ends

  • 1c. User enters an empty description.

    • 1c1. ELISA informs the user that the description cannot be empty.

    • 1c2. User enters a non-empty description

      Use case resumes at step 2

  • a. At any time, User can view the task from the task list or the calendar view.

  • b. At any time, User can add a deadline to the task

  • c. At any time, User can add a reminder to the task

Use Case 003: Deleting a task

MSS

  1. User enters the command to show the task list.

  2. ELISA shows the task list.

  3. User request to delete a task based on its index.

  4. ELISA deletes the task from the task list.

  5. ELISA shows the updated task list.

    Use case ends.

Extensions

  • 2a. The task list is empty.

    Use case ends.

  • 3a. The given index is invalid.

    • 3a1. ELISA shows an error message.

      Use case resumes at step 2.

Use Case 004: Snooze a reminder

MSS

  1. User enters the snooze command.

  2. ELISA snoozes the reminder.

  3. ELISA reminds the user of that reminder after the specified duration.

Extensions

  • 1a. There are no recent reminders to be snooze

    • 1a1. ELISA displays an error message.

      Use case ends.

  • 1b. The user does not which reminder to snooze.

    • 1b1. ELISA snoozes the most recent reminder.

Use case resumes at step 2.

  • 1c. The user does not specify how long to snooze.

    • 1c1. ELISA snoozes the reminder for a default duration.

Use case resumes at step 2.

Use Case 005: Find upcoming reminders.

MSS

  1. User enters the command to show the reminder list.

  2. ELISA shows the reminder list.

  3. User enters command to sort reminders by date and time.

  4. ELISA shows the updated list of reminders sorted by date and time.

Use Case 006: Search for a task by its description

MSS

  1. User enters the command to show the task list.

  2. ELISA shows the reminder list.

  3. User enters command to find all matching tasks with the given search term(s)

  4. ELISA shows a list of tasks with descriptions matching the search term(s)

Extensions

  • 4a. There are no matching tasks

    • 4a1. ELISA shows that there are 0 items listed

      Use case ends.

Use Case 007: Undo the last command

MSS

  1. User enters the undo command.

  2. ELISA reverts the last executed command.

  3. ELISA displays a confirmation message.

Extensions

  • 2a. There are no commands to be undone

    • 2a1. ELISA displays an error message.

      Use case ends.

Use Case 008: Using Priority Mode

MSS

  1. User enters the command to enter priority mode.

  2. ELISA hides all tasks except the one with the highest priority.

  3. User enters command to set that task as done once they finish it.

  4. ELISA shows the next highest priority task.

Extensions

  • 1a. User is not viewing the task list

    • 1a1. ELISA displays an error message

      Use case ends. {More to be added}

Appendix D: Non Functional Requirements

  1. Should work on any mainstream OS as long as it has Java 11 or above installed.

  2. Should be able to hold up to 1000 tasks / events / reminders (combined) without a noticeable sluggishness in performance for typical usage.

  3. A user with above average typing speed for regular English text (i.e. not code, not system admin commands) should be able to accomplish most of the tasks faster using commands than using the mouse.

{More to be added}

Appendix E: Glossary

Mainstream OS

Windows, Linux, Unix, OS-X

Private contact detail

A contact detail that is not meant to be shared with others

Appendix F: Product Survey

Product Name

Author: …​

Pros:

  • …​

  • …​

Cons:

  • …​

  • …​

Appendix G: Instructions for Manual Testing

Given below are instructions to test the app manually.

These instructions only provide a starting point for testers to work on; testers are expected to do more exploratory testing.

G.1. Launch and Shutdown

  1. Initial launch

    1. Download the jar file and copy into an empty folder

    2. Double-click the jar file
      Expected: Shows the GUI with an empty set of tasks. The window size may not be optimum.

  2. Saving window preferences

    1. Resize the window to an optimum size. Move the window to a different location. Close the window.

    2. Re-launch the app by double-clicking the jar file.
      Expected: The most recent window size and location is retained.

G.2. Adding a task

  1. Adding a task while on the task list panel

    1. Prerequisites: Switch to the task list panel using the show T command.

    2. Test case: task testcase
      Expected: A task with the description "testcase" is added to the task list panel. The priority of the task is medium (the default value).

    3. Test case: task testcase 2 -p high
      Expected: A task with the description "testcase 2" and of high priority is added to the task list panel.

  2. Adding a task while not on the task list panel

    1. Prerequisites: Switch to the event list panel using the show E command.

    2. Test case: task testcase 3 -p low -d 1.min.later
      Expected: ELISA will automatically switch to the task list panel and a new task with the description "testcase 3" and priority low should be added to the task list panel.

  3. Adding a task that already exists

    1. Prerequisites: The task list panel must already be populated and a task on the list is already know.

    2. Test case: task testcase (in this case, we are using one of the earlier test case)
      Expected: Elisa will prompt you that the task already exist in the list and cannot be added.

    3. As an additional test case, you can mark a current task as done and then try adding that task into ELISA again. ELISA will still flag it as a repeated object despite the different state of completeness.

Even though this is for task, the same tests can be used for testing events and reminders.

G.3. Deleting a task

  1. Deleting a task while all tasks are listed

    1. Prerequisites: Switch to the task list panel using the show T command. There should be multiple tasks in the list

    2. Test case: delete 1
      Expected: First task is deleted from the list. Details of the deleted task will show in the result display.

    3. Test case: delete 0
      Expected: No task is deleted. Error details shown in the result display.

    4. Other incorrect delete commands to try: delete, delete x (where x is greater than the size of the list), delete y (where y is a negative index)
      Expected: Similar to previous.

      Even though this is for task, the same tests can be used for testing events and reminders.

G.4. Adding a reminder

  1. Adding a reminder

    1. Prerequisites: Know the current date and time. Volume of computer is audible to tester.

    2. Test case: reminder John’s Birthday -r 1.min.later
      Expected: View is switched to reminder list panel (if not already there). A reminder is added to the reminder list. Details of the reminder will be shown in the result display. After 1 minute, a chime is played and a red dialog box with the details of the reminder will appear in the result display.

    3. Test case: reminder John’s Birthday -r x (where x is the date and time 1 minute later from now in the format dd/MM/yyyy HHmm. E.g. reminder John’s Birthday -r 15/11/2019 1800) Expected: Similar to previous test case. (Since x is 1 minute from now.)

    4. Test case: reminder John’s Birthday -r y (where y is the date and time 1 minute later from now in the format yyyy-MM-ddTHHmm. E.g. reminder John’s Birthday -r 2019-11-15T18:00) Expected: Similar to previous test case. (Since y is 1 minute from now.)

    5. Test case: undo (used after one of the above has taken place) Expected: ELISA will reverse the addition of the reminder and no reminder will occur later on.

    6. Test case: redo (used after a valid undo command has taken place) Expected: ELISA will reverse the undo of the addition of the reminder and a reminder will occur at the appropriate time. Note that if the time for the reminder to occur has already passed, the reminder will not occur.

    7. Test case: reminder John’s Birthday -r z (where z is the date and time 1 minute before now in the format dd/MM/yyyy HHmm. E.g. reminder John’s Birthday -r 15/11/2019 1358) Expected: No reminder is added. Error details shown in result display. (Since z is 1 minute before now.)

G.5. Snoozing a reminder

  1. Snoozing a reminder

    1. Prerequisites: Reminder has been added. Know the current date and time. Volume of computer is audible to tester.

    2. Test case: snooze 1
      Expected: First reminder of the reminder list will occur again five minutes from now.

    3. Test case: snooze 1 -s 1.min.later
      Expected: First reminder of the reminder list will occur again one minute from now.

    4. Test case: snooze 1 -s x (where x is the date and time 1 minute later from now in the format dd/MM/yyyy HHmm. E.g. reminder John’s Birthday -r 15/11/2019 1800) Expected: Similar to previous test case. (Since x is 1 minute from now.)

    5. Test case: snooze John’s Birthday -s y (where y is the date and time 1 minute later from now in the format yyyy-MM-ddTHHmm. E.g. reminder John’s Birthday -s 2019-11-15T18:00) Expected: Similar to previous test case. (Since y is 1 minute from now.)

    6. Test case: undo (used after one of the above has taken place) Expected: ELISA will reverse the snoozing of the reminder and reminder’s occurrence date time will revert to it its state before the snooze.

    7. Test case: redo (used after a valid undo command has taken place) Expected: ELISA will reverse the undo of the snoozing of the reminder and a reminder will occur at the appropriate time. Note that if the time for the reminder to occur has already passed, the reminder will not occur.

    8. Test case: snooze John’s Birthday -s z (where z is the date and time 1 minute before now in the format dd/MM/yyyy HHmm. E.g. reminder John’s Birthday -s 15/11/2019 1358) Expected: No reminder is snoozed. Error details shown in result display. (Since z is 1 minute before now.)

G.6. Editing a task

  1. Editing a task while all tasks are listed

    1. Prerequisite: Switch to the task list panel using the show T command. There should be at least one task in the list

    2. Test case: edit 1 -p high
      Expected: The priority of the first task is changed to high (if the original priority of the task is already high, try other priority).

    3. Test case: edit 1 -desc testcase
      Expected: The description of the first task should change to "testcase".

    4. Test case: edit 1 -d 1.min.later
      Expected: A new event should be created for the task. You can verify by switching to the event panel or opening the task using the open 1 command.

    5. Test case: edit 1 -p high -d 2.min.later
      Expected: A new event should be created for the task (if it does not already exist) or the time of the event will be updated. The priority of the task will also change.

    6. Test case: Try different variation of the edit command to ensure that it works.

  2. Editing a task to another task that is in the list

    1. Prerequisite: Switch to the task list panel using the show T command. There should be at least two task in the list.

    2. Test case: Attempt to edit the first task such that it is the same as the second task. For example, if the second task has a description "testcase" and a priority of high, run edit 1 -desc testcase -p high.
      Expected: ELISA will feedback that the task already exists and will prevent you from editing.

  3. Editing a task to remove the task

    1. Prerequisite: Switch to the task list panel using the show T command. There should be at least one task in the list.

    2. Test case: edit 1 --tk when the task has an event and/or reminder.
      Expected: ELISA will remove the task from the task list but the event and/or reminder will still be viewable in the event/reminder panel.

    3. Test case: edit 1 --tk when the task has no event and no reminder. Expected: ELISA will prompt that you cannot edit an item such that it has no task, event or reminder and the task will not be removed from the task list.

Even though this is for task, the same tests can be used for testing events and reminders.

G.7. Undoing/Redoing previous commands

  1. Undoing when no UndoableCommand(s) have been executed

    1. Prerequisites: Open the application and do not execute any add, edit, delete, priority or show commands

    2. Test case: undo
      Expected: No changes to be undone. Error message shown in chat box.

    3. Test case: redo
      Expected: No undo commands to be redone. Error message shown in chat box.

  2. Undoing when UndoableCommand(s) have been executed

    1. Prerequisites: Open the application and execute some commands like adding/removing items, changing done/not done of tasks, modifying dates/descriptions

    2. Test case: undo
      Expected: Last executed change should be reverted.

    3. Test case: redo
      Expected: Last undone change should be re-applied

    4. Other test cases: You can undo and redo multiple times in either direction to remove and apply changes.

  3. Redoing when previous UndoCommand(s) exist but are not the last executed

    1. Prerequisites: Execute at least one UndoableCommand, followed by one or more UndoCommand(s), and then another UndoableCommand

    2. Test case: redo
      Expected: Should not be able to redo as the undo/redo command history has changed. Error message shown in chat box. === Game mode testing

500
Figure 27. Entering game mode (easy)
  1. Test case: game
    Expected: Enters easy mode of game (Refer to figure above)

  2. Test case: game e
    Expected: Same as above.

  3. Test case: game EASY Expected: Same as above.

500
Figure 28. Entering game mode (hard)
  1. Test case: game H
    Expected: Enters hard mode of game (Refer to figure above)

  2. Test case: game hard
    Expected: Same as above.

G.8. Change theme testing

  1. Changing theme of ELISA

    1. Prerequisites: You must be in a different theme from the theme you are switching to before you can see the change.

    2. Test case: theme white Expected: Change ELISA’s theme to white.

G.9. Priority mode testing

  1. Toggling on priority mode

    1. Prerequisites: Switch to the task list panel using the show T command. There should be at least 1 incomplete task in the list and priority mode should be disabled at the moment.

    2. Test case: priority
      Expected: The ELISA icon will turn red and only one task will be shown on the task list panel. You can try switching a panel (show E) or adding an event to make sure it works.

    3. Test case: priority -f
      Expected: Same as above, except this time switching of panel or adding an event is not allowed.

    4. Test case: priority 1.min.later -f
      Expected: Same as above, except this time priority mode will deactivate after 1 minute.

    5. Test case: priority -d Expected: Flag not recognized and ELISA will reject the command.

  2. Toggling off priority mode

    1. Prerequisites: Switch to the task list panel using the show T command. Priority mode is already activated.

    2. Test case: priority
      Expected: Deactivate priority mode and show you all your tasks.

    3. Test case: priority 1.min.later, priority -f
      Expected: Same as above.

  3. Manipulate list while in priority mode

    1. Prerequisites: Switch to the task list panel using the show T command. Priority mode is already activated.

    2. Test case: done 1
      Expected: ELISA will mark the task as done and generate the next task. If there is no next task, ELISA will automatically take you out of priority mode.

    3. Test case: delete 1
      Expected: ELISA will delete the task and generate the next task. If there is no next task, ELISA will automatically take you out of priority mode.

    4. Test case: edit 1 -p low (most effective for a task list with more than 1 task and the current task priority is high/medium)
      Expected: ELISA will edit the priority of the current task to low (any other priority can be used). A new task with a higher priority will be generated.

    5. Test case: undo (used after one of the above has taken place)
      Expected: ELISA will reverse the previous process and the old task will be generated again.

    6. Test case: redo (used after an undo command)
      Expected: ELISA will reverse the undo command and a new task is generated.

    7. Other test cases: You can try doing all of these commands in focus mode priority -f to ensure that they work. When in focus mode, you can try some of the banned command like show, game etc to make sure that it does not work.

G.10. Saving data

  1. Checking that ELISA saves the data properly

    1. Copy ELISA.jar to a new directory and open it. This is to ensure that there is no old data file. An empty ELISA will be displayed. Type some sample data into ELISA and you will notice that a data file has been created at the path data/itemstorage.json. You can open the file to see that the data has been added.

  2. Dealing with missing/corrupted data files

    1. To simulate a missing data file, start up ELISA. ELISA will create a data file for you as data/itemstorage.json (this is the default name of the storage file). Close ELISA and delete the itemstorage.json file. Re-open ELISA and ELISA will start with a new and empty data file. Verify it at data/itemstorage.json.

    2. To simulated a corrupted data file, start up ELISA. Type some test input into ELISA. Close ELISA. Open the data/itemstorage.json file and edit some of the fields there. Open ELISA again. ELISA will realize that the data is corrupted and will generate a new data file for you.

{ more test cases …​ }