Skip to content

Latest commit

 

History

History
849 lines (555 loc) · 40 KB

DeveloperGuide.adoc

File metadata and controls

849 lines (555 loc) · 40 KB

ELISA - Developer Guide

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.

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.

LogicComponentUML
Figure 2. Class Diagram of the Logic Component

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 a person).

  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

Given below is the Sequence Diagram for interactions within the Logic component for the execute("delete 1") API call.

DeleteSequenceDiagram
Figure 6. Interactions Inside the Logic Component for the delete 1 Command
ℹ️
The lifeline for DeleteCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.

2.4. Model component

ModelClassDiagram
Figure 7. Structure of the Model Component

API : Model.java

The Model,

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

  • stores the Item Storage data

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

ℹ️
The reason for using four observable list as opposed to having one observable list that is filtered every time we update the list is because we believe that this will lead to faster loading time every time we switch view as it is just a change in the Visualization List pointer. This is better than the O(n) method of filtering a single VisualizeList as it will require going through all the items in the list.

2.5. Storage component

StorageClassDiagram
Figure 8. 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. [Implemented] Undo Feature

3.1.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.

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.

UndoStackStep1

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.

UndoStackStep2

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

3.2. [Proposed] Undo/Redo feature

3.2.1. Proposed Implementation

The undo/redo mechanism is facilitated by VersionedAddressBook. It extends AddressBook with an undo/redo history, stored internally as an addressBookStateList and currentStatePointer. Additionally, it implements the following operations:

  • VersionedAddressBook#commit() — Saves the current address book state in its history.

  • VersionedAddressBook#undo() — Restores the previous address book state from its history.

  • VersionedAddressBook#redo() — Restores a previously undone address book state from its history.

These operations are exposed in the Model interface as Model#commitAddressBook(), Model#undoAddressBook() and Model#redoAddressBook() respectively.

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

Step 1. The user launches the application for the first time. The VersionedAddressBook will be initialized with the initial address book state, and the currentStatePointer pointing to that single address book state.

UndoRedoState0

Step 2. The user executes delete 5 command to delete the 5th person in the address book. The delete command calls Model#commitAddressBook(), causing the modified state of the address book after the delete 5 command executes to be saved in the addressBookStateList, and the currentStatePointer is shifted to the newly inserted address book state.

UndoRedoState1

Step 3. The user executes add n/David …​ to add a new person. The add command also calls Model#commitAddressBook(), causing another modified address book state to be saved into the addressBookStateList.

UndoRedoState2
ℹ️
If a command fails its execution, it will not call Model#commitAddressBook(), so the address book state will not be saved into the addressBookStateList.

Step 4. The user now decides that adding the person was a mistake, and decides to undo that action by executing the undo command. The undo command will call Model#undoAddressBook(), which will shift the currentStatePointer once to the left, pointing it to the previous address book state, and restores the address book to that state.

UndoRedoState3
ℹ️
If the currentStatePointer is at index 0, pointing to the initial address book state, then there are no previous address book states to restore. The undo command uses Model#canUndoAddressBook() to check if this is the case. 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:

UndoSequenceDiagram
ℹ️
The lifeline for UndoCommand should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.

The redo command does the opposite — it calls Model#redoAddressBook(), which shifts the currentStatePointer once to the right, pointing to the previously undone state, and restores the address book to that state.

ℹ️
If the currentStatePointer is at index addressBookStateList.size() - 1, pointing to the latest address book state, then there are no undone address book states to restore. The redo command uses Model#canRedoAddressBook() to check if this is the case. If so, it will return an error to the user rather than attempting to perform the redo.

Step 5. The user then decides to execute the command list. Commands that do not modify the address book, such as list, will usually not call Model#commitAddressBook(), Model#undoAddressBook() or Model#redoAddressBook(). Thus, the addressBookStateList remains unchanged.

UndoRedoState4

Step 6. The user executes clear, which calls Model#commitAddressBook(). Since the currentStatePointer is not pointing at the end of the addressBookStateList, all address book states after the currentStatePointer will be purged. We designed it this way because it no longer makes sense to redo the add n/David …​ command. This is the behavior that most modern desktop applications follow.

UndoRedoState5

The following activity diagram summarizes what happens when a user executes a new command:

CommitActivityDiagram

3.2.2. Design Considerations

Aspect: How undo & redo executes
  • Alternative 1 (current choice): Saves the entire address book.

    • Pros: Easy to implement.

    • Cons: May have performance issues in terms of memory usage.

  • Alternative 2: Individual command knows how to undo/redo by itself.

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

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

Aspect: Data structure to support the undo/redo commands
  • Alternative 1 (current choice): Use a list to store the history of address book states.

    • Pros: Easy for new Computer Science student undergraduates to understand, who are likely to be the new incoming developers of our project.

    • Cons: Logic is duplicated twice. For example, when a new command is executed, we must remember to update both HistoryManager and VersionedAddressBook.

  • Alternative 2: Use HistoryManager for undo/redo

    • Pros: We do not need to maintain a separate list, and just reuse what is already in the codebase.

    • Cons: Requires dealing with commands that have already been undone: We must remember to skip these commands. Violates Single Responsibility Principle and Separation of Concerns as HistoryManager now needs to do two different things.

