By: Team CS2103T-W16-1      Since: Mar 2020

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:

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

LogicClassDiagram2
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, PomodoroDisplay, StatisticsDisplay, PetDisplay 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

LogicClassDiagram2
Figure 5. Structure of the Logic Component

API : Logic.java

  1. Logic uses the TaskListParser 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 Model (e.g. adding a task).

  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 or highlighting the text input field with a certain color.

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

DeleteSequenceDiagram
Figure 6. Interactions Inside the Logic Component for the delete 1, 2 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 Task List, Pet, Pomodoro and statistics data.

  • exposes an unmodifiable ObservableList<Task> that can be 'observed' e.g. the UI can be bound to this list so that the UI automatically updates when the data in the list change.

  • does not depend on any of the other three components.

As a more OOP model, we can store a Tag list in Address Book, which Person can reference. This would allow Address Book to only require one Tag object per unique Tag, instead of each Person needing their own Tag object. An example of how such a model may look like is given below.

BetterModelClassDiagram

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 Task List data in json format and read it back.

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

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

  • can save the Statistics 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. TaskList

Shown below is a high level overview of task class and related classes. This is represented in a class diagram.

TaskClassDiagram
Figure 9. Task Class Diagram with all aforementioned attributes including recurring and reminder

3.1.1. Add

Implementation

The Add feature allows the user to add a Task. Its only compulsory field is Name. Description, Priority, Reminder, Recurring and Tag are optional fields.

Default Priority of 'low' is assigned if it is not specified.
The user can specify multiple `Tag`s.

The mechanism of how SwitchTabCommand updates the Ui is described below through an example usage.

Step 1. The user executes add n/Homework 1 des/Read up on Semaphotes p/3 to add a new Task. LogicManager calls execute on this inputs.

Step 2. TaskListParser creates an AddCommandParser to parse this input. AddCommandParser creates the relevant objects for the fields specified in input. Based on the input, it creates a Task with its assigned Name, Priority and Description.

Step 3. AddCommandParser returns a new AddCommand with the newly created Task as its only argument to LogicManager.

Step 4. AddCommand executes. It checks if the TaskList contains a duplicate Task to it through Model#hasTask. If a duplicate Task exists, a CommandException is thrown. If not, it adds the new Task into the Tasklist through Model#addTask.

Step 5. AddCommand creates and return the resulting CommandResult to the Ui.

The following sequence diagram shows how the AddCommand is executed.

AddSequenceDiagram
Figure 10. Add Command Sequence Diagram

The following activity diagram summarises what happens when the AddCommand is executed.

AddCommandActivityDiagram
Figure 11. Add Command Activity Diagram

3.1.2. Edit

The edit feature allows the user to edit the task, adding or updating fields in a task accordingly.

Implementation

The edit command is done in 2 parts. EditCommandParser as well as EditCommand itself.

EditCommandParser parses the user input including the index and the relevant prefixes that will be edited. This is done by checking the prefixes for each of the different task fields and calling the relevant parser for it. The parser then returns the relevant field, be it name, priority, reminder etc and this is set in the EditTaskDescriptor instance. This EditTaskDescriptor instance is a container for the updated fields. This instance is passed in the constructor of a new EditCommand.

EditCommand is executed. During execution, an edited task is created from retrieving the stored updated fields data from EditTaskDescriptor and copying the field from the original task to edit for the unchanged fields. This updated task is set in the Model for storage. Subsequently, a new CommandResult is generated to display that the task has been edited in the result display to the user. The general flow of EditCommand and EditCommandParser can be seen in the sequence diagram below.

EditSequenceDiagram
Figure 12. Sequence of executing an edit command

3.2. Sort

The sort order is not maintained after the application closes

3.2.1. Implementation

SortSequenceDiagram
Figure 13. Sequence of executing a sort command

The sort command takes in a list of fields and generates FieldComparators as seen in the diagram and then uses Comparator.thenComparing to aggregate the comparators. The first field provided will be of the highest sort order. The Model will then set the aggregated comparator on the TaskList.

SortedListClassDiagram
Figure 14. Class diagram of SortedList

We use a new SortedList from JavaFx within TaskList because FilteredList does not allow for sorting. As such we have the FilteredList reference the SortedList and the SortedList refernce the UniqueTaskList. By warpping the lists around another, this allows the SortedList and FilteredList to read changes to the UniqueTaskList and perform the appropriate filtering and sorting.

SortInitliazeDiagram
Figure 15. Sequence of initializing the Sorted List

Due to the requirements mentioned, this is how we generate our FilteredList. We set FilteredList to reference the SortedList and then the SortedList to reference the UniqueTaskList.

3.2.2. Updating UI

SortUiSequenceDiagram
Figure 16. Sequence of how sort updates the UI

Meanwhile to update the UI on the newest sorting order, the latest sortOrder is set on the TaskList. The LogicManager is then able to access the sort order from the TaskList throgh the Model and provide the MainWindow with the sort order. The MainWindow then sets it on the TaskListPanel.

3.3. AutoComplete

Auto complete is triggered when users press tab while focussed on the command line.

3.3.1. Implementation

ACSequenceDiagram
Figure 17. AutoComplete Sequence Diagram

