Developer Guide
- Introduction
- Setting Up, Getting Started
- Design
-
Implementation
- Adding Tasks to Projects
- Immutability
- Timers and Durations
- Deadlines
-
Reminders
- Organisation of Reminder Related Classes
- Alternative Implementation: Manage Reminders using
Reminder
Class - Rescheduling Reminders
- Alternative Implementation: Reschedule Reminders of Projects or Tasks Changed
- Scheduling of Reminders
- Alternative Implementation: Implement
ReminderTimerTask
as a Separate Class - Running Reminders
- Statistics
- Managing Time
- Find Command
- Settings
- Sort Command
- Undo/Redo Feature
- Documentation, logging, testing, configuration, dev-ops
-
Appendix: Requirements
- Product scope
- User stories
-
Use cases
- Use Case: Start and End a Timer
- Use Case: Add a Project
- Use Case: Dismiss a Reminder
- Use Case: Hide the Tags Panel
- Use Case: Delete a Project
- Use Case: Find a Project/Task in the List
- Use Case: View a Project’s Tasks
- Use Case: Changing Application Settings
- Use Case: Undo a Command
- Use Case: Redo a Command
- Non-Functional Requirements
- Glossary
- Appendix: Instructions for manual testing
- Apendix: Effort
Introduction
Momentum is a desktop app that helps freelancers track time spent on different projects and gain insights on how their time is spent.
It is designed for people that prefer typing, so that frequent tasks can be done faster by typing in commands.
This developer guide provides information about the architecture and implementation of Momentum. It gives developers interested in developing Momentum a good start in knowing how the application works, without going too much into the lower level details. It also provides information for testers on how to test the product.
Some things to take note of in this guide:
- When a notation like
Foo#bar
is used (e.g. “The methodFoo#bar
is called…”) it refers too thebar
method from theFoo
class. - Method references made in this document will only include arguments if relevant to what is being explained.
- The lifeline for sequence diagrams should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Setting Up, Getting Started
Refer to the guide Setting up and getting started.
Design
Architecture
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 methods where necessary.
Commons
represents a collection of classes used by multiple other components.
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 concrete
{Component Name}Manager
class (which implements the corresponding APIinterface
mentioned in the previous point.
For example, the Logic
component (see the class diagram given below) defines its API in the Logic.java
interface and exposes its functionality using the LogicManager.java
class which implements the Logic
interface.
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
when in project view.
The sections below give more details of each component.
UI Component
API :
Ui.java
The UI consists of a MainWindow
that is made up of parts e.g.CommandBox
, ResultDisplay
, TrackedItemListPanel
, BottomBar
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. - Various UI parts such as
TrackedItemCard
,TimerCard
,PieChartCard
listen for changes toModel
data so that they can be updated with the modified data. -
MainWindow
has an association toLogic
as it will call onLogic
to fetch certain data for the some of the UI parts such asStatCard
.
Logic Component
API :
Logic.java
-
Logic
uses theProjectBookParser
class to parse the user command. - This results in a
Command
object which is executed by theLogicManager
. - The command execution can affect the
Model
(e.g. adding a project). - 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.
Given below is the Sequence Diagram for interactions within the Logic
component for the execute("delete 1")
API call when in project view.
Model Component
API : Model.java
The Model
:
- Exposes an unmodifiable
ObjectProperty<ObservableList<TrackedItem>>
that stores the projects or tasks that are currently displayed to the user. - Exposes an unmodifiable
ObservableList<TrackedItems>
that stores projects or tasks 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. - Exposes an unmodifiable
ObservableList<TrackedItems>
that stores the total projects or tasks with running timers 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.
Packages in the Model
:
- The
project
package contains classes representing aProject
andTask
that can be added by a user under a project, such that a project can have a list of tasks. BothProject
andTask
extendTrackedItem
. - A
Project
can store multipleTask
objects. - The
project
package also containsUniqueItemList<TrackedItem>
which is a list of unique projects, or a list of unique tasks.
Storage Component
API : Storage.java
The Storage
component,
- can save
UserPref
objects in json format and read it back. - can save
JsonAdaptedProject
objects inJsonSerializableProjectBook
in json format and read it back.
The JsonAdaptedProject
class contains the same fields as the JsonAdaptedTask
class.
In addition to the fields in JsonAdaptedTask
component, JsonAdaptedProject
also contains a taskList in List<JsonAdaptedTask>
format, as show in the class diagram above.
Common Classes
Classes used by multiple components are in the seedu.momentum.commons
package. These classes contain methods or data used by various components and serve as a single source of such methods and data.
Notable classes in this package include:
-
Clock
: Acts as a consistent, single source of the ‘current time’ within the application -
DateWrapper
,TimeWrapper
,DateTimeWrapper
: Represents dates and times within Momentum, with utility methods to calculate the dates and times required by various parts of the application. -
UniqueItem
,UniqueItemList
: Represents a list of unique items that are compared using a specially defined identity instead of the standardequals()
method. -
GuiWindowSettings
: Manages the GUI window size and position settings. -
GuiThemeSettings
: Manages the GUI theme settings that can be changed by the user. -
StatisticTimeFrame
,StatisticTimeFrameSettings
: Manages the statistics settings that can be changed by the user.
There are also classes with useful utility methods used to handle different types of data, such as dates, times, strings, json and files.
Implementation
This section describes some noteworthy details on how certain features are implemented.
Adding Tasks to Projects
Done by Balasubramaniam Praveen
In Momentum, each project can contain a list of tasks. These can use used to represent various sub-tasks that the user needs to do as part of the project. This section will explain how this is implemented, and some alternative implementations that we have considered.
Chosen Implementation: Separate Task and Project
Done by Farrell Nah Jun Hao
Both projects and tasks have many similarities. They share the following fields:
- Name
- Description
- Completion Status
- Reminder
- Deadline
- Created Date
- Tags
Additionally, both projects and tasks need to work with Momentum’s time tracking and statistics features.
Therefore, it is reasonable to have an abstract TrackedItem
class that contains the fields and methods shared by both projects and tasks, and have Project
and Task
extend from it.
Projects and tasks will then have fields and methods for the behaviours unique to each item. Specifically, a project will contain a list of tasks, and have methods that allow it to modify its own list of tasks. This results in the structure illustrated by the class diagram below:
This allows us to take advantage of polymorphism to ensure that every command will work with both projects and tasks, without having to provide separate implementations for each.
Below is an object diagram to illustrate an example of the structure of some projects and tasks being tracked by Momentum:
The view
and home
commands allow users to navigate between viewing a single project’s tasks, and a view of all projects (with their tasks not visible).
This is implemented by having a list of tracked items to be shown to the user, itemList
. This list is changed to be the project’s task list when a view
command is executed, and changed to the overall project list when a home
command is executed. The list can then be further sorted using the sort command or filtered using the find command, to form a separate list, displayList
, that is provided to the UI components to be displayed to the user.
Most of the commands in Momentum thus become context sensitive, behaving differently depending on whether the project list is being viewed, or a task list if being viewed. For example, the add
command would add a project if the user is viewing the project list, but if the user is viewing a specific project’s task list, it will add a task to that project instead.
We have identified the following benefits and drawbacks of this implementation.
Benefits:
- Having a
TrackedItem
parent class gives us the opportunity to easily extend Momentum to track other things beyond projects and tasks, while also making it easier to integrate new items with existing commands. - Having a clear difference between
Project
andTask
classes allows us to further differentiate projects and tasks in the future. Additional task or project specific features can be easily added without affecting the other.
Drawbacks:
- Some type casting is required for certain operations on projects and tasks, especially for testing purposes. While this is not neccessarily a bad thing, it may make the code less readable and harder to follow.
Alternative Implemention: Using Predicates
Done by Balasubramaniam Praveen
Another implementation we considered was to add all Project
and Task
objects to the same UniqueItemsList
.
This implementation shares some similarities with our chosen implementation. Both Project
and Task
will extend an abstract TrackedItem
class.
However, it differs in the way the displayList
is updated.
A rough summary of the proposed implementation is as follows:
- There will be two predicates. The first predicate will be used to check whether an object is a project or a task. The second predicate will be the normal predicate used to filter the list in the find command.
- Changes in view will modify the first predicate.
- Using the find command will modify the second predicate.
- The predicate used to determine the entries shown in the
displayList
is the logical AND of the first and second predicates.
We have identified the following benefits and drawbacks of this implementation.
Benefits:
- This implementation is much simpler than having to maintain a separate list of
Task
objects for each project. It is likely that existing commands would not have to be changed as much.
Drawbacks:
- A bi-directional association between projects and tasks will be needed. This is unnecessary as a project is composed of multiple tasks. Tasks do not need to know which project they are a part of.
- It might be harder and more time-consuming to write rigorous tests for this implementation.
Alternative Implementation: Projects can contain Projects
Done by Balasubramaniam Praveen
Since projects and tasks are so similar, it may make more sense to treat them as the same object in the first place. Therefore, it is possible to model a project’s sub-tasks as projects themselves. This results in a structure where each project can contain a list of other projects, as illustrated below:
We have identified the following benefits and drawbacks of this implementation.
Benefits:
- This implementation is much simpler than having to maintain separate
Project
andTask
classes. It is likely that existing commands would not have to be changed as much. - Projects can contain not just sub-projects, but sub-sub-projects, sub-sub-sub-projects, etc, allowing for deeper nesting of projects. This may be useful for users to manage more complex project structures.
Drawbacks:
- We will be unable to differentiate between a project and sub-project, since they are both modeled as the same class. This means that project or sub-project specific features cannot be easily implemented without affecting the other.
- Allowing for deeper nesting of projects may make the application more confusing to use without significant UI changes.
Immutability
Done by Farrell Nah Jun Hao
Projects
, Tasks
, Timers
, and WorkDurations
are immutable. This means that anytime a project’s details are changed, a new object is created with the new details, and the model is updated with the new object.
Notable examples include:
- Starting/Stopping a Timer: A new object is created with the updated timer state and durations.
- Editing a Project: A new object is created with the new project’s details, with the same timer and durations recorded.
Below is an example of what happens when a project’s timer is stopped:
In this case, since the project’s timer is being changed, new TimerWrapper
, WorkDuration
, UniqueDurationList
objects are created, which are then used to create a new Project
, which is subsequently used to replace the old Project
in the model.
We chose to implement projects this way as immutability makes these classes more easily testable, and also to support undo and redo commands.
Timers and Durations
Done by Farrell Nah Jun Hao
Momentum allows users to track the time that they spend on each project and task. Time tracking is done by starting and stopping a timer using the start
and stop
commands. The period of time that the user spends is then stored as a WorkDuration
object.
The below diagram illustrates the structure of the classes used for timetracking, and how they are used to calculate statistics.
Each project/task has a TimerWrapper
that represents a timer that can track the time spent on that project. The timer can be started and stopped by the user using the start
/stop
commands.
The timer does not run actively (counting each second/millisecond), instead it records the time when it was started, and the time when it was stopped. This implementation was chosen because it allows Momentum’s timers to continue running even when the application is closed, by saving the timer’s start/stop times together with project/task data.
We chose to give each project and task its own timer as that allows Momentum to support running multiple timers concurrently, one for each project/task, for users that want to multi-task.
A WorkDuration
represents a period of time that the user spent working on a project. Each Project
contains a list of WorkDuration
that represents each time the each the user starts and stops the timer for the project.
We chose to do this implementation to allow for flexibility in calculating statistics.
Deadlines
Done by Cheong Ying Yi Clara
Implementation of Deadline Class
The deadline of a project and tasks is implemented using DateWrapper
and TimeWrapper
. The dateWrapper
and timeWrapper
is stored as Optional<DateWrapper>
and Optional<TimeWrapper>
in the Deadline
class.
Since both date and time is optional in the class, a deadline is empty when both dateWrapper
and timeWrapper
is empty. An empty deadline can be created easily without TrackedItem
needing to know whether it has a deadline. This design was chosen due to the ease of implementation. Another reason is because no dummy data will be required.
Alternative Implementation: Store Date and Time using DateTimeWrapper
An alternative design is to store date and time in a DateTimeWrapper
with dummy date and time if the date or time is not present as LocalDateTime
requires both date and time. However, extra checks will have to be done to differentiate between dummy and actual data.
Parsing a Deadline
The date and time of a deadline of a project or task is parsed separately using different prefixes. This design is chosen as date and time is stored separately and the format of date and time can be more flexible.
Alternative Implementation: Parsing Date and Time Together
An alternative design is to parse both date and time together. This is harder to implement as date and time is stored separately in deadline. This design would also restrict the format of the date and time.
Constraints of a Deadline
The deadline has to be on or after the created date. This is checked when the Deadline
is instantiated. This constraint has been added so that more meaningful statistics can be generated.
For EditCommand
, a descriptor of type editTrackedItemDescriptor
containing edited fields is created directly from parsing the user input in EditCommandParser
, hence the created date is unknown. A dummy date using LocalDate.EPOCH
is passed into the constructor of Deadline
in EditCommandParser
to allow creation of the deadline. The check that deadline has to be on or after the created date is done in the getUpdatedDeadline
method of EditCommand
class after the created date of the project to be edited is known.
Reminders
Done by Cheong Ying Yi Clara
Users can add reminders to be notified on particular projects or tasks at the date and time specified.
Reminders are stored in a project or task. The reminder run and shows the name of the project or task in the reminder panel of the sidebar at the date and time while the application is opened. Reminders are removed after a reminder is runned at the specified date and time.
If application is not open at the date and time of the reminder or if there are multiple reminders scheduled at the same date and time, the reminder will be marked as missed. Details on how the reminder will be marked as missed is in the Scheduling of Reminders section.
Organisation of Reminder Related Classes
The reminder is stored as a Reminder
class in a project or task. The date and time of a reminder is stored in Reminder
.
ReminderManager
schedules the reminder using the schedule
method of the Timer
class and runs the reminder using the run
method of the ThreadWrapper
class.
The diagram below shows the structure of the classes related to the reminder
package.
More details on the implementation of ReminderManager
is given in the Scheduling of Reminders section.
Alternative Implementation: Manage Reminders using Reminder
Class
An alternative would be to schedule and run the reminder in Reminder
class directly. This design was not chosen as that Reminder
would have to contain references to both Model
and ProjectBook
, which is undesired as the projects and tasks in the ProjectBook
will have to be modified.
Rescheduling Reminders
Whenever a project or task is added, edited or removed, the reminders needs to be adjusted accordingly. The chosen implementation is to reschedule all the reminders. This is done through Model#rescheduleReminders
which is further explained in the Scheduling of Reminders section.
Alternative Implementation: Reschedule Reminders of Projects or Tasks Changed
An alternative would be to only reschedule projects or tasks that are affected by the change. This design was not chosen as it is more complicated and would increase the coupling between ReminderManager
and other related classes.
Scheduling of Reminders
ReminderManager
contains a reference to a Model
so that the projects and tasks can be iterated through callback methods and the reminders of the projects can be modified.
To schedule reminders, several callback functions are used to iterate through the project book in the model. The entry point is in ModelManager
where rescheduleReminders
can be called.
This method calls ReminderManager#rescheduleReminder
so that the timer
in ReminderManager
can be reseted before the reminders are actually scheduled.
After resetting the timer
, reminders are rescheduled by calling
Model#rescheduleReminder
. This method iterates through the project book through ProjectBook#rescheduleReminder
to modify the projects and tasks. In this method, the expiration of the reminders will be updated through ProjectBook#updateExpiredReminders
before the reminder of each project and task is rescheduled as shown in the diagram below.
ReminderManager
has an inner class ReminderTimerTask
which implements TimerTask
that is used to schedule a reminder with Timer
. This design was chosen as ReminderTimerTask
references non-static methods of ReminderMananger
as well as Model
, which is also referenced in ReminderManager
. More details on how the reminders are runned using ReminderTimerTask
is given in the Running Reminders section
Alternative Implementation: Implement ReminderTimerTask
as a Separate Class
An alternative implementation is to implement ReminderTimerTask
as a separate class. With this implementation, ReminderTimerTask
will have to contain extra references such as ReminderManager
and Model
.
Running Reminders
At the date and time scheduled, the reminder will be run.
In the process of running the reminders, the UI will show the reminder and it will be removed.
The result of the reminder is stored as a StringProperty
in ReminderManager
and retrieved from the Model
so that a listener can be used in MainWindow
to observe the StringProperty
so that changes can be detected and the GUI can be updated acccordingly.
A BooleanProperty
is also stored in ReminderManager
to keep track of whether there are any reminders so that MainWindow
can detect whether there are reminders and hide or show the reminder panel accordingly. This design was also chosen due to the ease of implementation.
Statistics
Done by Farrell Nah Jun Hao
Momentum calculates statistics using the time tracking data collected from timers and durations.
These statistics are implemented using the command design pattern, similar to how Commands are implemented. Each statistic tracked by Momentum is represented by a Statistic
object, and a StatisticManager
contains all the statistics and is responsible for updating them whenever the model is changed.
Each statistic exposes a calculate(Model model)
method that is called by the StatisticManager
to calculate or update the data with the information in the model. The method contains instructions on how that particular statistic is calculated.
For example, the PeriodicTotalTimeStatistic
calculates the amount of time the user
spends on each project within a specified timeframe, and is calculated by looking at each project in the model and summing up all the durations spent working on the project for the given timeframe.
The statistics data is stored in each Statistic
object as one or more StatisticEntry
objects. A StatisticEntry
represents a unit statistics data, which contains a label
describing the data and the data’s value
.
Below is a sequence diagram to demonstrate how the statistics for time spent per project (weekly) is calculated and how the data is retrieved.
Timeframes
Momentum currently supports calculating statistics within the following timeframes:
- Daily: The period between midnight of the previous day, to the current time.
- Weekly: The period between midnight of the Monday of that week, to the current time.
- Monthly: The period between midnight of the 1st day of the month, to the current time.
The timeframe used to calculate statistics can be set by the user.
Managing Time
Done by Farrell Nah Jun Hao
The Clock
class acts as a consistent, single source of the current time within the application, and provides the option to manually set and control the current time for testing purposes. Objects that need to know the current time must obtain it from Clock
.
The Clock
class has 3 modes that allow for it to perform different functions:
- Normal: The normal system time is returned.
- Fixed: The same, preset time is always returned. Used for testing purposes.
- Manual: The passage of time can be manually controlled, such as fast-forwarding and rewinding time by specific amounts. Used for testing purposes.
This implementation was chosen because it allows all time-related features to be more easily testable.
Alternative Implementation: Using LocalDateTime.now()
directly
This implementation was considered but ultimately rejected as it introduced several problems in testing time-related features. Notable issues are:
- It is impossible to check for equality when getting system time directly using
LocalDateTime.now()
and other similar methods, since time would always progress by a small amount between each call. - It is difficult to test features that require the passage of time, such as the
start
andstop
commands as we would need to actually wait an amount of time during the tests.
Below are some activity diagrams to illustrate the process of obtaining the current time from Clock
in the various modes:
Normal | Fixed | Manual |
Find Command
Momentum allows users to search for projects and tasks using the find command. Users can search for projects/tasks based on their name, description, tag and completion status. A FindType is included to determine whether any, all or none of the parameters need to match a project/task for it to be displayed.
Find Command Implementation
Done by Balasubramaniam Praveen
A predicate is created for each type of search parameter (name, description, tags, completion status). There are four predicates classes defined for this purpose.
-
NameContainsKeywordPredicate
- Filters for projects/tasks based on name. -
DescriptionContainsKeywordPredicate
- Filters for projects/tasks based on description. -
TagListContainsKeywordPredicate
- Filters for projects/tasks based on tags. -
CompletionStatusPredicate
- Filters for projects/tasks based on completion status.
Each of these predicate classes extends the abstract ContainsKeywordPredicate
class which implements the Predicate
interface. Each of these predicate classes takes in a match type, represented by the enumeration FindType
.
The ContainsKeywordPredicate
has a testPredicate
method that is used or overridden by the subclasses. This method is used to test predicates based on the FindType
.
The following class diagram shows the structure of the aforementioned classes.
The FindCommandParser
creates a list of predicates based on the arguments entered by the user. FindCommandParser#combinePredicates
is then used to chain these predicates using the Predicate#or
or Predicate#and
methods depending on the FindType
selected. This returns a Predicate<TrackedItem> predicate
. The FindCommand
will pass predicate
into Model#updatePredicate
to update the displayList
once executed.
The following sequence diagram shows how the FindCommandParser
works. Note that some details have been omitted from the diagram below for clarity.
Chaining Predicates based on Find Type
The process of creating and chaining predicates varies based on the FindType
selected. The following activity diagrams show this process for the various FindType
s.
Note that FindType.NONE
uses the logical AND when combining predicates. This is because individual predicates test for a negative match result. These negative results need to be chained together using the logical AND because a negative match requires a project to not match every keyword.
This design was chosen as it built on the existing implementation of the find command, which passed a NameContainsKeywordPredicate
to the displayList
. This means that minimal changes to other parts of the project were required.
Behaviour of Find Command
The filter used on the displayList
by the Find Command will be reset after the Add
Command is used. It will however persist after using the Edit
Command and Delete
Command.
The list will not be filtered after using the View
or Home
Commands.
This implementation is chosen as we felt that it presents users with the best experience.
Alternative Implementation: Using a Custom Predicate Class
A custom predicate class is used to contain all predicates in a separate MomentumPrediate
interface.
This implementation was ultimately rejected as it introduced unnecessary complexities with Predicate chaining. The MomentumPredicate
interface will need to override Predicate#and
and Predicate#or
with our custom implementation.
Settings
Done by Khoo De Hui
Currently, Momentum allows the GUI theme and the statistics timeframe to be adjusted by the user. This is done using the set command.
Set Command
The command works by first creating and filling up a SettingsToChange
object with the settings given by the user, and then identifying what will be changed. The necessary methods in Model
such as setGuiThemeSettings
or setStatisticTimeframeSettings
will be called to update the settings.
The settings changed by the user will also reflect immediately in the application. This is handled by SettingsUpdateManager
, which is called during the execution of the command.
The following sequence diagram shows how the set command works.
Updating and Saving User Prefs
Settings are saved by updating GuiThemeSettings
and/or StatisticTimeframeSettings
in UserPrefs
in the application model. All class attributes in UserPrefs
are serializable, so that all settings in UserPrefs
can be saved in preferences.json
when the user exits the application. Serialization is done using JsonUserPrefsStorage#saveUserPrefs
.
Below is the class diagram of UserPrefs
.
Model manager will call on UserPrefs#returnChangedGuiThemeSettings
or UserPrefs#returnChangedStatisticTimeframeSettings
when updating the settings. Notice that the two methods will return a new UserPrefs
. This design is chosen so as to support Undo/Redo
, where versions can be placed on the different instances of UserPrefs
.
Settings Update Manager
SettingsUpdateManager
is a class that assists in updating the application instance with the new settings when there are changes made to UserPrefs
.
Currently, the user adjustable settings are the GUI theme and the timeframe of the statistics shown. Hence, SettingsUpdateManager
takes in a Ui
, and a StatisticGenerator
as attributes in order to update them.
SettingsUpdateManager#updateTheme
and SettingsUpdateManager#updateStatisticTimeFrame
are designed to handle null cases of Ui
and StatisticGenerator
so as to make testing more convenient. This is because there are methods being tested that will indirectly call the above methods. Allowing Ui
and StatisticGenerator
to be null will enable them to not be instantiated in the tests.
It is also worth noting that all attributes and methods in SettingUpdateManager
are class-level instead of instance-level. This design was chosen so as to allow minimal changes to the code base. However, one con of this design will be that the attributes and methods can be set or called from anywhere in the code.
Alternative Implementation of SettingsUpdateManager
An alternative implemention of SettingsUpdateManager
is to convert all of the class-level attributes and methods to become instance-level. While this can address the con mentioned above, having to pass an instantiated SettingsUpdateManager
object around now will require some undesirable changes to be made. Below describe the possible ways to pass a SettingsUpdateManager
object around and it’s undesired effects.
- Include
SettingsUpdateManager
as an attribute inModelManager
:- As
Model
is only meant to hold data of the app, puttingSettingUpdateManager
inModelManager
is not ideal.
- As
- Include
SettingsUpdateManager
as an attribute inLogicManager
:- With the current code design, in order for
SetCommand
to be able to useSettingsUpdateManager
, it is required thatSettingsUpdateManager
is passed in as an argument inSetCommand#execute
when the method is called byLogicManager
. This will require changes to be made to the abstractCommand
superclass’execute
method, and is also an undesirable design as all commands will now be aware ofSettingsUpdateManager
whenSetCommand
is the only command using it.
- With the current code design, in order for
Alternative Implementation of Settings Feature
An alternative way to implement the settings feature is to not make the settings reflect immediately. Instead, the user will have to restart the application for the settings to take effect. While it will be much easier to implement since it will only require updating UserPrefs
, it will not provide a good user experience.
Sort Command
Done by Kang Su Min
Momentum allows users to sort their list of projects/tasks using sort command. The following sort types and orders are available:
Sort Type
-
SortType.ALPHA
: sort the list of projects/tasks in alphabetical order. -
SortType.DEADLINE
: sort the list of projects/tasks according to their deadlines. -
SortType.CREATED
: sort the list of projects/tasks according to their date of creation. -
SortType.NULL
: sort type not specified by user, sort the list of projects/tasks according to the current sort type.
Sort Order
- Ascending order
- Descending order
Sort By Completion Status
- On: First sort by placing projects/tasks with incomplete status at the top of the list then sorting by specified sort type and order
- Off: Sort projects/tasks by specified sort type and order without regard for completion status.
The comparators below facilitate the ordering of the list of projects/tasks.
-
CompletionStatusCompare
- Comparator that compares the completion status of two tasks. This is a comparator that imposed a sort order on top of other comparators, which means that all incomplete projects/tasks are shown at the top of the list ordered in the specified orders, and all complete projects/tasks are shown at the bottom, also ordered in the specified order. This sort order is imposed by default, and can be toggled on and off. -
CreatedDateCompare
- Comparator that compares the created date of two tasks, then the alphabetical names of two tasks if created dates are the same. -
NameCompare
- Comparator that compares the alphabetical names of two tasks. -
DeadlineCompare
- Comparator that compares the deadlines of two tasks, then the alphabetical names of two tasks if deadlines are the same.
Design Details
- The
SortCommandParser
parses user input and passes sort values (Sort type, whether it is in ascending order, whether the default ordering of completion status) to theModelManager
. -
The comparators are then generated according to these values in
ModelManager
and sort order is imposed on the list of projects/tasks based on the comparator.ModelManager
stores the information of the latest sort order imposed so that the sort order can be maintained. - All comparators extend the class
Comparator<TrackedItem>
exceptDeadlineCompare
, which extends the classComparator<HashMap<String, Object>>
.- This is because for all other attributes such as name, completion status and created date, it is guaranteed that every
TrackedItem
will have a non-null value, however it is possible that a project or a task has no deadline. - Therefore,
Comparator#nullsLast
was used to place the project/tasks with no deadlines at the end of the list if the list is to be sorted by deadline. Those with deadlines will then be compared by passing in their deadline and name details to aHashMap
which is then compared usingDeadlineCompare
, while those without deadlines will be sorted in alphabetical order usingNameCompare
.
- This is because for all other attributes such as name, completion status and created date, it is guaranteed that every
Alternative Implementation: Making TrackedItem
extend Comparable
This implementation was initially considered at the start before developing the sort feature further to include different sort types and sort orders. However, this was not as appropriate for usage due to the following reasons:
- Making
TrackedItem
extendComparable<TrackedItem>
would not allow for advanced, multi-level sort feature that we have now as it would only be sorted in one particular order. - In the case of deadline, some tasks/projects do not have them, and it would not be possible to sort projects/tasks using
Comparable<TrackedItem>
.
Undo/Redo Feature
Done by Kang Su Min
The undo/redo command allows users to step through their history log of Momentum, such that they can undo commands they have excecuted wrongly, or redo commands that they have previously undone.
Chosen Implementation
The undo/redo implementation is as such:
- Create a
VersionedProjectBook
which extendsProjectBook
with an undo/redo history log - The history of
VersionedProjectBook
is stored as aprojectBookStateList
containing versions ofProjectBookWithUi
and acurrentStatePointer
. Users are able to go back to a particular point in their history log by shiting thecurrentStatePointer
.- The need for an additional class
ProjectBookWithUi
comes from the need to store UI details that need to be reset inModelManager
class in addition to the resetting ofProjectBook
data done by undo/redo withinVersionedProjectBook
class. TheVersionedProjectBook
implements the following operations to facilitate the storing and traversing of history:
- The need for an additional class
-
VersionedProjectBook#commit()
— Saves the current project book state in itsprojectBookStateList
as aProjectBookWithUi
object. -
VersionedProjectBook#undo()
— Resets the project book data with data from the previous project book state in its history. -
VersionedProjectBook#redo()
— Resets the project book data with data from a previously undone project book state in its history.
The above operations are exposed in the Model
interface as Model#commitToHistory()
, Model#undoCommand()
and Model#redoCommand()
respectively.
An example usage scenario has been provided below to demonstrate the undo/redo mechanism.
Step 1. The user launches the application for the first time. The VersionedProjectBook
is initialized with the initial project book state, and the state is added to the projectBookStateList
with the currentStatePointer
pointing to that state.
Step 2. The user executes delete 2
command to delete the 2nd project in the project book. The delete
command calls Model#commitToHistory
, which adds the new state of the project book after the execution of delete 2
command as ProjectBookWithUi
in the projectBookStateList
. After every new command (excluding undo, redo, and help), the currentStatePointer
is shifted to the most recent project book state.
Step 3. The user executes add n/Design Webpage for XYZ
to add a new project. The add
command also calls Model#commitProjectBook()
, which similarly adds the new state of the project book after the execution of add n/Design Webpage for XYZ
command as ProjectBookWithUi
in the projectBookStateList
.
Model#commitProjectBook()
is not called. Project book state will not be saved into the projectBookStateList
.
Step 4. If user wants undo that action due to some errors in the information, they can do so by executing the undo
command. The undo
command calls Model#undoCommand()
, which resets the current project book with the data from the previous project book state. This is done after currentStatePointer
is shifted once to the left.
currentStatePointer
is at index 0, meaning there is no history to traverse back in time, then the undo
command will throw an exception that informs user that there is no command to undo. This is done after checking that there is no history to go back to using Model#canUndoCommand()
.
Model#commitProjectBook()
as these command will not cause any project book changes in terms of data or UI.
The following sequence diagram shows how the undo operation works:
The redo
command does the opposite — it calls Model#redoCommand()
, which shifts the currentStatePointer
once to the right, pointing to the previously undone state, and resets the current project book with the data from the next project book state.
currentStatePointer
is at index projectBookStateList.size() - 1
, meaning there is no history to move forward to (undo has not been executed), then the redo
command will throw an exception that informs user that there is no command to redo. This is done after checking that there is no history to move forward to using Model#canRedoCommand()
Step 5. If the user changes their mind and decides that the error is minor and wish to redo the previously undone command, they can do so by executing the redo
command. The redo
command calls Model#redoCommand()
, which resets the current project book with the data from the next project book state. This is done after currentStatePointer
is shifted once to the right.
Step 6. If the user changes their mind once again and decides to go with undo, they can do so by executing the undo
command again.
Step 7. The user executes clear
, which calls Model#commitProjectBook()
. Because the currentStatePointer
is not the most recent state in projectBookStateList
, all project book states after the currentStatePointer
will be flushed. This is to maintain a single history of states based on executed commands.
The following activity diagram summarizes what happens when a user executes a new command (that is not undo, redo, help, or exit):
Alternative Implementation: Saving Commands Instead of Entire Project Book
This would allow users to go back in history through a reversal of command once a command is undone.
Because this stores a history of commands and versions of the entire project book, it takes up less memory in users’ devices and as a result would have performance gains.
This was a candidate for implementation but ultimately rejected due to the following concerns:
-
It is difficult to implement the reversal of every command.
- We have added many new features and commands, hence it would take time to implement the reversal of each command. It would be wiser to spend the time on improving our existing features.
-
This would be more prone to bugs due to the compulsory implementation of reversal of every command.
Documentation, logging, testing, configuration, dev-ops
Appendix: Requirements
Product scope
Target user profile:
- Freelancers
- Freelancers may take on multiple projects simultaneously, so they need to manage and track the time they spend on each project.
- Freelancers want to know how much time they spend on a project in order to accurately bill their clients and set future rates.
- Freelancers might want to know more about how they distribute their time and track the time spent on each project so that they can better understand their working style, and plan their time more efficiently.
Value proposition:
- Time tracking app
- Dashboard view for freelancer to get an overview of all projects.
- Projects can contain multiple tasks to facilitate effective tracking of projects.
- Use tags to organise tasks and projects for commonly used categories.
- Timer to track the duration of a task or project, so that the user can price their rates and charge clients more accurately.
- Deadline and completion status to track the status of a task or project.
- Reminder for a project (only when application is open).
- Perform highly customised searches for projects and tasks.
- Quickly organise projects and tasks based on different parameters.
- Attractive GUI with customisable themes for better user experience.
- Interesting/creative views for visualizing the data.
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 with many projects in Momentum | sort projects/tasks by name | locate a project/task easily |
* |
user with many projects in Momentum | sort projects/tasks by completion status | locate an incomplete or complete project/task easily |
* |
user with many projects in Momentum | hide and show the tags panel | focus more on statistics and timers |
* |
user with many projects in Momentum | dismiss the reminder | focus more on statistics and timers |
* |
user with many projects in the project book | sort projects by name | locate a project easily |
* |
user with many projects in the project book | sort projects by created date | view their history of projects/tasks |
* |
user with many projects in the project book | hide and show the tags panel | focus more on statistics and timers |
* |
user with many projects in the project book | dismiss the reminder | focus more on statistics and timers |
* * |
new user | start and stop a timer for a project/task | track the time I spent on the project/task |
* * |
user | see the amount of time I spend on each project/task | gain insights on how I am using my time |
* * |
user | can create tasks within a project | better organize my work |
* * |
user | can change the way the UI looks | have the application more personalised to me |
* * |
user | can adjust the timeframe of the statistics shown | gain even better insights on how I am using my time in different timeframes |
* * |
user with many projects in the project book | sort projects by deadline | prioritise urgent projects/tasks |
* * |
user with many projects in the project book | sort projects by completion status | locate an incomplete or complete project easily |
* * |
new user | start and stop a timer for a project | track the time I spent on the project |
* * |
user | see the amount of time I spend on each project | gain insights on how I am using my time |
* * |
user | can create tasks within a project | better organize my work |
* * * |
new user | see usage instructions | refer to instructions when I forget how to use the App |
* * * |
user | add a new project/task | |
* * * |
user | view the project/task’s creation date | know when I started tracking that project/task |
* * * |
user | view the project/task’s completion status | check if I have completed a project/task |
* * * |
user | add and edit a deadline for a project/task | know when I need to finish the project/task |
* * * |
user | add and edit a reminder for a project/task | remind myself to do important projects/tasks |
* * * |
user | delete a project/task | remove entries that I no longer need |
* * * |
user | find a project/task by name | locate projects/task by name without having to go through the entire list |
* * * |
user | find a project/task by description | locate projects/tasks by description without having to go through the entire list |
* * * |
user | find a project/task by tag | locate projects/tasks by tag without having to go through the entire list |
* * * |
user | find a project/task by completion status | locate projects/tasks that are completed or incomplete without having to go through the entire list |
* * * |
user | find a project/task by multiple parameters | locate details of projects/tasks without having to go through the entire list |
* * * |
user | add a new project | |
* * * |
user | view the project creation date | |
* * * |
user | view the project completion status | |
* * * |
user | add and edit a deadline for a project | |
* * * |
user | add and edit a reminder for a project | |
* * * |
user | undo a wrong command | revert unwanted changes |
* * * |
user | redo a undone command | revert unwanted changes |
* * * |
user | delete a project | remove entries that I no longer need |
* * * |
user | find a project by name | locate projects by name without having to go through the entire list |
* * * |
user | find a project by description | locate projects by description without having to go through the entire list |
* * * |
user | find a project by tag | locate projects by tag without having to go through the entire list |
* * * |
user | find a project by completion status | locate projects that are completed or incomplete without having to go through the entire list |
* * * |
user | find a project by multiple parameters | locate details of projects without having to go through the entire list |
Use cases
(For all use cases below, the System is the Momentum
and the Actor is the user
, unless specified otherwise)
Use Case: Start and End a Timer
MSS
- User requests to start a timer for a specific project in the list.
- Momemtum starts the timer for the project.
- User requests to end a timer for a specific project in the list.
- Momemtum ends the timer for the project.
Extensions
-
2a. There is an existing timer for the given project id.
-
a1. Momentum shows an error message.
Use case ends.
-
-
3a. There is no ongoing timer for the given project id.
-
a1. Momentum shows an error message.
Use case ends.
-
-
*a. The given project id is invalid.
-
a1. Momentum shows an error message.
Use case ends.
-
Use Case: Add a Project
MSS
- User requests to add a project with a name, a description, a deadline, a completion status, a reminder and a tag.
- Momentum shows a command result and updates the project list shown to reflect the addition.
- Momentum shows the name of the project in the reminder panel and remove the reminder of the project at the date and time of the reminder specified.
- User requests to [dismiss the reminder](#use-case-dismiss-a-reminder)
Extensions
-
2a. Momentum detects an error in the user input or a duplicate project in the project list.
- a1. Momentum shows an error message.
Use case ends.
The use cases for editing a project, adding a task and editing a task is similar to adding a project, except that the error messages differ slightly.
Use Case: Dismiss a Reminder
- User requests to dismiss a reminder.
- Momentum hides the reminder panel.
Extensions
-
1a. Momentum detects an error as there is no reminder to dismiss.
- a1. Momentum shows an error message.
Use case ends.
Use Case: Hide the Tags Panel
- User requests to hide the tags panel.
- Momentum hides the tags panel.
Use case ends.
Use Case: Delete a Project
MSS
- User requests to list projects.
- Momentum shows a list of projects.
- User requests to delete a specific project in the list.
-
Momentum deletes the project.
Use case ends.
The use cases for deleting a task is similar to deleting a project.
Extensions
-
3a. The given project id is invalid.
-
a1. Momentum shows an error message.
Use case ends.
-
Use Case: Find a Project/Task in the List
MSS
- User requests to filter the projects/tasks displayed based on certain parameters.
- Momemtum filters the list of projects displayed.
Extensions
-
2a. There is no project/task that matches the specified parameters.
-
a1. Momentum shows an empty list.
Use case ends.
-
-
*a. The arguments are given in an incorrect format.
-
a1. Momentum shows an error message.
Use case ends.
-
Use Case: View a Project’s Tasks
MSS
- User requests to view the tasks belonging to a project.
- Momentum shows a list of tasks belonging to the project.
Extensions
-
*a. The arguments are given in an incorrect format.
-
a1. Momentum shows an error message.
Use case ends.
-
Use Case: Changing Application Settings
MSS
- User requests to change theme settings.
- Momentum updates the user preferences.
- Momentum reflects the changes in the application GUI.
- User requests to change statistic timeframe settings.
- Momentum updates the user preferences.
-
Momentum reflects the changes in the application GUI.
Use case ends.
Extensions
-
1a. The given theme is invalid.
-
1a1. Momentum shows an error message.
Use case ends
-
-
4a. The given timeframe is invalid.
-
4a1. Momentum shows an error message.
Use case ends.
-
Use Case: Undo a Command
MSS
- User requests to undo the command.
- User previously executed a certain undoable command in Momentum.
- Momentum undoes the command and reverts back to its previous state before the command was executed.
Extensions
- 2a. User did not previously execute an undoable command and there is no history to undo command.
- 2a1. Momentum shows an error message.
Use case ends.
Use Case: Redo a Command
MSS
- User requests to redo the command.
- User previously executed undo command.
- Momentum redoes the command and reverts back to the state before the undo was executed.
Extensions
- 2a. User did not previously execute undo command and there is no history to redo command.
- 2a1. Momentum shows an error message.
Use case ends.
Non-Functional Requirements
- Should work on any mainstream OS as long as it has Java
11
or above installed. - Should be able to hold up to 1000 projects 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.
Glossary
- Command Line Interface(CLI): Command Line Interface processes commands in the form of text
- Mainstream OS: Windows, Linux, Unix, OS-X
- Project View: View all projects in the project book.
- Task View: View all tasks that are added to a single project.
Appendix: Instructions for manual testing
Done by Balasubramaniam Praveen
Given below are instructions to test the app manually.
Launch and Shutdown
-
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 projects and tasks.
-
-
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.
-
Saving Data
-
Dealing with missing data files
-
Delete the existing
projectbook.json
file in thedata
directory -
Re-launch the app by double-clicking the jar file.
Expected: The project book is initalized with default data.
-
-
Dealing with corrupted data files
-
Corrupt the values inside the existing
projectbook.json
file by changing the nameprojects
in torojects
-
Re-launch the app by double-clicking the jar file.
Expected: The project book is initalized with no data.
-
Add a Project
-
Adding a project while all projects are shown.
-
Prerequisites: List all projects using the
list
command. Multiple projects in the list. -
Test case:
add n/project1
Expected: A new project with the nameproject1
will be created. Details of the project shown in the status message. -
Test case:
add n/project2 d/desc2
Expected: A new project with the nameproject2
and descriptiondesc2
will be created. Details of the project shown in the status message. -
Test case:
add n/project3 t/tagA t/tagB
Expected: A new project with the nameproject3
and tagstagA
andtagB
will be created. Details of the project shown in the status message. -
Test case:
add n/project4 c/
Expected: A new project with the nameproject4
and completion statusdone
will be created. Details of the project shown in the status message. -
Test case:
add n/project5 dd/2020-12-21
Expected: A new project with the nameproject5
and deadline date2020-12-21
will be created. Details of the project shown in the status message. -
Test case:
add n/project6 dd/2020-12-21 dt/12:34:56
Expected: A new project with the nameproject5
and deadline date2020-12-21
and deadline time12:34:56
will be created. Details of the project shown in the status message. -
Test case:
add n/project7 r/x
wherex
is a time later that the current time in theYYYY-MM-DDTHH:MM:SS
format.
Expected: A new project with the nameproject6
and a reminder scheduled at timex
will be created. Details of the project shown in the status message.
-
-
Adding a project while only some projects are shown.
-
Prerequisites: List only some projects using the
find
command. -
Test case:
add n/project1
Expected: A new project with the nameproject1
will be created. Details of the project shown in the status message. View will be reset and all projects should be shown. -
Test case:
add n/project2 d/desc2
Expected: A new project with the nameproject2
and descriptiondesc2
will be created. Details of the project shown in the status message. View will be reset and all projects should be shown. -
Test case:
add n/project3 t/tagA t/tagB
Expected: A new project with the nameproject3
and tagstagA
andtagB
will be created. Details of the project shown in the status message. View will be reset and all projects should be shown. -
Test case:
add n/project4 c/
Expected: A new project with the nameproject4
and completion statusdone
will be created. Details of the project shown in the status message. View will be reset and all projects should be shown. -
Test case:
add n/project5 dd/2020-12-21
Expected: A new project with the nameproject5
and deadline date2020-12-21
will be created. Details of the project shown in the status message. View will be reset and all projects should be shown. -
Test case:
add n/project6 dd/2020-12-21 dt/12:34:56
Expected: A new project with the nameproject5
and deadline date2020-12-21
and deadline time12:34:56
will be created. Details of the project shown in the status message. View will be reset and all projects should be shown. -
Test case:
add n/project7 r/x
wherex
is a time later that the current time in theYYYY-MM-DDTHH:MM:SS
format.
Expected: A new project with the nameproject6
and a reminder scheduled at timex
will be created. Details of the project shown in the status message. View will be reset and all projects should be shown.
-
-
Adding a project with invalid inputs parameters.
-
Prerequisites: List all projects using the
list
command. Multiple projects in the list. -
Test case:
add n/$$
Expected: A new project will not be created. Invalid name format message shown in the status message. -
Test case:
add n/project3 t/invalid tag
Expected: A new project will not be created. Invalid name format message shown in the status message. -
Test case:
add n/project5 dd/2020-21-12
Expected: A new project will not be created. Invalid date format message shown in the status message. -
Test case:
add n/project6 dd/2020-12-21 dt/99:99:99
Expected: A new project will not be created. Invalid time format message shown in the status message. -
Test case:
add n/project7 r/x
wherex
is a time earlier that the current time in theYYYY-MM-DDTHH:MM:SS
format.
Expected: A new project will not be created. Invalid reminder date and time message shown in the status message.
-
Edit a Project
-
Editing a project while all projects are shown.
-
Prerequisites: List all projects using the
list
command. Multiple projects in the list. -
Test case:
edit x n/project1
wherex
is the index of a project in the list.
Expected: The project at indexx
will be edited to have the nameproject1
Details of the edited project shown in the status message. -
Test case:
edit x d/desc2
wherex
is the index of a project in the list.
Expected: The project at indexx
will be edited to have the descriptiondesc2
. Details of the edited project shown in the status message. -
Test case:
edit x t/tagA t/tagB
wherex
is the index of a project in the list.
Expected: The project at indexx
will be edited to have the tagstagA
andtagB
. Details of the edited project shown in the status message. -
Test case:
edit x c/
wherex
is the index of a project in the list.
Expected: The project at indexx
will be edited to have the completion statusdone
. Details of the edited project shown in the status message. -
Test case:
edit x dd/2020-12-21
wherex
is the index of a project in the list.
Expected: The project at indexx
will be edited to have the deadline date2020-12-21
. Details of the edited project shown in the status message. -
Test case:
edit x dd/2020-12-21 dt/12:34:56
wherex
is the index of a project in the list.
Expected: The project at indexx
will be edited to have thr deadline date2020-12-21
and deadline time12:34:56
. Details of the edited project shown in the status message. -
Test case:
edit x r/y
wherex
is the index of a project in the list andy
is a time later that the current time in theYYYY-MM-DDTHH:MM:SS
format.
Expected: The project at indexx
will be edited to have the nameproject6
and a reminder scheduled at timey
. Details of the edited project shown in the status message.
-
-
Editing a project while only some projects are shown.
-
Prerequisites: List only some projects using the
find
command. -
Test case:
edit x n/project1
wherex
is the index of a project in the list.
Expected: The project at indexx
will be edited to have the nameproject1
Details of the edited project shown in the status message. View will persist and only some projects should be shown. -
Test case:
edit x d/desc2
wherex
is the index of a project in the list.
Expected: The project at indexx
will be edited to have the descriptiondesc2
. Details of the edited project shown in the status message. View will persist and only some projects should be shown. -
Test case:
edit x t/tagA t/tagB
wherex
is the index of a project in the list.
Expected: The project at indexx
will be edited to have the tagstagA
andtagB
. Details of the edited project shown in the status message. View will persist and only some projects should be shown. -
Test case:
edit x c/
wherex
is the index of a project in the list.
Expected: The project at indexx
will be edited to have the completion statusdone
. Details of the edited project shown in the status message. View will persist and only some projects should be shown. -
Test case:
edit x dd/2020-12-21
wherex
is the index of a project in the list.
Expected: The project at indexx
will be edited to have the deadline date2020-12-21
. Details of the edited project shown in the status message. View will persist and only some projects should be shown. -
Test case:
edit x dd/2020-12-21 dt/12:34:56
wherex
is the index of a project in the list.
Expected: The project at indexx
will be edited to have thr deadline date2020-12-21
and deadline time12:34:56
. Details of the edited project shown in the status message. View will persist and only some projects should be shown. -
Test case:
edit x r/y
wherex
is the index of a project in the list andy
is a time later that the current time in theYYYY-MM-DDTHH:MM:SS
format.
Expected: The project at indexx
will be edited to have the nameproject6
and a reminder scheduled at timey
. Details of the edited project shown in the status message. View will persist and only some projects should be shown.
-
-
Editing a project with invalid inputs parameters.
-
Prerequisites: List all projects using the
list
command. Multiple projects in the list. -
Test case:
edit x n/$$
wherex
is the index of a project in the list.
Expected: The project at indexx
will not be edited. Invalid name format message shown in the status message. -
Test case:
edit x t/invalid tag
wherex
is the index of a project in the list.
Expected: The project at indexx
will not be edited. Invalid tag format message shown in the status message. -
Test case:
edit x dd/2020-21-12
wherex
is the index of a project in the list.
Expected: The project at indexx
will not be edited. Invalid date format message shown in the status message. -
Test case:
edit x dd/2020-12-21 dt/99:99:99
wherex
is the index of a project in the list.
Expected: The project at indexx
will not be edited. Invalid time format message shown in the status message. -
Test case:
edit x r/y
wherex
is the index of a project in the list andy
is a time later that the current time in theYYYY-MM-DDTHH:MM:SS
format.
Expected: The project at indexx
will not be edited. Invalid reminder date and time message shown in the status message.
-
Delete a Project
-
Deleting a project while all projects are shown.
-
Prerequisites: List all projects using the
list
command. Multiple projects in the list. -
Test case:
delete 1
Expected: The first project in the list will be deleted. Details of the deleted project shown in the status message. -
Test case:
delete 0
,delete
Expected: No project will be deleted. Invalid command format message shown. No change to the list of projects. -
Test case:
delete x
, where x is greater than the number of projects
Expected: No project will be deleted. Invalid index message shown.
-
-
Deleting a project while only some projects are being shown.
-
Prerequisites: Find some projects using the
find
command. Multiple projects in the filtered list. -
Test case:
delete 1
Expected: First project in the filtered list will be deleted. Details of the deleted project shown in the status message. -
Test case:
delete 0
,delete
Expected: No project will be deleted. Invalid command format message shown. No change to the list of projects. -
Test case:
delete x
, where x is greater than the number of projects
Expected: No project will be deleted. Invalid index message shown.
-
-
Deleting a project while only one project is being shown.
-
Prerequisites: Find a single project using the
find
command. Only one project in the filtered list. -
Test case:
delete 1
Expected: First project in the filtered list will be deleted. Details of the deleted project shown in the status message. The filtered list will be empty. Application will not revert to an unfiltered list. -
Test case:
delete 0
,delete
Expected: No project will be deleted. Invalid command format message shown. No change to the list of projects. -
Test case:
delete x
, where x is greater than the number of projects
Expected: No project will be deleted. Invalid index message shown.
-
Clear All Projects
-
Clearing projects when all projects are shown.
-
Prerequisites: List all projects using the
list
command. Multiple projects in the list. -
Test case:
clear
Expected: All projects and tasks in the project book will be deleted.
-
-
Clearing projects when only some projects are shown.
-
Prerequisites: Find some projects using the
find
command. Multiple projects in the filtered list. -
Test case:
clear
Expected: All projects and tasks in the project book will be deleted.
-
Add a Task
-
Adding a task while all tasks are shown.
-
Prerequisites: Viewing tasks for any project. List all tasks using the
list
command. Multiple tasks in the list. -
Test case:
add n/task1
Expected: A new task with the nametask1
will be created. Details of the task shown in the status message. -
Test case:
add n/task2 d/desc2
Expected: A new task with the nametask2
and descriptiondesc2
will be created. Details of the task shown in the status message. -
Test case:
add n/task3 t/tagA t/tagB
Expected: A new task with the nametask3
and tagstagA
andtagB
will be created. Details of the task shown in the status message. -
Test case:
add n/task4 c/
Expected: A new task with the nametask4
and completion statusdone
will be created. Details of the task shown in the status message. -
Test case:
add n/task5 dd/2020-12-21
Expected: A new task with the nametask5
and deadline date2020-12-21
will be created. Details of the task shown in the status message. -
Test case:
add n/task6 dd/2020-12-21 dt/12:34:56
Expected: A new task with the nametask5
and deadline date2020-12-21
and deadline time12:34:56
will be created. Details of the task shown in the status message. -
Test case:
add n/task7 r/x
wherex
is a time later that the current time in theYYYY-MM-DDTHH:MM:SS
format.
Expected: A new task with the nametask6
and a reminder scheduled at timex
will be created. Details of the task shown in the status message.
-
-
Adding a task while only some tasks are shown.
-
Prerequisites: Viewing tasks for any project.List only some tasks using the
find
command. -
Test case:
add n/task1
Expected: A new task with the nametask1
will be created. Details of the task shown in the status message. View will be reset and all tasks should be shown. -
Test case:
add n/task2 d/desc2
Expected: A new task with the nametask2
and descriptiondesc2
will be created. Details of the task shown in the status message. View will be reset and all tasks should be shown. -
Test case:
add n/task3 t/tagA t/tagB
Expected: A new task with the nametask3
and tagstagA
andtagB
will be created. Details of the task shown in the status message. View will be reset and all tasks should be shown. -
Test case:
add n/task4 c/
Expected: A new task with the nametask4
and completion statusdone
will be created. Details of the task shown in the status message. View will be reset and all tasks should be shown. -
Test case:
add n/task5 dd/2020-12-21
Expected: A new task with the nametask5
and deadline date2020-12-21
will be created. Details of the task shown in the status message. View will be reset and all tasks should be shown. -
Test case:
add n/task6 dd/2020-12-21 dt/12:34:56
Expected: A new task with the nametask5
and deadline date2020-12-21
and deadline time12:34:56
will be created. Details of the task shown in the status message. View will be reset and all tasks should be shown. -
Test case:
add n/task7 r/x
wherex
is a time later that the current time in theYYYY-MM-DDTHH:MM:SS
format.
Expected: A new task with the nametask6
and a reminder scheduled at timex
will be created. Details of the task shown in the status message. View will be reset and all tasks should be shown.
-
-
Adding a task with invalid inputs parameters.
-
Prerequisites: Viewing tasks for any project. List all tasks using the
list
command. Multiple tasks in the list. -
Test case:
add n/$$
Expected: A new task will not be created. Invalid name format message shown in the status message. -
Test case:
add n/task3 t/invalid tag
Expected: A new task will not be created. Invalid name format message shown in the status message. -
Test case:
add n/task5 dd/2020-21-12
Expected: A new task will not be created. Invalid date format message shown in the status message. -
Test case:
add n/task6 dd/2020-12-21 dt/99:99:99
Expected: A new task will not be created. Invalid time format message shown in the status message. -
Test case:
add n/task7 r/x
wherex
is a time earlier that the current time in theYYYY-MM-DDTHH:MM:SS
format.
Expected: A new task will not be created. Invalid reminder date and time message shown in the status message.
-
Edit a Task
-
Editing a task while all tasks are shown.
-
Prerequisites: Viewing tasks for any project. List all tasks using the
list
command. Multiple tasks in the list. -
Test case:
edit x n/task1
wherex
is the index of a task in the list.
Expected: The task at indexx
will be edited to have the nametask1
Details of the edited task shown in the status message. -
Test case:
edit x d/desc2
wherex
is the index of a task in the list.
Expected: The task at indexx
will be edited to have the descriptiondesc2
. Details of the edited task shown in the status message. -
Test case:
edit x t/tagA t/tagB
wherex
is the index of a task in the list.
Expected: The task at indexx
will be edited to have the tagstagA
andtagB
. Details of the edited task shown in the status message. -
Test case:
edit x c/
wherex
is the index of a task in the list.
Expected: The task at indexx
will be edited to have the completion statusdone
. Details of the edited task shown in the status message. -
Test case:
edit x dd/2020-12-21
wherex
is the index of a task in the list.
Expected: The task at indexx
will be edited to have the deadline date2020-12-21
. Details of the edited task shown in the status message. -
Test case:
edit x dd/2020-12-21 dt/12:34:56
wherex
is the index of a task in the list.
Expected: The task at indexx
will be edited to have thr deadline date2020-12-21
and deadline time12:34:56
. Details of the edited task shown in the status message. -
Test case:
edit x r/y
wherex
is the index of a task in the list andy
is a time later that the current time in theYYYY-MM-DDTHH:MM:SS
format.
Expected: The task at indexx
will be edited to have the nametask6
and a reminder scheduled at timey
. Details of the edited task shown in the status message.
-
-
Editing a task while only some tasks are shown.
-
Prerequisites: Viewing tasks for any project. List only some tasks using the
find
command. -
Test case:
edit x n/task1
wherex
is the index of a task in the list.
Expected: The task at indexx
will be edited to have the nametask1
Details of the edited task shown in the status message. View will persist and only some tasks should be shown. -
Test case:
edit x d/desc2
wherex
is the index of a task in the list.
Expected: The task at indexx
will be edited to have the descriptiondesc2
. Details of the edited task shown in the status message. View will persist and only some tasks should be shown. -
Test case:
edit x t/tagA t/tagB
wherex
is the index of a task in the list.
Expected: The task at indexx
will be edited to have the tagstagA
andtagB
. Details of the edited task shown in the status message. View will persist and only some tasks should be shown. -
Test case:
edit x c/
wherex
is the index of a task in the list.
Expected: The task at indexx
will be edited to have the completion statusdone
. Details of the edited task shown in the status message. View will persist and only some tasks should be shown. -
Test case:
edit x dd/2020-12-21
wherex
is the index of a task in the list.
Expected: The task at indexx
will be edited to have the deadline date2020-12-21
. Details of the edited task shown in the status message. View will persist and only some tasks should be shown. -
Test case:
edit x dd/2020-12-21 dt/12:34:56
wherex
is the index of a task in the list.
Expected: The task at indexx
will be edited to have thr deadline date2020-12-21
and deadline time12:34:56
. Details of the edited task shown in the status message. View will persist and only some tasks should be shown. -
Test case:
edit x r/y
wherex
is the index of a task in the list andy
is a time later that the current time in theYYYY-MM-DDTHH:MM:SS
format.
Expected: The task at indexx
will be edited to have the nametask6
and a reminder scheduled at timey
. Details of the edited task shown in the status message. View will persist and only some tasks should be shown.
-
-
Editing a task with invalid inputs parameters.
-
Prerequisites: Viewing tasks for any project. List all tasks using the
list
command. Multiple tasks in the list. -
Test case:
edit x n/$$
wherex
is the index of a task in the list.
Expected: The task at indexx
will not be edited. Invalid name format message shown in the status message. -
Test case:
edit x t/invalid tag
wherex
is the index of a task in the list.
Expected: The task at indexx
will not be edited. Invalid tag format message shown in the status message. -
Test case:
edit x dd/2020-21-12
wherex
is the index of a task in the list.
Expected: The task at indexx
will not be edited. Invalid date format message shown in the status message. -
Test case:
edit x dd/2020-12-21 dt/99:99:99
wherex
is the index of a task in the list.
Expected: The task at indexx
will not be edited. Invalid time format message shown in the status message. -
Test case:
edit x r/y
wherex
is the index of a task in the list andy
is a time later that the current time in theYYYY-MM-DDTHH:MM:SS
format.
Expected: The task at indexx
will not be edited. Invalid reminder date and time message shown in the status message.
-
Delete a Task
-
Deleting a task while all tasks are shown.
-
Prerequisites: Viewing tasks for any project. List all tasks using the
list
command. Multiple tasks in the list. -
Test case:
delete 1
Expected: The first task in the list will be deleted. Details of the deleted task shown in the status message. -
Test case:
delete 0
,delete
Expected: No task will be deleted. Invalid command format message shown. No change to the list of tasks. -
Test case:
delete x
, where x is greater than the number of tasks
Expected: No task will be deleted. Invalid index message shown.
-
-
Deleting a task while only some tasks are being shown.
-
Prerequisites: Viewing tasks for any project. Find some tasks using the
find
command. Multiple tasks in the filtered list. -
Test case:
delete 1
Expected: First task in the filtered list will be deleted. Details of the deleted task shown in the status message. -
Test case:
delete 0
,delete
Expected: No task will be deleted. Invalid command format message shown. No change to the list of tasks. -
Test case:
delete x
, where x is greater than the number of tasks
Expected: No task will be deleted. Invalid index message shown.
-
-
Deleting a task while only one task is being shown.
-
Prerequisites: Viewing tasks for any project. Find a single task using the
find
command. Only one task in the filtered list. -
Test case:
delete 1
Expected: First task in the filtered list will be deleted. Details of the deleted task shown in the status message. The filtered list will be empty. Application will not revert to an unfiltered list. -
Test case:
delete 0
,delete
Expected: No task will be deleted. Invalid command format message shown. No change to the list of tasks. -
Test case:
delete x
, where x is greater than the number of tasks
Expected: No task will be deleted. Invalid index message shown.
-
Clear All Tasks
-
Clearing tasks when all tasks are shown.
-
Prerequisites: Viewing tasks for any project. List all tasks using the
list
command. Multiple tasks in the list. -
Test case:
clear
Expected: All tasks associated with the project being viewed will be deleted. Other projects and their tasks should not be deleted.
-
-
Clearing projects when only some tasks are shown.
-
Prerequisites: Viewing tasks for any project. Find some tasks using the
find
command. Multiple tasks in the filtered list. -
Test case:
clear
Expected: All tasks associated with the project being viewed will be deleted. Other projects and their tasks should not be deleted.
-
Changing Views
-
Changing view while viewing all projects.
-
Prerequisites: View all projects by running the
home
command. -
Test case:
view x
wherex
is the index of a project in the list.
Expected: All tasks associated with the selected project will be displayed. -
Test case:
home
Expected: All projects should be displayed. Viewing all projects message should be displayed.
-
-
Changing view while viewing all tasks associated with a project.
-
Prerequisites: Viewing tasks for any project. Run
home
followed byview x
wherex
is the index of any project in the list. -
Test case:
view x
wherex
is the index of a task in the list.
Expected: View will not change. Message saying that you cannot use theview
command on a task will be shown. -
Test case:
home
Expected: All projects should be displayed. Viewing all projects message will be shown.
-
Finding Tasks
-
Finding projects that match a single search parameter that only contains one value.
-
Prerequisites: View all projects by running the
home
command. -
Test case:
find n/test
Expected: All projects that contain the wordtest
in their names will be displayed. -
Test case:
find match/any n/test
Expected: All projects that contain the wordtest
in their names will be displayed. -
Test case:
find match/all n/test
Expected: All projects that contain the wordtest
in their names will be displayed. -
Test case:
find d/desc
Expected: All projects that contain the worddesc
in their description will be displayed. -
Test case:
find match/any d/desc
Expected: All projects that contain the worddesc
in their description will be displayed. -
Test case:
find match/all d/desc
Expected: All projects that contain the worddesc
in their description will be displayed. -
Test case:
find t/tagA
Expected: All projects that contain the tagtagA
will be displayed. -
Test case:
find match/any t/tagA
Expected: All projects that contain the tagtagA
will be displayed. -
Test case:
find match/all t/tagA
Expected: All projects that contain the tagtagA
will be displayed. -
Test case:
find c/completed
Expected: All projects that are marked as done will be displayed. -
Test case:
find match/any c/completed
Expected: All projects that are marked as done will be displayed. -
Test case:
find match/all c/completed
Expected: All projects that are marked as done will be displayed. -
Test case:
find c/incomplete
Expected: All projects that are marked as done will be displayed. -
Test case:
find match/any c/incomplete
Expected: All projects that are not marked as done will be displayed. -
Test case:
find match/all c/incomplete
Expected: All projects that are not marked as done will be displayed.
-
-
Finding projects that match a single search parameter that only contains multiple values.
-
Prerequisites: View all projects by running the
home
command. -
Test case:
find n/test case
Expected: All projects that containtest
orcase
in their names will be displayed. -
Test case:
find match/any n/test
Expected: All projects that containtest
orcase
in their names will be displayed. -
Test case:
find match/all n/test
Expected: All projects that contain bothtest
andcase
in their names will be displayed. -
Test case:
find d/desc ription
Expected: All projects that containdesc
orription
in their descriptions will be displayed. -
Test case:
find match/any d/desc ription
Expected: All projects that containdesc
orription
in their descriptions will be displayed. -
Test case:
find match/all d/desc ription
Expected: All projects that contain bothdesc
andription
in their descriptions will be displayed. -
Test case:
find t/tagA tagB
Expected: All projects that contain the tagstagA
ortagB
will be displayed. -
Test case:
find match/any t/tagA tagB
Expected: All projects that contain the tagstagA
ortagB
will be displayed. -
Test case:
find match/all t/tagA tagB
Expected: All projects that contain both tagstagA
andtagB
will be displayed.
-
-
Finding projects that match multiple parameters that each contain multiple values.
-
Prerequisites: View all projects by running the
home
command. - Test case:
find n/test case d/desc ription t/tagA tagB
Expected: All projects that contain any one of the following will be shown:-
test
orcase
in their names. -
desc
orription
in their descriptions. - The tags
tagA
ortagB
-
- Test case:
find match/any n/test case d/desc ription t/tagA tagB
Expected: All projects that contain any one of the following will be shown:-
test
orcase
in their names. -
desc
orription
in their descriptions. - The tags
tagA
ortagB
-
- Test case:
find match/all n/test case d/desc ription t/tagA tagB
Expected: All projects that contain all of the following will be shown:- Both
test
andcase
in their names. - Both
desc
andription
in their descriptions. - Both tags
tagA
andtagB
- Both
-
Sorting Tasks
-
Sorting projects by different parameters.
-
Prerequisites: View all projects by running the
home
command. There are multiple projects in the list. -
Test case:
sort order/asc type/alpha
Expected: Projects should be sorted by their names in alphabetical, ascending order. -
Test case:
sort order/dsc type/alpha
Expected: Projects should be sorted by their names in alphabetical descending order. -
Test case:
sort order/asc type/created
Expected: Projects should be sorted by their created date in ascending order. -
Test case:
sort order/dsc type/created
Expected: Projects should be sorted by their created date in descending order. -
Test case:
sort order/asc type/deadline
Expected: Projects should be sorted in their deadlines in ascending order. Projects without a deadline will be sent to the bottom. -
Test case:
sort order/dsc type/deadline
Expected: Projects should be sorted in their deadlines in descending order. Projects without a deadline will be sent to the bottom.
-
-
Sorting tasks by different parameters.
-
Prerequisites: View all tasks by running the
home
command followed byview x
where x is the index of a project in the list. There are multiple projects in the list. -
Test case:
sort order/asc type/alpha
Expected: Tasks should be sorted by their names in alphabetical, ascending order. -
Test case:
sort order/dsc type/alpha
Expected: Tasks should be sorted by their names in alphabetical descending order. -
Test case:
sort order/asc type/created
Expected: Tasks should be sorted by their created date in ascending order. -
Test case:
sort order/dsc type/created
Expected: Tasks should be sorted by their created date in descending order. -
Test case:
sort order/asc type/deadline
Expected: Tasks should be sorted in their deadlines in ascending order. Projects without a deadline will be sent to the bottom, displayed in alphabetical ascending order. -
Test case:
sort order/dsc type/deadline
Expected: Tasks should be sorted in their deadlines in descending order. Projects without a deadline will be sent to the bottom, displayed in alphabetical descending order.
-
-
Persistence of sort
-
Prerequisites: Run
sort order/asc type/alpha
in any view. There are multiple projects in the list. -
Test case:
home
Expected: Projects should be sorted by their names in alphabetical, ascending order. -
Test case:
view x
where x is the index of a project in the list.
Expected: Tasks should be sorted by their names in alphabetical, ascending order.
-
-
Sorting by completion status in addition to a given sort order
-
Prerequisites: There are multiple projects in the list. Sort by completion status is disabled.
-
Test case:
sort order/dsc type/created c/
Expected: Entries should be sorted by completion status. Entries from each completion status will be sorted by their created date in descending order.
-
-
Ignoring completion status for a given sort order
-
Prerequisites: There are multiple projects in the list. Sort by completion status is enabled.
-
Test case:
sort order/dsc type/created c/
Expected: Entries should only be sorted by their created date in descending order.
-
Time Tracking
-
Starting Timers for Projects
-
Prerequisites: View all projects by running the
home
command. -
Test case:
start x
wherex
is the index of a project in the list.
Expected: There should be a new timer for the project at indexx
. -
Test case:
start x
where x is the greater than the number of projects.
Expected: No timer started. Invalid index message shown.
-
-
Stopping Timers for Projects
-
Prerequisites: View all projects by running the
home
command. -
Test case:
stop x
wherex
is the index of a project in the list with an active timer.
Expected: There the timer for the project at indexx
should be stopped. -
Test case:
stop x
wherex
is the index of a project in the list without an active timer.
Expected: No timer stopped. No timer running message shown. -
Test case:
stop x
where x is the greater than the number of projects.
Expected: No timer stopped. Invalid index message shown.
-
-
Starting Timers for Tasks
-
Prerequisites: View all tasks by running
home
followed byview x
command, wherex
is the index of a project in the list. -
Test case:
start x
wherex
is the index of a task in the list.
Expected: There should be a new timer for the task at indexx
. -
Test case:
start x
where x is the greater than the number of tasks.
Expected: No timer started. Invalid index message shown.
-
-
Stopping Timers for Tasks
-
Prerequisites: View all tasks by running
home
followed byview x
command, wherex
is the index of a project in the list. -
Test case:
stop x
wherex
is the index of a task in the list with an active timer.
Expected: There the timer for the task at indexx
should be stopped. -
Test case:
stop x
wherex
is the index of a task in the list without an active timer.
Expected: No timer stopped. No timer running message shown. -
Test case:
stop x
where x is the greater than the number of tasks.
Expected: No timer stopped. Invalid index message shown.
-
Undo/Redo
-
Undoing a command
-
Prerequisites: A command that can be undone has been used.
-
Test case:
undo
Expected: Actions of undone command have been reverted.
-
-
Redoing a command
-
Prerequisites: A command has been undone.
-
Test case:
redo
Expected: Actions of undone command have been redone.
-
UI Testing
-
Hiding Tag List.
-
Prerequisites: Tag list is visible.
-
Test case:
show t/
Expected: Tag list should be hidden.
-
-
Showing Tag List.
-
Prerequisites: Tag list is not visible.
-
Test case:
show t/
Expected: Tag list should be shown.
-
-
Updating tag list after find command.
-
Prerequisites: Multiple projects in the list. Tag list is visible.
-
Test case:
find n/test
Expected: Only the tags associated with the visible projects are shown.
-
-
Waiting for a reminder.
-
Prerequisites: Reminder has been set.
-
Test case: Wait till reminder time
Expected: Reminder will be displayed in the UI.
-
-
Dismissing a reminder.
-
Prerequisites: Reminder is displayed in the UI.
-
Test case:
dismiss
Expected: The reminder should no longer be visible.
-
Settings
-
Changing colour scheme.
-
Prerequisites: Program is open.
-
Test case:
set th/dark
Expected: Program should switch to dark mode if it is not already in it. -
Test case:
set th/light
Expected: Program should switch to light mode if it is not already in it.
-
-
Changing statistics time frame.
-
Prerequisites: Program is open.
-
Test case:
set st/daily
Expected: Statistics panel should displayDaily Time Spent
-
Test case:
set st/weekly
Expected: Statistics panel should displayWeekly Time Spent
-
Test case:
set st/monthly
Expected: Statistics panel should displayMonthly Time Spent
-
-
Changing statistics timeframe with no available durations.
-
Prerequisites: There are no durations available for all time frames.
-
Test case:
set st/daily
.
Expected: Time spent section should indicate that there are no durations in the list. -
Test case:
set st/weekly
.
Expected: Time spent section should indicate that there are no durations in the list. -
Test case:
set st/monthly
.
Expected: Time spent section should indicate that there are no durations in the list.
-
-
Changing statistics timeframe with available durations.
-
Prerequisites: There are no durations available for all time frames.
-
Test case:
set st/daily
.
Expected: Time spent section should display a pie chart, and a table that shows all durations associated with a project/task. -
Test case:
set st/weekly
.
Expected: Time spent section should display a pie chart, and a table that shows all durations associated with a project/task. -
Test case:
set st/monthly
.
Expected: Time spent section should display a pie chart, and a table that shows all durations associated with a project/task.
-
Exit the Program
-
Exit a program using the exit command.
-
Prerequisites: Program is open
-
Test case:
exit
Expected: Program should close.
-
-
Exit a program using the menu bar.
-
Prerequisites: Program is open
-
Test case: Click
file
followed byexit
in the menu bar.
Expected: Program should close.
-
Apendix: Effort
This section gives an overview of the total effort put into the project, challenges faced, as well as the achievements of the project.
New Features
The following new features were implemented on top of AB3:
Tasks
While AB3 only managed 1 entity type (Persons), Momentum handles 2 entity types (Projects and Tasks). Additionally, the 2 entities are related, where each project can contain any number of tasks, which further increases the complexity. Implementing this feature required major changes to all parts of the code base, as tasks needed to integrate well with both existing and new features. This also required us to make most commands context sensitive, so that they can handle different behaviours for Projects and Tasks, which required changes to the way commands are parsed and executed.
Time Tracking and Statistics
The time tracking and statistics features involved working with dates and times, which also increased the complexity of the application.
The feature involved introducing the WorkDuration
and Statistic
entities, and additional code to manage and operate on them.
The UI was also improved to display timers and statistics in a visually pleasing yet comprehensible way. Testing time
related features was also difficult, but the team overcame this by allowing for manual control of time using the Clock
class.
Reminders
The implementation of reminders was particularly difficult since required the use of threads to schedule and run tasks at different times. In addition, the way threads are run in JavaFX applications are different form normal Java applications, since the JavaFX application itself runs on threads. This made it difficult to test the reminder functions. Hence we had to use other methods to switch between running on the JavaFX platform and running it normally, to allow for testing.
Sorting
While the team could have implemented a simple alphabetical sort, the team went an extra mile to implement sorting for other parameters (deadline, created date, completion status, etc) as well. The team also allowed for both ascending and descending sort. The implementation’s complexity was further compounded by the fact that sort needed to work with undo/redo.
Undo/Redo
While AB3 provided a proposed implementation of an undo/redo feature, many changes had to be made to accomodate the new features and improvements introduced in Momentum. This meant that there were many additional considerations to be made, espcially with undoing and redoing UI related components.
Enhancements to existing features
We have also made significant enhancements to the following existing AB3 features:
Find
The team improved upon the existing AB3 find features to allow for more flexibility. Users can not only find based on name, but also other parameters like description and tags. Users can also match any, all or none of the provided parameters, as opposed to AB3 where only matching all was available. The implementation involved an almost complete change in the way find was handled. Predicate chaining was utilized to handle all the possible find types. Additional code was written to handle the parsing of the user’s commands to these predicates. The difficulty was compounded by the fact that it had to allow for undo/redo.
User Interface
The team conducted an overhaul of the AB3 UI. Since the new features implemented required much more data to be displayed to the user, it was challenging to design the UI in a way that allowed all the information to be shown while still being asthetically pleasing and user friendly.
We added some customizability in the form of a light and dark theme. Most of the fxml code for existing UI elements were changed. Each theme also required new css stylesheets. Additional commands such as the set
, show
and dismiss
commands were implemented to allow the user to change UI elements.