Overview
ZeroToOne is a desktop application that serves as an all-in-one exercise tracker and personal aide. The user interacts with it using a CLI, and it has a GUI created with JavaFX. It is written in Java, and has about 26 kLoC.
Summary of contributions
-
Major enhancement: added the Exercise Feature
-
What it does: This feature allows users to create, read, update and delete exercises and exercise sets.
-
Justification: The feature formed the base for all the other features to build upon. For example, the Workout feature required exercises to have been created first.
-
Highlights: Since this feature forms the base for all other features, the design of this feature will inevitably affect them, as well as features that will be implemented in the future. As such, I ensured that the feature is compliant with the SOLID priciples. All relevant classes are abstracted and well documented, such that each class only has one single responsibility. As such, this allows the Exercise feature to be extensible by any other developers.
-
-
Major enhancement: added the Splash Screen
-
What it does: The splash screen will load up first while the application runs through its initialisation process.
-
Justification: This enables users to feel that the application is more responsive, enhancing the user experience of the application.
-
Highlights: While the application runs locally and the loading process is relatively fast right now, the aim of this enhancement is for future-proofing purposes. It allows developers to further extend the application using other external sources such as an external DBMS, while retaining the "responsiveness" of the application.
-
Credits: Some ideas to implement this feature were taken from this tutorial created by Oracle.
-
-
Code contributed:
-
Other contributions:
-
Project management:
-
Lead release
v1.2on GitHub -
Explained the original codebase to developers
-
-
Enhancements to existing features:
-
Headed the initial code refactorisation
-
Replaced all references to AddressBook to ZeroToOne
-
Modularised the inital AddressBook-Level3 codebase that allowed developers to easily extend the project
-
Pull Request #66
-
-
-
Documentation:
-
Helped Chi Shan with the editing of the User Guide and Developer Guide to ensure that the English used is friendly and simpler to understand.
-
Edited high-level UML Diagrams of the application to fit the latest update. Pull Request #228
-
-
Community:
-
Tools:
-
Contributions to the User Guide
Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users. |
Managing Your Exercises [Aloysius Chan]
The commands in this section allows you to manage your customised exercises in ZeroToOne. These exercises will eventually be the building blocks of a workout.
Creating a new exercise
To create a new exercise in ZeroToOne, simply enter this command into the command box:
exercise create e/<exercise_name>
Example use:
exercise create e/squat
The newly created exercise will be automatically added to the bottom of the exercise list. This exercise will not contain any sets at this point.
NOTE: <exercise_name> has to be a string, consisting of only alphanumeric characters
Adding a set to an exercise
After you have created a new exercise in ZeroToOne, the next step is to add a set to the exercise! To add a set, simply enter this command:
exercise set add EXERCISE_ID r/<num_of_reps> m/<weight>
Example use:
exercise set add 2 r/2 m/30
The exercise set will be automatically appended to the current list of sets in the exercise. The user interface will be updated to show the edited exercise.
NOTE:
-
This command assumes that you have already created an exercise under
EXERCISE_ID. If you have not created the exercise, refer to the section on “Creating a new exercise” first. -
EXERCISE_IDrefers to the index of the exercise inexercise list -
<num_of_reps>should be a positive integer -
<weight>should be a positive integer between 1 and 1000
Editing a set in an exercise
Changed your mind on the details of an exercise set? No worries, you can edit the information in an exercise set by simply entering this command:
exercise set edit EXERCISE_ID SET_ID r/<num_of_reps> m/<weight>
Example use:
exercise set edit 1 1 r/20 m/30
The exercise set will be automatically updated in the exercise list. If so, the following message will be displayed in the feedback display:
Edited exercise set: Deadlift
NOTE:
-
EXERCISE_IDrefers to the index of the exercise inexercise list -
SET_IDrefers to the index of the set in the exercise -
<num_of_reps>has to be a positive integer -
<weight>has to be a positive integer between 1 and 1000
Deleting a set in an exercise
Want to delete an exercise set from the exercise? You can do so by simply entering this command:
exercise set delete EXERCISE_ID SET_ID
Example use:
exercise set delete 1 2
The exercise set will be removed from the exercise, and the view will automatically update to show that the exercise no longer contains that set. If this is successful, the following message will be displayed in the feedback display:
Deleted Exercise Set: Deadlift
NOTE:
-
EXERCISE_IDrefers to the index of the exercise inexercise list -
SET_IDrefers to the index of the set in the exercise
Listing all exercises
To show a list of exercises that you have created in ZeroToOne, simply enter this command into the command box:
exercise list
The User Interface will automatically switch to the “Exercise” tab, and the result display will automatically update with the list of exercises.
Finding an exercise by name
To find and view the information of a particular exercise that you have previously created, you can simply enter this command:
exercise find e/<exercise_name>
Example use:
exercise find e/Bench Press
The Result Display will automatically update to only show exercises that match the search keyword.
NOTE:
-
<exercise_name>has to be a String, consisting of only Alphanumeric characters -
<exercise_name>can be a partial substring of the full exercise name -
<exercise_name>is not case-sensitive
Changing an exercise’s name
Made a mistake while creating the exercise’s name? You can change the exercise name by simply running this command in the command box:
exercise edit EXERCISE_ID e/<exercise_name>
Example use:
exercise edit 1 e/Squat
The exercise in ZeroToOne will be automatically updated to show its new name. If this is successful, the following message will be displayed in the feedback display:
Edited exercise: Squat
NOTE:
-
EXERCISE_IDrefers to the index of the exercise inexercise list -
<exercise_name>has to be a String, consisting of only Alphanumeric characters
Deleting an exercise
Want to remove an exercise from ZeroToOne? You can do so by entering this command into the command box:
exercise delete EXERCISE_ID
Example use:
exercise delete 1
The exercise will be removed from ZeroToOne. At the same time, all current workouts that contain this exercise will also have this exercise removed. If this is successful, the following message will be displayed in the feedback display:
Deleted Exercise: Deadlift
NOTE:
-
EXERCISE_IDrefers to the index of the exercise inexercise list
Contributions to the Developer Guide
Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project. |
Exercise [Aloysius Chan]
Overview
The Exercise feature forms the basic building block for the application. It allows users to CRUD exercises, which will then be used for the creation of workouts. The command is prefixed by the keyword exercise. Available commands are create, edit, list, delete and many more.
Implementation
The following portion will explain in-detail each component of the Exercise feature.
Model
The figure above depicts the Model of the Exercise feature. Starting from the most primitive type:
-
NumRepsstores the number of repetitions a person has to complete for a particular exercise set -
Weightstores the weight in kg that a person has to complete for a particular exercise set -
ExerciseSetrepresents an exercise set that a person has to complete. EachExerciseSetcomprises of exactly 1NumRepsobject and 1Weightobject -
ExerciseNamestores the name of a particular exercise -
Exerciserepresents a collection of exercise sets that a person has to complete. EachExercisewill consists of exactly 1ExerciseNameobject and any number ofExerciseSet(including zero) -
UniqueExerciseListrepresents a collection ofExerciseobjects. There can be any number ofExerciseobjects inUniqueExerciseList, but they must be unique. -
ExerciseListimplements the interfaceReadOnlyExerciseListthat ensures that the outward-facing exercise list is unmodifiable by other modules. TheExerciseListobject has exactly 1UniqueExerciseListfor storage purposes. -
ExerciseListis controlled by theModelManager.
Do note that some of the Exercise objects in the ExerciseList are also referenced in the WorkoutList. For more information, refer to the Workout implementation.
Storage
The Storage component provides the functionalities that enable the persistent storage of the model. Starting from the most primitive type:
-
JacksonExerciseSetcontains exactly twoStringobjects, one for the number of repetitions and one for the weight. This class has a dependency to theNumRepsandWeightmodel due to thetoModelType()function. This function convertsJacksonExerciseSetinto the model’sExerciseSetso that it can be used in other parts of the application. -
JacksonExercisecontains exactly oneStringobject that represents the exercise name, and any number ofJacksonExerciseSetobjects. Similarly, it has a dependency toExerciseName,ExerciseSetandExerciseobject due to thetoModelType()function. -
JacksonExerciseListis the persistent storage for theExerciseListmodel, and it contains any number ofJacksonExerciseobjects. -
ExerciseListStorageManagerimplements theExerciseListStoragewhich provides certain functionalities required for the storage to work properly. TheExerciseListStorageManageris controlled by theStorageManager.
Logic - Commands
The Exercise Commands package stores the business logic of the exercise feature. The commands are organised in a hierarchical fashion, in the order of precedence in a valid input. For example, SetCommand inherits from ExerciseCommand as the set comes after exercise in the input exercise set.
Each command contains a COMMAND_WORD which is a single word that is unique to the command. Each command also implements an execute method that represents the logic of the command. Instructions to control the model, storage and view are stored inside this method.
Logic - Parsers
The parsers are responsible for parsing a user input into a Command object. For the Exercise component, there are parsers for every command that accepts user arguments. For example, since exercise list does not take in any argument, there is no parser for the ListCommand. After parsing the user input, the parser will return Command object to the caller, which will execute the command via the execute method.
Sample Command Execution
This section will illustrate an example of an exercise command execution using the input exercise create e/Bench Press.
In this portion, we will trace the sequence diagram of the exercise create command to better understand the internals of the Exercise feature.
-
The user enters the command
exercise create e/Bench Press -
LogicManagerwill pass the command to theParserManagerfor parsing -
ParserManagerupon seeing that the command is prefixed byexercisecreates aExerciseCommandParser -
ParserManagerthen passcreate e/Bench PresstoExerciseCommandParser -
ExerciseCommandParserupon seeing that the command is prefixed bycreatecreates aCreateCommandParser -
ExerciseCommandParserthen pass the argumente/Bench PresstoCreateCommandParser -
CreateCommandParserthen attempts to create anExerciseNameobject using theStringin the argument -
Using the
ExerciseName,CreateCommandParserthen create aCreateCommandobject with the exercise name -
The
CreateCommandis then passed back to theLogicManager -
LogicManagercallsc.execute() -
CreateCommandwill attempt to create anExerciseusing the exercise name -
After creating the
Exerciseobject, theCreateCommandwill attempt to store the new exercise by calling theaddExercisemethod ofModel -
After the exercise is successfully added, a
CommandResultobject is created -
This result is then passed back to the
LogicManagerwhich will display the output on the GUI
Summary
At this point, you should have gather enough information to start developing the Exercise feature. As a summary, this is a sample Activity Diagram that depicts a user flow when they want to edit an exercise set.
Design Considerations
Parser Component
One of the consideration while designing was that the commands in exercise are extremely nested. We have commands such as exercise set create r/1 m/10. While we could have chucked all the parsing in ExerciseSetCreateParser class, we realised that it will be better if we were to abstract the parser into separate classes. This allows us to group the functionalities of the parser in a single file. For example, ExerciseCommandParser will parse any string that has the word exercise as the prefix. SetCommandParser will do so for a prefix of set. This means that for the above command, while we have to go through multiple parsers which can make the performance of the application suffer, each of the parsers have a single responsibility which makes it a better design choice.
Model Component
For the Model component, note that Exercise objects are supposed to be unique whereas ExerciseSet objects are not. This is created due to our observations of the workout regimes in the real world.
For ExerciseSet, while set weights and number of repetitions tend to vary during an exercise, users may want to have the freedom to do multiple sets with the same configuration during the course of the exercise. Hence, it is unwise to make it unique.
However, for exercises, we noted that users tend to reuse the same exercise throughout different workout plans. At the same time, there is a high chance of users creating duplicate exercises when the number of exercises in the application increases significantly. Therefore, we chose to make Exercise a unique object instead.