When a user presses tab on the command line, a key event handler in the CommandBox calls the suggestCommand function of MainWindow with the user input. The MainWindow then passes the user input through the LogicManager to the CommandCompletor.

The input is pass through the LogicManager so that we can get TaskList details from the LogicManager and transfer it to the CommandCompletor (e.g. taskList length). The CommandCompletor then parses the input and returns one of three things which lead to different changes to the UI:

  1. CompletorResult

    1. Will cause CommandBox to setSuccess on CommandTextField

  2. CompletorDeletionResult [inherits from CompletorResult]

    1. Contains deleted input which will be shown as feedback

    2. Will cause MainWindow to call setWarning on ResultDisplay

  3. CompletorException

    1. Will cause CommandBox to setFailure on CommandTextField

3.3.2. Auto Complete Overview

ACActivityDiagram
Figure 18. Activity diagram of auto complete

Auto completion of a word happens when either:

  1. the input matches the start of a target word

  2. the edit distance between the input and the target < 2.

The above diagram provides a big picture overview of decisions CommandCompletor goes through when processing user input.

  1. It attempts to complete the command word as in the callout above

    1. if command word is unrecognized, CommandCompletor throws a CompletorException which leads to Unknown Command UI

    2. else it performs argument checks and auto completes as necessary

Argument checks overview
  1. If the input is an add/edit/pom command then CommandCompletor will attempt to add prefixes.

    1. add/edit command → add priority and reminder prefixes

      1. Edit auto complete will only add prefixes after the second word to avoid adding a prefix to the compulsory INDEX field of edit commands

    2. pom command → add timer prefix

  2. If input is a delete/done command

    1. remove any invalid indices that are greater than the length of the displayed task list or that are not a positive integer

  3. If input is a sort command

    1. Auto completion of fields is performed based on the criteria

    2. If the field is not recongized, then it is removed

3.3.3. Auto Complete output:

As seen from the activity diagram above:

  1. Known Command UI is displayed when:

    1. Any kind of completion has happened or nothing has changed for the input

      1. CompletorResult is returned

    2. Any input is deleted (invalid index or sort field)

      1. CompletorDeletionResult is returned

  2. Unknown Command UI is displayed when:

    1. Command word provided is not recognized

      1. CompletorException is raised

3.3.4. Known Command UI

ACsuccess
Figure 19. AutoComplete Success UI
  • CommandTextField is set to green

  • CommandTextField text is replaced by the suggested command

  • Feedback is also provided on what changes have been made

    • If input has been removed, ResultDisplay is set to orange

3.3.5. Unknown Command UI

ACfailure
Figure 20. AutoComplete Failure UI
  • CommandTextField is set to red

  • CommandTextField text is unchanged

  • Feedback is provided that command word is not recognized

3.3.6. Prefix Completion

ACPrefixActivityDiagram

Here we take a closer look at how prefix completion is implemented. We iterate through every word of the user’s input and then check if the word is a valid task field. If it is, we append the prefix and update the hasPrefix boolean to true so that we don’t append duplicate prefixes. The input is then updated and we continue iterating.

3.3.7. Index Completion

ACIndexActivityDiagram

Similar to before, we iterate through the arguments and we remove indexes that are either out of the displayed TaskList size or that is not a positive integer. We then append it to a removed list so that we can inform the user what input has been removed.

3.3.8. Sort field Completion

Sort field completion is done by iterating through all arguments word by word and performing the auto complete checks against all possible sort fields. The auto complete checks were the same as the above criteria.

3.4. Enhanced Find

We’ve built upon the existing find function in AB-3 to filter tasks based on phrases (with some degree of typing errors) and based on task tags.

The filtered list is not maintained after the application closes

3.4.1. Implementation

FindSequenceDiagram
Figure 21. Find Command Sequence diagram
  • After setting the predicate on the model and FilteredList, the FilteredList will apply the Test method of the predicate.

    • The test method calculates a score for every task and only displays tasks with score < 2.

  • A comparator is then retrived from the Predicate by comparing Tasks based on their score and is used to sort the filtered list to show the more relevant searches first

    • Lower scores means a more relevant task to the search term.

    • Tasks with lower scores will preceed those with higher scores based on the comparator.

Any existing comparator set by previous sort commands is replaced by the find command’s relevance comparator.

3.4.2. Predicate

Scoring decision

The score is first initialized to 2 and is later replaced by name score if the name score is lower than 2. We then subtract tag score from it to get the final score.

PredicateSequenceDiagram
Figure 22. Overview of predicate sequence
Name scoring

Please refer to the above’s name score group

  • The name score of a task is the minimum score of all chunks of a task.

    • A chunk is a String subsequence of the task name that has the same number of words as the search term.

  • We iterate through all chunks of the task name and calculate a score for each chunk.

  • Here is how we set the score for each chunk:

    • edit distance between one of the chunks and the search term < 2, chunk score is set to 1.

    • search term matches the start of one of the chunks, chunk score is set to 1.

    • one of the chunks is the same as the search term, chunk score is set to 0.

    • else chunk score is 2.

  • We then get the minimum of these chunk scores.

PredicateNameSequenceDiagram
Figure 23. Name scoring in predicate
Tag scoring

For every tag in the search term that appears in a Task, we increment the tag score by 1.

