Developer Guide
- Setting up, getting started
- Design
- Implementation
- Documentation, logging, testing, configuration, dev-ops
- Appendix: Requirements
- Appendix: Instructions for manual testing
Setting up, getting started
Refer to the guide Setting up and getting started.
Design
Architecture
The Architecture Diagram given above explains the high-level design of the App. Given below is a quick overview of each component.
.puml
files used to create diagrams in this document can be found in the diagrams folder. Refer to the PlantUML Tutorial at se-edu/guides to learn how to create and edit diagrams.
Main
has two classes called Main
and MainApp
. It is responsible for,
- At app launch: Initializes the components in the correct sequence, and connects them up with each other.
- At shut down: Shuts down the components and invokes cleanup 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
.
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
, LogListPanel
, StatusBarFooter
etc. All these, including the MainWindow
, inherit from the abstract UiPart
class.
The UI
component uses JavaFx UI framework. The layout of these UI parts are defined in matching .fxml
files that are in the src/main/resources/view
folder. For example, the layout of the MainWindow
is specified in MainWindow.fxml
The UI
component,
- Executes user commands using the
Logic
component. - Listens for changes to
Model
data so that the UI can be updated with the modified data.
Logic component
API :
Logic.java
-
Logic
uses theFixMyAbsParser
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 log). - 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.
DeleteCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Model component
API : Model.java
The Model
component,
- stores a
UserPref
object that represents the user’s preferences. - stores the logbook data.
- exposes unmodifiable lists
ObservableList<Log>
andObservableList<Exercise>
that can be ‘observed’ e.g. the UI can be bound to these lists so that the UI automatically updates when the data in these lists change. - does not depend on any of the other three components.
Storage component
API : Storage.java
The Storage
component,
- can save
UserPref
objects in json format and read it back. - can save the logbook data in json format and read it back.
Common classes
Classes used by multiple components are in the seedu.fma.commons
package.
Implementation
This section describes some noteworthy details on how certain features were implemented.
Add Exercise feature
The adding of Exercises is one of the core functionalities of FixMyAbs. Apart from the generic exercises provided when users first start the app, users are also able to add their own exercises, which makes FixMyAbs customizable and more suited to each user’s specific needs.
The mechanism is facilitated by an Exercise
class. An Exercise
class has Name
and Calories
. Calories represent the number of calories burnt per rep of the exercise.
A user can add an Exercise
to the LogBook
by executing the addex
command.
Example usage scenario
Given below is an example usage scenario and how the add exercise
mechanism behaves at each step after launching the application.
Step 1. The user executes the command addex e/Jumping kicks c/2
. FixMyAbsParser
creates a new AddExCommandParser
and calls the AddExCommandParser#parse()
method.
Step 2. The user input is passed into the AddExCommandParser#parse()
method and instances of Name
and Calories
are created using the ParserUtil
class, from user input. These new instances are passed as parameters to the Exercise
constructor, and a new Exercise
object is created as a result.
Step 3. A new AddExCommand
is returned with the created Exercise
object as an attribute. The Exercise
object is then added to the Model
.
The following sequence diagram shows how the Add Exercise
feature works:
AddExCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Add Log feature
The adding of Logs are the core to the functionality of FixMyAbs. Users are able to add information related to that exercise log, which will then allow them to track their fitness progress and details regarding their workout.
The mechanism is facilitated by a Log
class. A Log
class has Exercise
, Rep
, Comment
and LocalDateTime
.
A user can add a Log
to the LogBook
by executing the add
command.
Example usage scenario
Given below is an example usage scenario and how the add log
mechanism behaves at each step after launching the application.
Step 1. The user executes the command add e/Pushups r/50 c/Managed to increase to 50 reps today!
. FixMyAbsParser
creates a new AddCommandParser
and calls the AddCommandParser#parse()
method.
Step 2. The user input is passed into the AddCommandParser#parse()
method and instances of Exercise
, Rep
and Comment
are created using the ParserUtil
class, from user input. These new instances are passed as parameters to the Log
constructor, and a new Log
object is created as a result. Each Log
instantiates with a new dateTime
field, which calls the LocalDateTime#now()
method alongside the current system clock of the user’s computer.`
Step 3. A new AddCommand
is returned with the created Log
object as an attribute. The Log
object is then added to the Model
.
The following sequence diagram shows how the Add Log
feature works:
AddCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Find Log feature
To find specific logs, users are able to search for logs based on certain keywords. This will allow them to easily find logs with a certain exercise, as well as any of its details.
NameContainsKeywordsPredicate
supports this command.
NameContainsKeywordsPredicate#test()
checks if a Log contains all the keywords in the user input.
A user can thus find a Log
by executing the find
command.
Example usage scenario
Given below is an example usage scenario and how the find
command behaves at each step after launching the application.
Step 1. The user executes the command find Push ups
. FixMyAbsParser
creates a new FindCommandParser
and calls the FindCommandParser#parse()
method.
Step 2. The user input is passed into the FindCommandParser#parse()
method, which then creates a new NameContainsKeywordsPredicate
object, with the user input as the parameter. This object checks if there is a match between the keyword and the tested Log
.
Step 3. As a result of the FindCommandParser#parse()
method, a new FindCommand
is returned with the created NameContainsKeywordsPredicate
object as an attribute. Upon calling FindCommand#execute()
, the model is updated through Model#updateFilteredLogList()
, and the new filtered log list is displayed to the user.
The following sequence diagram shows how the find
feature works:
FindCommandParser
should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
Autocomplete feature
Autocomplete feature uses following classes:
-
ResultDisplay
- Displays user input. -
CommandBox
- CommandBox which consists ofcommandTextField
-
LogicManager
- Implements logic between models and user interface
Below is how it works:
Step 1. User enters command add
.
Step 2. commandTextField
in CommandBox
detects changes in the user input and parse the input into
showAutoCompleteResult()
method in ResultDisplay
Step 3: ResultDisplay
executes method setText
which executes getAutoCompleteResult
method.
Step 4: getAutoCompleteResult
computes the result to display to the user and returns the String result
.
Step 5: setText
method in ResultDisplay
receives the result
as a parameter and display the result
for the user.
Better user interface
We changed and improve the user interface to support exercise by adding ExerciseListCard
and ExerciseListPanel
which is similar to LogListCard
and LogListPanel
to the
MainWindow
.
The UI
component works the same
- Executes user commands using the
Logic
component. - Listens for changes to
Model
data so that the UI can be updated with the modified data.
The design looks like:
Documentation, logging, testing, configuration, dev-ops
Appendix: Requirements
Product scope
Target user profile:
- has a need to keep track of exercises done
- has a need to keep track of calories burnt over time
- prefer desktop apps over other types
- can type fast
- prefers typing to mouse interactions
- is reasonably comfortable using CLI apps
Value proposition: simple and quick way to monitor exercises and quantify fitness progress
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 | see usage instructions | refer to instructions when I forget how to use the App |
* * * |
user | add an exercise | track what I have done in the app |
* * * |
user | delete a log | remove exercises that I no longer want to track |
* * * |
user | update an exercise | edit what the app is tracking |
* * * |
user | list exercises | view what the app is tracking |
* * |
impatient user | have quick app response times | not waste time waiting for it to load |
* * |
new user | see the app populated with sample data | view what the app will looks like when there is input |
* * |
user ready to use the app | reset all current data | begin using the app for real without any sample data |
* * |
busy user | use my keyboard to log exercises | log exercises as quickly as possible |
* * |
forgetful user | have easy to remember input commands | use the app quickly without constantly referring to the manual |
* * |
indecisive user | view a list of exercises I can do | start exercising without having to think of what to do |
* |
user | have a graph showing my calories burnt over time | see if I am making progress |
* |
user | view the calories I have burnt over time | feel a sense of accomplishment |
* |
tech savvy user | import my own list of exercises | view and track it in the application |
* |
unmotivated user | have reminders of the last time I exercised | feel more motivated to start exercising again |
* |
careless user | be able to undo actions | fix any mistakes I may have done regarding input |
Use cases
(For all use cases below, the System is FixMyAbs
and the Actor is the user
, unless specified otherwise)
Use case: UC01 - Create a log
MSS
- User requests to create a specific log
- FixMyAbs creates the log
-
FixMyAbs shows a success message
Use case ends.
Extensions
-
1a. The given exercise does not exist.
-
1a1. FixMyAbs shows an error message.
Use case resumes at step 1.
-
-
1b. The given reps is invalid.
-
1b1. FixMyAbs shows an error message.
Use case resumes at step 1.
-
Use case: UC-02 - Edit a log
MSS
- User requests to list all logs
- FixMyAbs shows a list of all recorded logs
- User requests to edit a specific log in the list
- FixMyAbs edits the log according to user specifications
-
FixMyAbs shows a success message
Use case ends.
Extensions
-
2a. The list of logs is empty.
-
2a1. FixMyAbs shows an error message.
Use case ends.
-
-
3a. The given index is invalid.
-
3a1. FixMyAbs shows an error message.
Use case resumes at step 2.
-
Use case: UC03 - Delete a log
MSS
- User requests to list all logs
- FixMyAbs shows a list of all recorded logs
- User requests to delete a specific log in the list
- FixMyAbs deletes the log
-
FixMyAbs shows a success message
Use case ends.
Extensions
-
2a. The list of logs is empty.
-
2a1. FixMyAbs shows an error message.
Use case ends.
-
-
3a. The given index is invalid.
-
3a1. FixMyAbs shows an error message.
Use case resumes at step 2.
-
Use case: UC04 - Find logs
MSS
- User requests to find all logs that contain specific keywords
-
FixMyAbs shows a list of all recorded logs that contain all the specified keywords
Use case ends.
Extensions
-
1a. No keywords are given.
-
1a1. FixMyAbs shows an error message.
Use case resumes at step 1.
-
Use case: UC05 - Create an exercise
MSS
- User requests to create a specific exercise
- FixMyAbs creates the exercise
-
FixMyAbs shows a success message
Use case ends.
Extensions
-
1a. The given exercise already exists.
-
1a1. FixMyAbs shows an error message.
Use case resumes at step 1.
-
-
1b. The given calories per rep is invalid.
-
1b1. FixMyAbs shows an error message.
Use case resumes at step 1.
-
Use case: UC06 - Edit an exercise
MSS
- User requests to edit the calories per rep of an existing exercise.
- FixMyAbs edits the indicated exercise
-
FixMyAbs shows a success message
Use case ends.
Extensions
-
1a. The given new exercise name exists.
-
1a1. FixMyAbs shows an error message.
Use case resumes at step 1.
-
-
1b. The given calories per rep is invalid.
-
1b1. FixMyAbs shows an error message.
Use case resumes at step 1.
-
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 exercises 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.
- Response time and processing time for user input should be under 0.1s.
- Startup and showdown times should be under 1.0s.
Glossary
- Mainstream OS: Windows, Linux, Unix, OS-X
Appendix: Instructions for manual testing
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 logs and exercises. The window size may not be optimum.
-
-
Saving window preferences
-
Resize the window to an optimum size. Move the window to a different location. Close the window.
-
Re-launch the app by double-clicking the jar file.
Expected: The most recent window size and location is retained.
-
Creating a log
-
Creating a log
-
Prerequisites: At least one exercise in the exercise list.
-
Test case:
add e/Sit ups r/1 c/my abs hurt :(
Expected: A log with the specified details is created and displayed in the log list. Details of the created log shown in the status message. -
Test case:
add e/Sit ups
Expected: No log is created. Error details shown in the status message. -
Other incorrect add commands to try:
add
,add e/x r/1 c/my abs hurt :(
(where x is an exercise that does not exist)
Expected: Similar to previous.
-
Editing a log
-
Editing a log while all logs are being shown
-
Prerequisites: List all logs using the
list
command. Multiple logs in the list. -
Test case:
edit 1 c/no abs were hurt
Expected: Edits the log at index 1, with a comment ofno abs were hurt
. Details of the edited log shown in the status message. -
Test case:
edit 1 r/20 c/no abs were hurt
Expected: Edits the log at index 1, with reps of20
and a comment ofno abs were hurt
. Details of the edited log shown in the status message. -
Test case:
edit 1
Expected: No log is edited. Error details shown in the status message. -
Other incorrect edit commands to try:
edit
,edit x ...
(where x is an integer larger than the list size or less than 1)
Expected: Similar to previous.
-
Deleting a log
-
Deleting a log while all logs are being shown
-
Prerequisites: List all logs using the
list
command. Multiple logs in the list. -
Test case:
delete 1
Expected: First log is deleted from the list. Details of the deleted log shown in the status message. -
Test case:
delete 0
Expected: No log is deleted. Error details shown in the status message. -
Other incorrect delete commands to try:
delete
,delete x
(where x is an integer larger than the list size or less than 1)
Expected: Similar to previous.
-
Adding an exercise
-
Adding an exercise in the shown exercises list.
-
Prerequisites: No prerequisites, you can add an exercise in any state of FixMyAbs.
-
Test cases:
addex e/High jump c/100
. Expected: The exercise with name asHigh jump
and calories per rep as 100 is added to the end of the exercise list. -
Test case:
addex e/ c/
Expected: No exercise is added. Error details shown in the status message. -
Other incorrect addex commands to try:
addex e/High jump c/0
,addex c/123
.
-
Deleting an exercise
-
Deleting an exercise in the shown exercises list.
-
Prerequisites: No prerequisites, you can delete an exercise in any state of FixMyAbs.
-
Test case:
delete 1
Expected: First exercise is deleted from the list. Details of the deleted exercise shown in the status message. -
Test case:
delete 0
Expected: No exercise is deleted. Error details shown in the status message. -
Other incorrect delete commands to try:
delete
,delete x
(where x is larger than the list size or less than 1)
Expected: Similar to previous.
-
Editing an exercise
-
Editing an exercise
-
Prerequisites: No prerequisites, you can delete an exercise in any state of FixMyAbs.
-
Test case:
editex 1 e/High jump
Expected: Edits the exercise at index 1, with a comment ofHigh jump
. Details of the edited exercise shown in the status message. -
Test case:
editex 1 c/123 e/High jump
Expected: Edits the exercise at index 1, with name ofHigh jump
and calories per rep of123
. Details of the edited exercise shown in the status message. -
Test case:
edit 1
Expected: No exercise is edited. Error details shown in the status message. -
Other incorrect edit commands to try:
edit
,edit x ...
(where x is larger than the list size or less than 1)
Expected: Similar to previous.
-
Saving data
-
Saving data upon shutdown
-
Make some changes in the app.
-
Close the window or use the
exit
command. -
Re-launch the app by double-clicking the jar file.
Expected: All changes should be saved.
-
-
Dealing with missing/corrupted data files
-
Locate the local data file
.\data\logbook.json
. -
Test case: Delete the file. Launch the app by double-clicking the jar file.
Expected: A new data file will be created with a set of sample logs and exercises. -
Test case: Corrupt the file (e.g. delete an attribute of a log). Launch the app by double-clicking the jar file.
Expected: The app will startup without any data.
-