By: AY1920S1-CS2103T-T10-3
Since: Sep 2019
Licence: MIT
Refer to the guide here.
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.
|
-
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.
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.
The Sequence Diagram below shows how the components interact with each other for the scenario where the user issues the command delete 1
.
The sections below give more details of each 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.
API :
Logic.java
-
Logic
uses theElisaParser
class to parse the user command. -
This results in a
Command
object which is executed by theLogicManager
. -
The command execution can affect the
ItemModel
(e.g. adding a person). -
The result of the command execution is encapsulated as a
CommandResult
object which is passed back to theUi
. -
In addition, the
CommandResult
object can also instruct theUi
to perform certain actions, such as displaying help to the user. -
More instructions for the
Ui
can be given through implementingScrollCommand
Given below is the Sequence Diagram for interactions within the Logic
component for the execute("delete 1")
API call.
ℹ️
|
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.
|
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. |
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.
This section describes some noteworthy details on how certain features are implemented.
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.
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.
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.
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.
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
.
ℹ️
|
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.
ℹ️
|
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:
ℹ️
|
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.
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.
The following activity diagram summarizes what happens when a user executes a new command:
-
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.
-
-
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
andVersionedAddressBook
.
-
-
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.
-
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
and the following are the methods it implements within the ItemModelManager
:ItemModelManager
-
- Toggle the priority mode depending on whether it is on or off.ItemModelManager#togglePriorityMode()
-
- Helper function to toggle on the priority mode.ItemModelManager#toggleOnPriorityMode()
-
- Helper function to toggle off the priority mode.ItemModelManager#toggleOffPriorityMode()
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
also uses the following method:ScheduledPriorityMode
-
- Starts a timer to turn off the priority mode.ItemModelManager#startTimer(LocalDateTime)
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
works as it has a more complicated implementation than the normal ScheduledPriorityMode
.PriorityMode
-
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.
-
The user types
into the command box of ELISA and hits enter. The incomplete items are added to apriority 30.min.later
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.PriorityQueue<Item>
-
Once all the items are added into the
, ELISA will peek the first task from the queue and present it to the user.PriorityQueue<Item>
-
The user can type
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.done 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.
The figure below shows the sequence diagram on what happens from a simple execution of the
command. We will be going through step by step the internal mechanism of the execution of the priority 30.min.later
.ScheduledPriorityCommand
Step 1. When the user types in the command, the
takes in the command as a string and pass it to the LogicManager
AddressBookParser
Step 2. The
parses the string and determine whether the command is that of a normal AddressBookParser
or a PriorityCommand
.ScheduledPriorityCommand
In this case, the command is that of a
and so a new ScheduledPriorityCommand
is created. This ScheduledPriorityCommand
is passed back to the ScheduledPriorityCommand
.LogicManager
ℹ️
|
The following steps (except those marked with a *) are also applicable to .
|
Step 3. Within the
, the LogicManager
method is called and the command is executed.ScheduledPriorityCommand#execute()
Step 4*. The
calls the ScheduledPriorityCommand
which creates a new ItemModel#scheduleOffPriorityMethod()
object and a new Timer
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).TimerTask
Step 5. The
then calls SchedulePriorityCommand
which calls the private method ItemModel#togglePriorityMode()
(since the current state of the priority mode is false).ItemModel#toggleOnPriorityMode()
Step 6. This creates a new
which will be the visualization list for the Task Panel throughout the entire priority mode period.TaskList
Step 7. A
is passed to the CommandResult
and then back to the ScheduledPriorityCommand
to be passed into the LogicManager
, informing the user that the priority mode is activate.Ui
ℹ️
|
A normal will end at this point and will only be deactivated by the user’s input of again.
|
Step 8. As the
within the Timer
is still running on a separate thread, it will trigger the ItemModelManager
when the user defined time is reached.TimerTask#run()
Step 9. The
will call TimerTask
which will cancel the ItemModelManager#toggleOffPriorityMode()
and destroy the Timer
. This is to ensure that the program can be closed properly.Timer
Step 10. The items are all added back into the
and the priority mode is considered deactivated.TaskList
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 |
This implementation is not scalable as each new |
-
Alternative 2 (Current implementation): Create a new
that extends from the currentFocusElisaParser
but prevent the parsing of commands that are not allowed in focus mode.ElisaParser
Pros | Cons |
---|---|
This implementation stops the creation of the |
This implementation requires the manipulation of the |
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
method instead of having an if-else loop in all the command that are banned.Parser#parse()
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
and aPriorityCommand
that extends from theScheduledPriorityCommand
. The timer will be activated in thePriorityCommand
.ScheduledPriorityCommand
Pros | Cons |
---|---|
Adheres to the SLAP principle with each class having it’s own implementation of the |
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
and having a specific method within theItemModelManager
to handle this creation of the timer.ItemModelManager
Pros | Cons |
---|---|
The timer can be referenced from the |
This implementation will clutter the |
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.
Task, Events and Reminders are all Items and can be added using the same command. Adding of Items is facilitated by ItemModel#add(Item).
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:
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.
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:
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:
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").
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 |
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.
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).
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:
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:
-
When the event is created, as shown in the diagram above.
-
While the app is running, the Event’s start time will be continuously updated when it has passed.
This is done usingTimer
andTimerTask
, usingTimer#scheduleAtFixedRate()
. -
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:
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.
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:
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
.
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. |
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 usingLogsCenter.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
Refer to the guide here.
Refer to the guide here.
Refer to the guide here.
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
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}
(For all use cases below, the System is ELISA
and the Actor is the user
, unless specified otherwise)
MSS
-
User enters the command to show the task list.
-
ELISA shows the task list to the user.
-
User marks the task as done by using the index of the task.
-
ELISA updates the task list.
-
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.
-
MSS
-
User creates a new task with a description.
-
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
MSS
-
User enters the command to show the task list.
-
ELISA shows the task list.
-
User request to delete a task based on its index.
-
ELISA deletes the task from the task list.
-
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.
-
MSS
-
User enters the command to show the reminder list.
-
ELISA shows the reminder list.
-
User enters command to sort reminders by date and time.
-
ELISA shows the updated list of reminders sorted by date and time.
MSS
-
User enters the command to show the task list.
-
ELISA shows the reminder list.
-
User enters command to find all matching tasks with the given search term(s)
-
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.
-
MSS
-
User enters the undo command.
-
ELISA reverts the last executed command.
-
ELISA displays a confirmation message.
Extensions
-
2a. There are no commands to be undone
-
2a1. ELISA displays an error message.
Use case ends.
-
MSS
-
User enters the command to enter priority mode.
-
ELISA hides all tasks except the one with the highest priority.
-
User enters command to set that task as done once they finish it.
-
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}
-
Should work on any mainstream OS as long as it has Java
11
or above installed. -
Should be able to hold up to 1000 persons without a noticeable sluggishness in performance for typical usage.
-
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}
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. |
-
Initial launch
-
Download the jar file and copy into an empty folder
-
Double-click the jar file
Expected: Shows the GUI with a set of sample contacts. The window size may not be optimum.
-
-
Saving window preferences
-
Resize the window to an optimum size. Move the window to a different location. Close the window.
-
Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
-
{ more test cases … }
-
Deleting a person while all persons are listed
-
Prerequisites: List all persons using the
list
command. Multiple persons in the list. -
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. -
Test case:
delete 0
Expected: No person is deleted. Error details shown in the status message. Status bar remains the same. -
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 … }