PredicateTagSequenceDiagram
Figure 24. Tag scoring in predicate
Final score

final score = name score - tag score. Search results are displayed in ascending order of final score.

Design considerations
  1. The idea is to first ensure that tasks that are too different are not shown while allowing some degree of typo error on the user’s end when searching for a task.

    1. This is supported by the use of edit distance and a small threshold.

  2. Next we also wanted the user to be able to find a task name without searching the full name.

    1. We show tasks who have a chunk who’s start matches the search term.

  3. We also wanted to allow users to search by tags.

    1. Thus tag score is introduced.

  4. While the score helps to determine which tasks to show, it serves another job in providing the search relevance so that while accommodating for some degree of error from user input, they are still seeing what’s more relevant first.

    1. Users can also narrow their search by performing find with more tags or a more complete task name so that only that task has a chunk that matches.

  5. We chose to not use edit distance for search terms of string length less than 3 as this would bring about alot of false positives given that that the edit distance between words of length < 3 will easily be 1.

3.5. Pomodoro

Pomodoro is activated by the pom command. It follows the same execution flow as many of the other commands in BBProductive.

PomSequenceDiagram
Figure 25. Interactions Inside Logic Component for the pom 1 command

3.5.1. Implementation

Pomosoero’s features are implemented mainly in seedu.address.logic package. The PomodoroManager class is used to maniulate the timer and configure the relevant UI elements. The timer is facilitated by javafx.animation.Timeline.

When the PomCommand is executed, the PomodoroManager will handle the actual timer systems and update the relevant entities in the app. This is evident in the following sequence diagram.

PomExtendedSequenceDiagram
Figure 26. Interactions with PomodoroManager through a time cycle

Through the use of the Pomodoro feature, there are occasions where the app has to prompt the user for specific input in order to progress. This behaviour flow is represented in the Pomodoro Acctivity diagram.

PomodoroActivityDiagram
Figure 27. Pomodoro Activity Diagram

The PomodoroManager maintains a prompt_state indicating what the app might be prompting the user at a given time.

Pomodoro Prompt States

  • NONE: There is no particular prompt happening. The default state when the app is in the neutral state. (i.e. No pomodoro running.)

  • CHECK_DONE: This state occurs when a timer expires during a Pomodoro cycle.

  • CHECK_TAKE_BREAK: This state occurs after user response has been received in the CHECK_DONE state.

  • CHECK_DONE_MIDPOM: This state occurs when the user calls done on a task that is the Pomodoro running task.

Pomodoro has settings that can be configured by the user:

  • Pomodoro Time: This defines how long the Pomodoro work period is. The default is 25 minutes.

  • Break Time: This defines how long the breaks last in between Pomodoro periods. The default is 5 minutes.

This data is captured and stored in the Pomodoro class in seedu.address.model, which interacts with the app’s storage system. PomodoroManager also updates the Pomodoro model on what task is being run and the time remaining in a particular cycle. This allows the time progress to be persistent in between app closures and relaunches. === Reminders The user’s reminder functionality is achieved by calculating the time delay from the current time and the time from the user input. This time delay as well as the Task name and description is passed to the MainWindow for the reminder to be triggered as a pop up at the right time.

3.5.2. Implementation

A DateTimeFormatter is used to parse the date time from the user input, which is just the date in the r/ flag when adding or editing a task, into a LocalDateTime object. This LocalDateTime is used to store the date and time information. When the reminder is instantiated, a setDelay method is called setting in motion the calculation of time delay between the current time and the reminder time, and triggering of reminder on the MainWindow. The reminder class is stored as an Optional in the Task class itself.

Reminder is stored as a string in the JsonAdaptedTask. This string contains the exact format of the date and time that the user inputs, this allows the same constructor to be used when the data is read and changed to a task and thus reminder object. A sequence diagram of the reminder flow is shown below for reference.

ReminderSequenceDiagram
Figure 28. Reminder Sequence Diagram

3.6. Recurring

The user’s recurring tasks functionality is twofold. Resetting the task to be unfinished after the stipulated time interval and resetting the task’s reminder date according to the stipulated time interval. The behaviour for this recurring feature is mainly represented in the activity diagram below.

RecurringActivityDiagram
Figure 29. Recurring Activity Diagram

3.6.1. Implementation

The logic is mainly implemented in the Recurring class and ModelManager class in seedu.address.model, which interacts with the app’s storage system especially with respect to task storage. This Recurring instance is stored in Task as an optional field.

In the Recurring class, whenever a task is added or edited, the recurring type is then parsed to be either daily or weekly. Afterward, based on the time the recurring attribute is added, a reference LocalDateTime is noted in the Recurring instance itself. This ensures that the first recurring behaviour will trigger in the given interval with respect to that referenceDateTime and following the same interval afterwards.

The recurring behaviour is orchestrated in ModelManager whenever a task is added or edited, a setTask method is called that will generate a Timer and TimerTask. A TimerTask is the logic run to update the task, namely resetting the done and the reminder accordingly. The Timer schedules TimerTasks at a fixed rate based on the the time interval chosen, if it is daily it will be every 24 hours (but for testing purposes it will be every 60 seconds) and if it is weekly it will be every 7 days. There is only 1 Timer for the ModelManager that handles the scheduling of each TimerTask that corresponds to every task that has a recurring behaviour. On boot the Timer is canceled and replaced with a new instance, subsequently all the tasks are iterated through. Every task with a recurring attribute will have a TimerTask generated and scheduled accordingly.