3.3. Priority Mode

3.3.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 implements 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. It prevents the user from doing any task that are not relevant to the task list, such as adding a new event or switching the pane. This is currently implemented by having a boolean to check if the application is in focus mode. (Refer to )

There are two way to trigger the 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 using the above three methods, the ScheduledPriorityMode also uses the following method:

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

3.3.2. Example run of code

In the following section, we will be showing a run of the priority mode and a broad overview of the mechanism at each step. In particular, we will be showing how the ScheduledPriorityMode works as it has a more complicated implementation than the normal PriorityMode.

  1. The user opens his ELISA software. The first screen that he observes will be the task screen which contains all the task of the user based on the time they were added into the list.

  2. The user types priority 30.min.later into the command box of ELISA and hits enter. The incomplete items are added to a PriorityQueue<Item> where they are ranked by their priority and if they have the same priority, the item that is added to ELISA first will have a higher ranking.

  3. Once all the items are added into the PriorityQueue<Item>, 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 will carry on until there is no more undone task left to do in the priority queue. This is shown in the activity diagram below.

PriorityModeActivityDiagram
Figure 9. 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.3.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 be going through step by step the internal mechanism of the execution of the ScheduledPriorityCommand.

PriorityMode
Figure 10. Sequence diagram for priority mode

Step 1. When the user types in the command, the LogicManager takes in the command as a string and pass it to the AddressBookParser

Step 2. The AddressBookParser parses the string and determine whether the command is that of a normal PriorityCommand or a ScheduledPriorityCommand.

In this case, the command is that of a ScheduledPriorityCommand and so a new ScheduledPriorityCommand is created. This ScheduledPriorityCommand is passed back to the LogicManager.

ℹ️
The following steps (except those marked with a *) are also applicable to PriorityCommand.

Step 3. Within the LogicManager, the ScheduledPriorityCommand#execute() method is called and the command is executed.

Step 4*. 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).

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

Step 6. This creates a new TaskList which will be the visualization list for the Task Panel throughout the entire priority mode period.

Step 7. 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.
PriorityMode2
Figure 11. Sequence diagram for the scheduled turning off of priority mode

Step 8. 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.

Step 9. The TimerTask will call ItemModelManager#toggleOffPriorityMode() which will cancel the Timer and destroy the Timer. This is to ensure that the program can be closed properly.

Step 10. The items are all added back into the TaskList and the priority mode is considered deactivated.

3.3.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.

This implementation requires the manipulation of the LogicManager to change the parser and require it to observe the ItemModelManager for changes. There might also be more difficulty when maintaining the code as there is a need to maintain 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: Having two different classes for activating the priority mode, a normal PriorityCommand and a ScheduledPriorityCommand that extends from the PriorityCommand. The timer will be activated in the ScheduledPriorityCommand.

Pros Cons

Adheres to the SLAP principle with each class having it’s own implementation of the Command#execute(ItemModel). This makes it easier to maintain the code and prevents from overloading the ItemModelManager by keeping the timer there.

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): Having a timer within the ItemModelManager and having a specific method within the ItemModelManager to handle this creation of the timer.

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 takes priority over the maintainability of the code and should be used until a better method can be created.

3.3.5. Possible extension

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

3.4. 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.4.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 12. 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.4.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 13. 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 14. 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.4.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.5. 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.5.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 15. 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 16. Class Diagram of classes involved in AutoReschedule function

3.5.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 3. …​ {work in progress}

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.4, “Add Task/Event feature”. However, there are some minor differences due to the presence of -auto which should be noted.

AutoRescheduleSequence 1
Figure 17. 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 18. 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.5.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.6. [Proposed] Data Encryption

{Explain here how the data encryption feature will be implemented}

3.7. 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.8, “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.8. 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: 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 005: 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 006: 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 007: 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 persons 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 a set of sample contacts. 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.

{ more test cases …​ }

G.2. Deleting a person

  1. Deleting a person while all persons are listed

    1. Prerequisites: List all persons using the list command. Multiple persons in the list.

    2. Test case: delete 1
      Expected: First contact is deleted from the list. Details of the deleted contact shown in the status message. Timestamp in the status bar is updated.

    3. Test case: delete 0
      Expected: No person is deleted. Error details shown in the status message. Status bar remains the same.

    4. Other incorrect delete commands to try: delete, delete x (where x is larger than the list size) {give more}
      Expected: Similar to previous.

{ more test cases …​ }

G.3. Saving data

  1. Dealing with missing/corrupted data files

    1. {explain how to simulate a missing/corrupted file and the expected behavior}

{ more test cases …​ }