PROJECT: ZeroToOne

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:

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

      • Help refactor and create modular exercise list application (Pull request #66)

      • Enchancement to the GUI of Schedule tab (Pull requests #221, #172)

      • Wrote sufficient tests for scheduler features to increase its code coverage (except UI) to near 100% (Pull requests #192)

    • Community:

      • PRs reviewed (with non-trivial review comments): #103, #174, #192

      • Total PRs reviewed: 18+

      • I advocated standardized git workflow to my team and regularly helped troubleshoot git related errors for my teammates.

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
UgScheduleSession
Figure 1. Scheduling a workout session
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
UgListSchedule
Figure 2. Display of schedule in chronological order

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.

ScheduleActivityDiagram
Figure 3. Activity Diagram for Creating a 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:

ModelScheduleClassDiagram
Figure 4. Scheduler Class Diagram

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 populate SortedScheduledWorkoutList by querying every Schedule in SchedueList through method Schedule#getScheduledWorkout()

  • Model#getSortedScheduledWorkoutList() - Returns an unmodifiable view of ObservableList<ScheduledWorkout>

  • Model#deleteScheduledWorkout(ScheduledWorkout scheduledWorkoutToDelete) - Deletes the Schedule that generated the specified ScheduledWorkout from the schedule list, then re-populates SortedScheduledWorkoutList

  • 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 unmodifiable ReadOnlyScheduleList

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.

ScheduleCreateSequenceDiagram
Figure 5. Sequence Diagram for Creating a Schedule
  1. When the user runs the command schedule create 1 d/2020-04-01 14:00, the LogicManager will first take in the command, by calling the execute() function on it.

  2. The ParserManager then has to parse("schedule create 1 d/2020-04-01 14:00").

  3. Next, the ScheduleCommandParser has to parse("create 1 d/2020-04-01 14:00") for the command.

  4. Once the command has been parsed as a CreateCommand, it will be passed on to the CreateCommandParser, which will then parse the index using ParserUtil, and parse the date and time using ScheduleParserUtil.

  5. The CreateCommandParser can then create a CreateCommand, which is then passed back to LogicManager to execute.

  6. When LogicManager executes the CreateCommand, it creates a new Schedule, and checks whether the model already contains this Schedule.

  7. If the model does not contain this Schedule, the LogicalManager will then add it to the model by calling Model#addSchedule(schedule).

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

PopulateSortedScheduledWorkoutList
Figure 6. Sequence Diagram for Populating SortedScheduledWorkoutList
  1. After the LogicManager calls the method Model#addSchedule(schedule), ModelManager calls Scheduler#addSchedule(schedule), which in turns calls ScheduleList#addSchedule(schedule) and adds the Schedule in the ScheduleList.

  2. The Scheduler will then populate the ScheduledWorkoutList by calling the method populateSortedScheduledWorkoutList().

  3. First, Scheduler gets the current date and time by calling DateTime#now().

  4. Then, Scheduler iterates through every Schedule in ScheduleList, and requests to get ScheduledWorkout by calling Schedule#getScheduledWorkout(now) on each of them.

  5. Finally, Scheduler resets the SortedScheduledWorkoutList with the latest ScheduledWorkout by calling ScheduledWorkoutList#setScheduledWorkouts(scheduledWorkouts), and user’s view of ScheduledWorkout is refreshed.

  6. 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 only ScheduledWorkout objects.

    • Pros: Easier to implement.

    • Cons: Harder to maintain when it comes to edit or delete of recurring scheduled workouts.

  • Option 2 (current choice): Saves Schedule objects that can be used to produce ScheduledWorkout 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!