The recurring behaviour triggered will set the task as undone. If a reminder exists and has been triggered, it will increment the reminder to be the next day or week depending on the interval set. When the recurring behaviour is triggered, the result display will show a message that the recurring task has been reset.

Additionally, a flag has been made to check if the task needs to be changed, if it does not it will not be unnecessarily updated in the Model. A class diagram of the tasks and all its attributes is shown below.

Recurring is stored as a string in the JsonAdaptedTask. This string contains the LocalDateTime information for the reference date as well as the type of interval itself. A special constructor for this string is used to reconstruct the recurring attribute when reading from storage.

3.7. Switch Tab Feature

The Switch tab feature allows the user to traverse between the Tasks, Statistics and Settings tabs.

The user can switch tabs through 2 main methods: 1. User calls a valid SwitchTabCommand that displays the appropriate tab defined. 2. User calls a valid command that changes the display of Tab B while he or she is on Tab A. In this scenario, Tab B will display automatically.

This behaviour is represented in the following activity diagram.

SwitchTabActivityDiagram
Figure 30. Activity Diagram of Tab Switches

The mechanism of how SwitchTabCommand updates the Ui is described below.

Step 1. MainWindow executes the user input through logic and retrieves the SwitchTabCommandResult commandResult from Logic.

Step 2. MainWindow retrieves the tabToSwitchIndex from commandResult.

Step 3. MainWindow updates the tabToSwitchIndex tab through tabPanePlaceholder.

The following sequence diagram shows how SwitchTabCommand updates the tab in the Ui.

SwitchTabSequenceDiagram
Figure 31. Sequence Diagram of SwitchTabCommand

3.8. Statistics Feature

The Statistics feature allows the user to view information about their number of tasks completed and Pomodoro duration ran (in minutes) on a daily basis for the past CONSTANT_SIZE days.

CONSTANT_SIZE can be set to any number for any future developments. In our current implementation, we chose to store data for only the past 7 days to keep Statistics simple and intuitive for users.

3.8.1. Implementation

The Statistics feature is mainly supported by the Statistics class, which in turn is facilitated by the CustomQueue class. Its class diagram is given below.

StatisticsClassDiagram
Figure 32. Class Diagram of the Statistics Component

The CustomQueue class enforces the following constraints:

  1. Size of CustomQueue must be of CONSTANT_SIZE after each method call through Statistics.

  2. DayData dates in CustomQueue must be only 1 day apart between its elements, and sorted from oldest to latest date.

The CustomQueue class implements the following methods for other components to access or update its data:

  • Model#updateDataDatesStatistics - Updates data to current day while retaining stored data.

  • Model#updatesDayDataStatistics - Replaces existing DayData in Statistics with new DayData of the same date.

  • Model#getDayDataFromDateStatistics - Returns the DayData object from Statistics with the specified date.

The Statistics feature does not support any explicit commands. Instead, Ui is updated and displayed when the SwitchTabCommand 'stats' is called. The mechanism of this behaviour is described below.

Step 1. MainWindow receives the SwitchTabCommandResult commandResult from Logic.

Step 2. MainWindow calls StatisticsManager#updateStatisticsDisplayValues() which retrieve the latest Statistics from Model and generates the display information.

Step 3. MainWindow then retrieves these display information from StatisticsManager and sets this information in StatisticsDisplay.

SwitchTabCommand also switches the focused tab to the Statistics tab to display the results to the user.

The following sequence diagram shows how the Statistics is updated to the display.

StatisticsUiSequenceDiagram
Figure 33. Sequence Diagram of how Statistics

3.8.2. Design considerations

Aspect: Data structure to support Statistics
  • Alternative 1 (current choice): Use a list that stores a fixed number of DayData objects, with elements being strictly 1 day apart and sorted from oldest to latest date.

    • Pros: Lightweight, does not store unnecessary data. Easy to pass data to generate graphs. Systematic removal of outdated data.

    • Cons: Need to enforce constraints in methods.

  • Alternative 2: Use a list with elements sorted from oldest to latest date.

    • Pros: Easy to implement.

    • Cons: Harder to pass data to generate graphs. Need to handle outdated dates.

Aspect: when to update StatisticsDisplay
  • Alternative 1 (current choice): Update when the user runs the command to view Statistics

    • Pros: Easy to implement.

    • Cons: Progress can only be viewed at the Statistics tab.

  • Alternative 2: Update when any changes are made to Statistics.

    • Pros: In the event of future developments, any component of Statistics can be displayed at all times.

    • Cons: Need to keep track of all instances that can modify Statistics' values.

3.9. Pet

3.9.1. Implementation

The pet feature aims to provide a virtual pet for the app in order to motivate the user. The pet has three main components: the XP points, the evolution and the mood. To facilitate this function, a Pet class is created to represent the pet. A PetManager class is created to manage the pet via communications from MainWindow. Lastly, a PetDisplay class is created to handle the UI of the pet.

PetClassDiagram
Figure 34. Pet Class Diagram

