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: I implemented the Scheduler core feature of ZeroToOne.
-
What it does: allows the user to schedule workout sessions.
-
Justification: this feature is essential to the product as it enable user to make plans of their workout sessions, stick to the plans and finally achieve a life transformation.
-
Highlights: this feature affects efficiency and responsiveness if not implemented correctly. It required careful consideration and analysis of design alternatives. The implementation itself was challenging because it required implementation of a fairly complex model as well as its storage.
-
-
Minor enhancement: Created a DateTime class and its utility functions for team members' usage to standardize datetime formatting across the app and compare different datetime objects easily.
-
Code contributed on RepoSense:
-
Overview: [RepoSense]
-
Functional Code: [Commands] [Parsers] [Models] [Storage] [UI] [FXML]
-
Tests: [Commands Tests] [Parsers Tests] [Models Tests] [Storage Tests]
-
-
Other contributions:
-
Project management:
-
Organised and facilitated brainstorming sessions at the inception of the tP.
-
Proposed and finalized the overall fitness theme of the app and its epic features.
-
Facilitated delegation of epic features to each team members.
-
-
Enhancements to existing features:
-
Community:
-
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 Scheduled Sessions [Tang Guofeng]
You are now an expert in managing your workouts, and can start a workout any time! However, wouldn’t you like to have the ability to schedule your workout sessions? In this section, we will guide you to learn how ZeroToOne can help you in this aspect!
Scheduling a new workout session
To schedule a new workout session, simply type in this command:
schedule create WORKOUT_ID d/<datetime>
Example use:
schedule create 1 d/2020-10-06 18:00
NOTE:
* WORKOUT_ID refers to the index of the workout in `workout list`
* <datetime> must not be outdated and follow the format {yyyy}-{mm}-{dd} {HH:mm}
Listing all scheduled sessions [Tang Guofeng]
To view all of your schedule sessions, type the following command:
schedule list
ZeroToOne displays an intuitive chronological view, showing your upcoming schedule! From this view, you can see what workout sessions are coming up, which workout sessions are outdated, as well as their corresponding schedule IDs.
Changing a scheduled session to another date
If you need to shift your scheduled session to another date, try the following command:
schedule edit SCHEDULED_WORKOUT_ID d/<datetime>
Example use:
schedule edit 1 d/2020-05-08 18:00
If this is successful, the following message will be displayed in the feedback display:
Edited schedule: Strength Workout on 2020-05-08 18:00
NOTE:
* SCHEDULED_WORKOUT_ID refers to the index of the scheduled workout in `schedule list`
* <datetime> must not be outdated and follow the format {yyyy}-{mm}-{dd} {HH:mm}
Deleting a scheduled session
Want to delete a scheduled session? You can do so by typing the following command:
schedule delete SCHEDULED_WORKOUT_ID
Example use:
schedule delete 1
This deletes an existing scheduled workout session with the corresponding scheduled workout ID. If this is successful, the following message will be displayed in the feedback display:
Deleted scheduled workout: Strength Training
NOTE:
* SCHEDULED_WORKOUT_ID refers to the index of the scheduled workout in `schedule list`
Scheduling a recurring workout session (Coming in v2.0)
Sometimes you will want to schedule a workout session that repeats over time, with a certain frequency. No problem! Simply type the following command:
schedule recurring create WORKOUT_ID d/<datetime> f/<frequency>
Example use:
schedule recurring create WORKOUT_ID d/2020-05-26 10:00 f/MONTHLY
For example, if you want to have the workout Arms Workout on a monthly basis, starting from the 26th of May 2020 at 10am, you can type schedule recurring create WORKOUT_ID d/2020-05-26 10:00 f/MONTHLY
. If this is successful, the following message will be displayed in the feedback display:
New recurring schedule added: Strength Workout on 2020-05-06 18:00 Monthly
NOTE:
* WORKOUT_ID refers to the index of the workout in `workout list`
* <datetime> must not be outdated and follow the format {yyyy}-{mm}-{dd} {HH:mm}
* <frequency> must be one of the following: DAILY, WEEKLY, MONTHLY
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. |
Schedule [Tang Guofeng]
Overview
The schedule feature in ZeroToOne allows users to plan their workouts! Users will be able to create a schedule on a specific date and time in the future, edit the date and time, as well as delete the schedule.
This is an activity diagram for the user to create a new schedule. First, the user will try to find workout to schedule, and if their desired workout cannot be found, the user will create one and schedule them on a specified date.
Components
The following class diagram shows the overview of the Scheduler
:
As seen in the diagram above, the Scheduler
consists two lists, ScheduleList
and ScheduledWorkoutList
.
The ScheduleList
contains a number of Schedule
that the user has created, while the ScheduledWorkoutList
is essentially a chronologically sorted list of ScheduledWorkout
that allows JavaFX listeners to track changes when they occur.
The decision to have both ScheduleList and ScheduledWorkoutList may seem bizarre at first glance, but it is implemented this way after careful consideration, to better support operations on 'RecurringSchedule'(Proposed). Refer to Model Design Considerations for more information.
|
Schedule Model
ZeroToOne’s Model
extends the SchedulerModel
. Here are all the functions to carry out schedule-related activities:
-
Model#hasSchedule(Schedule schedule)
- Returns true if a schedule exists in the schedule list -
Model#addSchedule(Schedule schedule)
- Adds a new schedule to the schedule list -
Model#setSchedule(Schedule scheduleToEdit, Schedule editedSchedule)
- Replaces a particular schedule with an edited schedule -
Model#populateSortedScheduledWorkoutList()
- Clear and populateSortedScheduledWorkoutList
by querying everySchedule
inSchedueList
through methodSchedule#getScheduledWorkout()
-
Model#getSortedScheduledWorkoutList()
- Returns an unmodifiable view ofObservableList<ScheduledWorkout>
-
Model#deleteScheduledWorkout(ScheduledWorkout scheduledWorkoutToDelete)
- Deletes theSchedule
that generated the specifiedScheduledWorkout
from the schedule list, then re-populatesSortedScheduledWorkoutList
-
Model#deleteWorkoutNameFromSchedule(WorkoutName workoutNameToDelete)
- Deletes all instances of schedules that are associated with the specified workout name -
Model#editWorkoutNameInSchedule(WorkoutName workoutNameToEdit, WorkoutName editedWorkoutName)
- Updates all instances of schedules that are associated with the specified workout name to the new workout name -
Model#getScheduleList()
- Returns an unmodifiableReadOnlyScheduleList
Command Execution
Creating a Schedule
To illustrate an example of a command from the Scheduler
, the following sequence diagram depicts flow of the program when the command schedule create 1 d/2020-04-01 14:00
is run.
-
When the user runs the command
schedule create 1 d/2020-04-01 14:00
, theLogicManager
will first take in the command, by calling theexecute()
function on it. -
The
ParserManager
then has toparse("schedule create 1 d/2020-04-01 14:00")
. -
Next, the
ScheduleCommandParser
has toparse("create 1 d/2020-04-01 14:00")
for the command. -
Once the command has been parsed as a
CreateCommand
, it will be passed on to theCreateCommandParser
, which will then parse the index usingParserUtil
, and parse the date and time usingScheduleParserUtil
. -
The
CreateCommandParser
can then create aCreateCommand
, which is then passed back toLogicManager
to execute. -
When
LogicManager
executes theCreateCommand
, it creates a newSchedule
, and checks whether the model already contains thisSchedule
. -
If the model does not contain this
Schedule
, theLogicalManager
will then add it to the model by callingModel#addSchedule(schedule)
. -
Finally, the resulting output message will be returned as the
CommandResult
.
Date and time must not be outdated and follow the format {yyyy}-{mm}-{dd} {HH:mm} |
Populating the SortedScheduledWorkoutList
And the following sequence diagram shows how the ScheduledWorkoutList
is populated after the method Model#addSchedule(schedule)
is called:
SortedScheduledWorkoutList
-
After the
LogicManager
calls the methodModel#addSchedule(schedule)
,ModelManager
callsScheduler#addSchedule(schedule)
, which in turns callsScheduleList#addSchedule(schedule)
and adds theSchedule
in theScheduleList
. -
The
Scheduler
will then populate theScheduledWorkoutList
by calling the methodpopulateSortedScheduledWorkoutList()
. -
First,
Scheduler
gets the current date and time by callingDateTime#now()
. -
Then,
Scheduler
iterates through everySchedule
inScheduleList
, and requests to getScheduledWorkout
by callingSchedule#getScheduledWorkout(now)
on each of them. -
Finally,
Scheduler
resets theSortedScheduledWorkoutList
with the latestScheduledWorkout
by callingScheduledWorkoutList#setScheduledWorkouts(scheduledWorkouts)
, and user’s view ofScheduledWorkout
is refreshed. -
And in the end, the resulting output message will be passed back to
LogicManager
and display to user.
Scheduler#populateSortedScheduledWorkoutList() is called whenever the schedules in ScheduleList have been changed.
|
Model Design Considerations
Aspect: How to handle editing and deletion of recurring schedules
-
Option 1:
Model
stores onlyScheduledWorkout
objects.-
Pros: Easier to implement.
-
Cons: Harder to maintain when it comes to
edit
ordelete
of recurring scheduled workouts.
-
-
Option 2 (current choice): Saves
Schedule
objects that can be used to produceScheduledWorkout
when requested.-
Pros: Changes can be made to recurring schedules instead, and in turn reflect in all related
ScheduledWorkout
. -
Cons: Makes model much more complicated.
-
In the end, I decided to go with option 2 as it is easier to maintain, more extensible and less computationally expensive.
When the system has a number of recurring schedules that do not have an end date, it introduces a few problems:
-
How many scheduled workouts to create/store for each recurring schedule
-
How to efficiently retrieve and update all related scheduled workouts when a recurring schedule is edited or deleted
Implementing option 1 would mean that we will have to impose an additional constraint onto the system, which is either how many scheduled workouts to display for each recurring schedule or what is the longest time frame of scheduled workouts to display to user, as we simply can’t generate indefinite number of scheduled workouts for technically everlasting recurring schedules. Additionally, when the number of high frequency recurring schedules in the system increases, it will be extremly computationally expensive to edit or delete recurring schedules, as the system will have to iterate through every ScheduledWorkout objects and update accordingly.
On the other hand, implementing option 2 makes it easier to handle these problems by storing changes to the Schedule objects instead, which can be used to generate ScheduleWorkout objects when requested. Moreover, it is more extensible because if we are going to introduce a calendar view in the future, where user can view a specific time frame of scheduled workouts, the system only needs to generate for that time frame only, which can be done much more efficiently!