To exemplify the implementation for the components of the XP points and the evolution of the pet, an example usage scenario is given below.

Step 1. User finishes a task. User calls the done command for the task. MainWindow would execute this command and generate a DoneCommandResult object

DoneCommandSequenceDiagram

Step 2. The MainWindow will update PetManager to increase XP points after the DoneCommandResult Object is received. This is done by calling the method PetManager#incrementExp. PetManager would then update XP points of Pet by calling Pet#incrementExp. This method also checks whether the XP points have reached the milestones for the levels and will update the level of the pet accordingly.

PetSequenceDiagram
Figure 35. Pet Sequence Diagram

Step 3. Following the update of XP points, MainWindow also updates the mood of the pet. Supposedly, the pet is originally in "HANGRY" mood, MainWindow will call "MainWindow#updateMoodWhenDone" method to change the pet’s mood to Happy. It will also update the time of the last done task and reschedules a new timertask so that the pet will turn "Hangry" at the correct time. Lastly, this method also updates the elements

Step 4. MainWindow would then update the string of the filepaths for the respective UI elements in PetDisplay by executing the method PetManager#updateDisplayElements.

Step 5. Lastly, MainWindow will the update PetDisplay. The user will then see the UI be updated accodingly. For example, the progress bar would increase.

UpdatePetDisplaySequenceDiagram
Figure 36. update PetDisplay Diagram

3.10. Set Commands

SetClassDiagram
Figure 37. Set command class diagram

The Set Commands can be used to customise the features in BB Productive. It can be used to customised the name of the pet, the duration for pomodoro and the daily challenge target so as to better cater to the needs of the user.

Below is an example scenario when the user runs the set command.

Step 1. User runs the command "Set pet/momu pom/30 daily/150". MainWindow will take the user input and call upon LogicManager to pasrse it. LogicManager will the call AddressBookParser which in creates a SetcommandParser object and then parse the user argument. A SetCommand object is then executed and returned to logic.

SetCommandSequenceDiagram
Figure 38. Set command sequence diagram

Step 2. Logic calls upon the method SetCommand#execute which eventually calls the methods Model#SetPetName and Model#setPomodoroDefaultTime. A SetCommandResult object is return once these methods are executed.

Step 3. Upon receiving the SetCommandResult object, MainWindow then calls the method MainWindow:UpdatePetDisplay to update the UI for Pet. It also calls PomodormoManager#SetDefaultStartTime and PomdooroDisplay#setTimerText to update the Ui of pomodoro. Lastly, StatisticsManager#setDailyTarget is called to update the value of the dailyTargetText.

SetCommandUpdatingUi
Figure 39. set command updating Ui

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 significant number of tasks

  • prefer desktop apps over other types

  • can type fast

  • prefers typing over mouse input

  • is reasonably comfortable using CLI apps

  • need motivation to get things done

Value proposition: We integrate a Pomodoro-Pet environment into a full fledged task manager. The pet system serves to gamify the act of doing tasks, thereby motivating users, and the Pomodoro helps users get into a regular work/rest cycle. This integrationcovers all aspects of productivity in line platform. It covers motivation, organising of tasks and also how to go about doing them. This all in one solution is seldom found in other applications which implement maybe 1 or 2 of these features.

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…​

* * *

new user

see usage instructions

refer to instructions when I forget how to use the App

* * *

user

view all current ongoing tasks

manage my tasks and time

* * *

user

able to edit my task description

make changes in the event something unexpected happens

* * *

user

add a task by specifying a task description only

record tasks that needs to be done.

* * *

user

add a task by specifying a task description and a reminder

record tasks that needs to be done by a specific period

* * *

user

add a task that is recurring

record tasks that are either recurring daily or weekly without having to input it every day or week

* * *

user

sort upcoming tasks by date

filter out the latest/oldest tasks according to my needs

* * *

user

sort my tasks by priority

manage my tasks

* * *

user

delete a task

remove tasks that I no longer care to track

* * *

user

utilise the Pomodoro technique to break down my work into structured intervals

boost productivity and keep track of time

* * *

user

be able to remind myself on when I plan to work on a task

be on track to complete my tasks

* * *

user

get a visual cue from my pet to prompt me to do work

be motivated to work when my productivity is low

* * *

user

keep track of the time spent on each task

check my progress

* *

pro user

navigate commands using shortcuts

save more time

* *

pro user

customise the rate at which I should do work in the Pomodoro

fit my workstyle better

* * *

pro user

be able to remind myself on a recurring basis for repetitive tasks

be on track to complete my tasks, including those that are repetitive and also done on a recurring basis

* *

user

view the total number of tasks/duration spent on tasks I have done over a period of time

track my productivity over different periods

* *

user

view the durations in which I have currently spent on different tasks

better allocate my time

* *

user

see my pet grow because of my productivity

am more motivated to stay productive

*

user

be greeted by a cute mascot

feel happy and motivated to do work

Appendix C: Use Cases

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

use cases
Figure 40. Use case diagram for BBProductive

Use Case: UC01 - View tasks

MSS

  1. User requests to see the task list.

  2. BB Productive displays the view under the tasks tab.

    Use case ends.

Use Case: UC02 - Add task

MSS

  1. User requests to add a task to the task list.

  2. BB Productive shows view with updated task list.

    Use case ends.

Extensions

  • 1a. Task of the same name already exists.

    • 1a1. BBProductive shows "This task already exists in the task list" in response box.

      Use case ends.

Use Case: UC03 - Done task

MSS

  1. User requests to set a task to done.

  2. BB Productive shows view with updated task list.

    Use case ends.

Extensions

  • 1a. Task specified by user already marked as done.

    • 1a1. BBProductive shows "Task has already been marked as done!" in response box.

      Use case ends.

  • 1b. User fed in an invalid index.

    • 1b1. BBProductive shows "Invalid command format! " in response box.

      Use case ends.

  • 2a. A pommed task is among the tasks to be set to done.

    • 2a1. BBProductive prompts user if they want to pom another task, or N to return the app to neutral.

    • 2a2. If user pom another task, use case resumes at stage 2 of UC09.

      Use case ends.

Use Case: UC04 - Edit task

MSS

  1. User requests to update a task with updated fields and informs the task list.

  2. BB Productive shows view with updated task list.

    Use case ends.

Extensions

  • 1a. New task name matches that of another task.

    • 1a1. BBProductive shows "This task already exists in the task list." in response box.

      Use case ends.

  • 1b. User fed in an invalid index

    • 1b1. BBProductive shows "Invalid command format! " in response box.

      Use case ends.

Use Case: UC05 - Set a reminder for a task

MSS

  1. User requests to set a task with a Reminder.

  2. BB Productive creates/updates a task and shows the view with updated task list.

  3. A reminder pops up when the specified time has elapsed.

    Use case ends.

Extensions

  • 1a. New task name matches that of another task.

    • 1a1. BBProductive shows "This task already exists in the task list." in response box.

      Use case ends.

Use Case: UC06 - Set a task to recurring

MSS

  1. User requests to set a task to be a recurring task.

  2. BB Productive creates/updates a task and shows the view with updated task list.

  3. A reminder pops up when the specified time has elapsed.

    Use case ends.

Extensions

  • 1a. New task name matches that of another task.

    • 1a1. BBProductive shows "This task already exists in the task list." in response box.

      Use case ends.

Use Case: UC07 - Delete task

MSS

  1. User requests to list tasks.

  2. BBProductive shows a list of tasks.

  3. User requests to delete a specific person in the list.

  4. BBProductive deletes the task.

    Use case ends.

Extensions

  • 1a. New task name matches that of another task.

    • 1a1. BBProductive shows "This task already exists in the task list." in response box.

      Use case ends.

  • 1b. User fed in an invalid index.

    • 1b1. BBProductive shows "Invalid command format!" in response box.

      Use case ends.

  • 1c. Task to be deleted is being pommed.

    • 1c1. BBProductive shows "You can’t delete a task you’re pom-ming!" in response box.

      Use case ends.

Use Case: UC08 - Sort tasks

MSS

  1. User requests to list tasks.

  2. BBProductive shows a list of tasks.

  3. User requests to sort the list by one or more parameters.

  4. BBProductive creates a new view and updates the task list view.

    Use case ends.

Use Case: UC09 - Start pomodoro

MSS

  1. User requests to start pomodoro on a specific task.

  2. BBProductive starts timer and sets task-in-progress to said task.

  3. Pomodoro timer expires.

  4. BBProductive sets task-in-progress to null and prompts user if user has done the task.

  5. User replies the affirmative.

  6. BBProductive shows view with updated task list with done task. Pet adds additional points.

  7. BBProductive prompts user if user wants to do break time.

  8. User replies the affirmative.

  9. BBProductive starts break timer.

  10. Break timer expires.

  11. BBProductive returns to neutral state.

    Use case ends.

Extensions

  • 1a. User fed in an invalid index.

    • 1a1. BBProductive shows "Invalid command format! " in response box.

      Use case ends.

  • 1b. Task specified by user already marked as done.

    • 1b1. BBProductive shows "Task has already been marked as done!" in response box.

      Use case ends.

  • 5a. User replies negative.

    • 5a1. BBProductive will leave the task list as is.

      Use case resumes at stage 7.

  • 5b. User replies with answer that is neither Y/y nor N/n.

    • 5b1. BBProductive will leave the task list as is.

      Use case resumes at stage 7.

  • 8a. User replies negative.

    • 8a1. BBProductive will start no timer.

      Use case resumes at stage 11.

Use Case: UC10 - View stats

MSS

  1. User requests to see the statistics tab.

  2. BBProductive displays the view under the statistics tab.

    Use case ends.

Use Case: UC11 - View settings

MSS

  1. User requests to see the settings tab.

  2. BBProductive displays the view under the settings tab.

    Use case ends.

Use Case: UC12 - Set settings

MSS

  1. User requests to update the app’s settings.

  2. BBProductive takes the input and updates the app’s internal settings.

  3. User requests to see the settings tab.

  4. BBProductive displays the view under the settings tab with the updated preferences.

    Use case ends.

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

  4. Graphics should not be offensive to any culture in any way.

  5. Product should be fully functional with CLI alone.

  6. Storage should be done in a human readable and editable format.

  7. Commands should be user-friendly.

Appendix E: Glossary

Term Detail

Mainstream OS

Windows, Linux, Unix, OS-X

Pomodoro

A time management method developed by Francesco Cirillo. Traditionally, cycles of 25 minutes of work and 5 minutes of rest.

Task

A snippet of text specified by the user that can be tracked (done/time spent).

Pet

A cute little companion whom the player can care for and accessorise with more tasks being done.

CLI

Command Line Interface - a typing interface which is used to interact with the application

Command

Executes user input in the application

CommandBox

UI component that takes in user input

ResultDisplay

UI component that displays the feedback to the user

FXML

XML-based user interface markup language for defining user interface of a JaxaFX application

TaskListCard

UI component that displays information on an item

TaskListPanel

UI component that displays list of items

JavaFX

Software platform for creating and delivering desktop applications and rich Internet applications

JSON

An open-standard file format that uses human-readable text to transmit data objects consisting of attribute–value pairs and array data types

Logic

Handles user input for the application and returns the application’s output

MainWindow

Provides the basic application layout containing a pet and CLI sidebar and a task list interface with pomodoro timer

Model

Represents and exposes data in the task list, pet, pomodoro and statistics

Parser

Converts user input into a Command object

ReadOnlyTaskList

Provides an unmodifiable view of a task list

Storage

Manages data of the pet, pomodoro, tasklist and statistics in local storage

Edit distance

Integer calculated with the levenshtein distance that represents the number of changes to get from one string to another

Appendix F: 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.

F.1. Launch and Shutdown

  1. Initial launch

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

    2. In the home folder for BBproductive, launch the jar file by double clicking on the jar file itself.
      Expected: Shows the GUI with a set of sample items. The window size may not be optimum.

  2. Saving user preferences

    1. Add or edit tasks accordingly

    2. Re-launch the app by double clicking the jar file.
      Expected: The same GUI list of tasks appears.

{ more test cases …​ }

F.2. Viewing Relevant Screens on command

  1. On launch

    1. Upon double clicking the JAR file, a GUI with the tasks list on the right panel appears.

  2. On typing stats

    1. Type stats in the input command box if you are in either the tasks or settings panel.

      1. Expected: The right panel shows a GUI with multiple graphs.

  3. On typing settings

    1. Type settings in the input command box if you are in either the tasks or statistics panel.

      1. Expected: The right panel shows a GUI with multiple fields for the settings.

  4. On typing tasks

    1. Type tasks in the input command box if you are in either the settings or statistics panel.

      1. Expected: The right panel shows a GUI with the task list.

F.3. Adding a task

  1. Adding from a screen with 0 tasks

    1. First run clear to clear all tasks if there are still tasks on the screen.

    2. Add a task by running the command add n/test1
      Expected: A task card appears in the tasklist with the name test1.

  2. Adding from a screen with 1 task

    1. Add another task by running the command add n/test2
      Expected: A task card appears in the tasklist with the name test2.

F.4. Editing a task

+ Prerequisite : Run clear and add a task using the command add n/editTest

  1. Editing a task’s name

    1. Run the command edit 1 n/editedTest.
      Expected: The command will result in the first task card’s name to change from editTest to editedTest.

  2. Editing a task’s description

    1. Run the command edit 1 des/testDescription.
      Expected: The command will result in the testDescription being the description of the task card.

  3. Editing a task’s priority

    1. Run the command edit 1 p/2.
      Expected: The command will result in the priority to change from low to medium on the task card.

  4. Editing a task’s tags

    1. Run the command edit 1 t/test.
      Expected: The command will result in the test tag to appear below the task name on the task card.

F.5. Adding and triggering a reminder for the task

  1. Adding a task with a reminder.
    Prerequisite: Take note of the current time plus 1 minute and date in the format DD/MM/YY@HH:mm, for example if the current time is 15/03/20@15:47 then you should get the command ready 15/03/20@15:48 (but use the current date and time instead)

    1. Run the command add n/reminderTest des/test r/DD/MM/YY@HH:mm
      Expected: When the time has arrived a a pop up with a title reminderTest and description test appears.

  2. Editing a task to have a reminder.
    Prerequisite: Take note of the current time plus 1 minute and date in the format DD/MM/YY@HH:mm, for example if the current time is 15/03/20@15:47 then you should get the command ready 15/03/20@15:48 (but use the current date and time instead)

    1. Add a task add n/editReminderTest des/test first and see it added on the tasklist panel

    2. Take note of the index of that task

    3. Edit the task with edit <index> r/DD/MM/YY@HH:mm
      Expected: The task displays the reminder date in the task card. When the time comes, a pop up with a title editReminderTest and description test appears.

F.6. Adding a recurring attribute to a task

  1. Adding a task with a recurring attribute.

    1. Run the command add n/recurTest rec/t

    2. Take note of the index of that task.

    3. Run the done command done <index>
      Expected: For testing purposes, the time delay is set to 60 seconds and it mimics a weekly recurring task. After 60 seconds, the done is set back to unfinished, with the tick being removed from the task card.

  2. Editing a task to have a recurring attribute.

    1. Add a task add n/editRecurringTest first and see it added on the tasklist panel

    2. Take note of the index of that task

    3. Edit the task with edit <index> rec/t

    4. Run the done command done <index>
      Expected: The task is marked as done at first. After 60 seconds, the done is set back to unfinished, with the tick being removed from the task card.

  3. Adding a task with a reminder and recurring attribute.
    Prerequisite: Take note of the current time plus 1 minute and date in the format DD/MM/YY@HH:mm, for example if the current time is 15/03/20@15:47 then you should get the command ready 15/03/20@15:48 (but use the current date and time instead)

    1. Run the command add n/recurReminderTest r/DD/MM/YY@HH:mm rec/t

    2. Take note of the index of that task.

    3. Run the done command done <index>
      Expected: After 60 seconds, the done is set back to unfinished, with the tick being removed from the task card. After the reminder appears, the date displayed changes to the next week as it mimics a weekly recurring task albeit with a 60 second time delay, for example 15 March at 15:48 changes to 22 March at 15:48.

F.7. Sorting the task list

  1. Add a bunch of tasks with different priorities, reminder dates and done values

  2. Next perform sorts of various permutations of {(r-)priority, (r-)name, (r-)done, (r-)date} with spaces in between

    1. sort fields that appear first are of higher priority than those that appear less

    2. Expect the sort order of the tasklist to change, please reference our user guide for the specific changes to the tasklist if unsure

    3. also expect the UI to change to display the most recent sort order

    4. e.g. sort name priority → UI shows Tasks by name

      1. Note that sort order is not maintained after application closes

F.8. Finding a task

  1. Add a bunch of tasks with names with phrases that overlap and tags as well

  2. Next you can perform one of the three permutations

    1. find phrase

    2. find phrase [t/TAG]…​

    3. find t/TAG [t/TAG]…​

  3. Expected order of search results: [those mentioned first should appear first]

    1. tasks that have multiple tag matches

    2. tasks that have full name match and tag match

    3. tasks that have full name match or 2 tag matches

    4. tasks that match a tag or phrase is partially matched

  4. tasks that don’t meet any of the above won’t be shown

F.9. Auto complete

  1. UI changes

    1. Any known command words will have command text field set to green

    2. Any unknown command words will have command text field set to red

    3. Any input deletion or invalid indexes will have the result display set to orange

  2. Test the command words

    1. try partial start matches: fifind

    2. try typo matches: fandfind

      1. All command word partial matches should work

    3. asdfasdf

      1. [command text field set to red]

    4. try misspelled words by 1 character: fandfind

  3. Test prefix completion

    1. Add: add 20/10/20@10:30 3add r/20/10/20@10:30 p/3

    2. Edit: edit 2 20/10/20@10:30 1edit 2 r/20/10/20@10:30 p/1

      1. Ensure that the date values are valid

    3. Pom: pom 2 2.5pom 2 tm/2.5

  4. Test index checking

    1. Edit: edit -2edit -2

      1. [result display shown to user and turned orange]

      2. any non positive integer or integers outside of the displayed task list’s size will trigger the same deletion and feedback

    2. delete/done: done -2 a 1999 2done 2

      1. [result display also set to orange]

  5. Sort field completion

    1. sort: sort na prioruty blablasort name priority

      1. result display set to orange if input has been deleted

F.10. Activating Pomodoro

  1. Activating Pomodoro.

    1. Run the command pom 1

    2. Take note of the index of that task.
      Expected: Pomodoro timer will start counting down from 25:00 minutes (default). Upon expiry of the time, app will prompt user in the response bubble, asking if done or no.

  2. Activating Pomodoro with special time.

    1. Run the command pom 1 tm/0.5

    2. Take note of the index of that task
      Expected: Pomodoro timer will start counting down from 00:30 minutes. Upon expiry of the time, app will prompt user in the response bubble, asking if done or no.

  3. Pausing and Resuming Pomodoro.

    1. Run the command pom 2

    2. Then, run the command pom pause.

    3. Then, run the command pom continue.
      Expected: After the firs command, Pomodoro timer will start counting down from 25:00 minutes (default). After pom pause, the timer will pause. After pom continue, timer will resume.

{ more test cases …​ } === 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 …​ }

F.11. Switching tabs

  1. Switching tabs by using the SwitchTabCommands.

    1. Run the command stats Expected: The right screen displays the 'Statistics' tab. The 'Statistics' tab should have an orange background to indicate selection.

  2. Switching tabs by using other Commands.

    1. Run the command stats.

    2. Take note that the right screen displays the 'Statistics' tab.

    3. Run the command set daily/50. This is a SetCommand, and the right screen should automatically display the 'Settings' tab. Expected: The right screen displays the 'Statistics' tab. The 'Statistics' tab should have an orange background to indicate selection.

F.12. Checking Statistics

  1. Check done tabulation

    1. Run the command stats.

    2. Take note of the number of tasks done on the current day.

    3. Run the command clear.

    4. Run the command add n/new task.

    5. Run the command done 1.

    6. Run the command stats again. Expected: The number of tasks done on the current day should increase by 1.

  2. Check Pomodoro duration tabulation

    1. Run the command stats.

    2. Take note of the Pomodoro duration on the current day.

    3. Run the command clear.

    4. Run the command add n/new task.

    5. Run the command pom 1 tm/1. This runs the Pomodoro for 1 minute.

    6. Run the command stats again. Expected: The Pomodoro duration on the current day should increase by 1.