Overview
HealthyBaby (HYBB) is a desktop application targeted towards university students that provides users with a database of quick, easy, and healthy recipes. HYBB helps alleviate the challenges faced while maintaining healthy eating habits, easing the transition from eating out everyday to cooking healthy meals regularly.
The user interacts with HYBB using a Command Line Interface, and it has a Graphical User Interface created with JavaFX.
It is written in Java, and has about 18 kLoC.
Summary of contributions
-
Major enhancement: Added the Planning feature
-
What it does: Allows the user to plan and remove the plans for a recipe on a certain date. The user is also able to obtain all ingredients required for the planned recipes on a simple grocery list.
-
Justification: Assists users in making healthy cooking easier as the user can plan for recipes containing Goals for the nutritional food group that they want to focus on. Users can save money and reduce food wastage by planning for recipes with similar ingredients and purchasing only items that they need using the grocery list command.
-
Highlights: This enhancement is affected by recipes being modified, as the plans of the modified recipe needs to be updated as well. Ensuring that each plan is deleted or updated after each modification was challenging as HYBB supports many recipe customisation methods (9 in total).
-
-
Minor enhancement: Added Ingredient and Quantity classes to allow HYBB to estimate the portion of each food group in the recipes.
-
Code contributed: RepoSense
-
Other contributions:
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. |
HealthyBaby’s User Interface (Beatrice)
Upon opening HYBB, you will see our Graphical User Interface.
The Command Box is where you can enter commands to tell HYBB what to do.
The Result Box is where you can see whether the command you have given was successful or unsuccessful.
The Tab Panel can be clicked to switch between tabs.
Alternatively, if you wish to switch between tabs by typing instead of clicking, you can type switch [tab name]
into the Command Box instead.
For more information, please refer to [Switch the current tab: switch
].
The Display Panel displays the information for the current tab you are on.
Planning Command (Beatrice)
Most of the planning commands take place in the planning tab.
Switch to the planning tab by typing switch planning
or by clicking on Planning from the Tab Panel.
You should get the following interface:
The Display Panel for the planing tab lists all the plans that you have made.
You can the see the details of each plan from the list of plans.
Plan a recipe: plan
(Beatrice)
Plans a recipe that you would like to cook on a certain day in the future.
Format: plan [recipe index] [d/yyyy-mm-dd]
Example 1: plan 1 d/2020-05-27
Plans the recipe at recipe index 1 on 27 May 2020 and adds this plan into the plan list.
Example 2: plan 1 2 3 d/2020-05-27
Plans the recipes at recipe indexes 1, 2 and 3 on 27 May 2020 and adds these three plans into
the plan list.
As long as at least one index is specified, you can plan as many recipes as you want in one go. For example, we can
plan for five recipes in one command. plan 1 2 3 4 5 d/2020-05-27 will plan for the recipes at recipe indexes
1, 2, 3, 4 and 5 on 27 May 2020.
|
Valid indexes are integer numbers ranging from 1 to the current plan list size. If one of the indexes given was invalid, the command will not be successful. |
Valid dates start from the today’s date and are in the format yyyy-mm-dd. This means that we cannot make a plan on yesterday’s date. |
Delete a plan: deletePlan
(Beatrice)
Deletes a plan.
Format: deletePlan [plan index]…
Example 1: deletePlan 3
Deletes the 3rd plan.
Example 2: deletePlan 3 5 8
Deletes the 3rd, 5th and 8th plan.
As long as at least one index is specified, you can delete as many plans as you want in one go. For example, we can
delete five plans in one command. deletePlan 1 2 3 4 5 will delete all plans at plan indexes 1, 2, 3, 4 and 5.
|
Valid indexes are integer numbers ranging from 1 to the current plan list size. If one of the indexes given was invalid, the command will not be successful. |
Using the cooked command in [Track cooked meals: cooked (Harshita)] will automatically delete today’s plan for
the recipe that is cooked.
|
Clear all planned recipes: clearPlan
(Beatrice)
Clears all the plans you have made.
Format: clearPlan
All plans will be removed. |
You can undo this command if it was performed by accident.
|
Obtain ingredients for planned recipes: groceryList
(Beatrice)
Lists the ingredients needed for all recipes that have been planned.
Click on 'Copy' to copy all the ingredients into your clipboard.
Simplify your next grocery shopping experience by pasting this list into your preferred social networking
application (like Telegram or Whatsapp) and sending it to yourself for an easy reference from your
mobile phone.
Alternatively, you can paste the list into a word document and print it out.
You can print this list out by pasting the text into a word document to
Format: groceryList
If no plans have been made, the grocery list will not be generated. |
View this week’s planned recipes: viewWeek
[Coming in v2.0]
View all the plans for the week.
Format: viewWeek
View this month’s planned recipes: viewMonth
[Coming in v2.0]
View all the plans for the month.
Format: viewMonth
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. |
Edit command (Beatrice)
The edit feature allows users to edit the properties of a Recipe with ease using the edit
command.
This feature is facilitated by the EditCommand
class.
The following activity diagram illustrates how the EditCommand
is used.
Implementation
This section explains how the edit
command is implemented.
-
User specified arguments are passed to the
EditCommandParser
and the arguments are broken up by theArgumentTokenizer
andArgumentMultimap
. -
The arguments will then be parsed by
ParserUtil
and passed intoEditRecipeDescriptor
. An error will be thrown if the inputs were invalid or if no properties of the Recipe were edited. -
A new
EditCommand
object will be created containing the new properties of theRecipe
. -
EditCommand#execute()
will then get the latest list of recipes fromModel
and obtain theRecipe
that is being edited. -
This
Recipe
is passed intoEditCommand#createEditedRecipe()
which creates a newRecipe
with the edited properties. -
Model#setRecipe()
will then replace theRecipe
being edited with the newRecipe
and update the list of recipes and plans. -
The success message will be returned to the user by the
CommandResult
.
The following sequence diagram summarizes the steps taken so far:
The lifeline for EditCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram. |
The details of some methods, like the the usage of EditRecipeDecriptor , was omitted to reduce clutter in the diagram.
|
The edited recipe will be updated in both the list of recipes and plans.
The following section explains in detail the implementation behind how each list is updated in the
RecipeBook
and PlannedBook
class.
-
Continuing off from Step 8,
ModelManager#setRecipe()
will be called to replace the targetRecipe
with the editedRecipe
. (ModelManager
implementsModel
) -
The target and edited
Recipe
is passed intoRecipeBook#setRecipe()
andUniqueRecipeList#setRecipe()
, which will replace the target with the editedRecipe
in the recipe list. -
The same arguments are then passed into
PlannedBook#setRecipe()
which will get a list of all the plans that uses the targetRecipe
fromPlannedRecipeMap
. -
If there are no plans that uses
Recipe
, the process stops. However if plans exists, thePlannedBook
will iterate through each old plan and update each plan.
Step 4. is an example of how the PlannedRecipeMap
can be used to ease the cost of updating each plan.
The following sequence diagram summarizes how the Recipe
and all its related Plan
are updated
when the Recipe
is edited.
Design Considerations
Aspect: How recipes are edited
-
Alternative 1 (current choice): The
EditRecipeDescriptor
class is used to make sense of user input and mimics theRecipe
class with the same properties.-
Pros: Multiple fields can be edited in one go.
-
Cons: Might make testing harder since there are many properties in a Recipe and an edit command can take on any combination of each property.
-
-
Alternative 2: Allow each property in the
Recipe
to have its ownedit
command.-
Pros: Implementation of each command will be simpler.
-
Cons: Editing a recipe will be harder and more troublesome for the user.
-
We decided to stick with alternative 1, which is the implementation inherited by AB3, as we believe that being able to edit multiple fields in one go provides much more versatility and convenience to the user. Additionally, although there are many properties to test, it is still a finite number and testing can be done with adequate time.
Aspect: Data structure to support plans
Please refer to Aspect: Data structure to support plans for the design considerations for plans.
Plan command (Beatrice)
The plan feature allows users to plan for recipes that they wish to cook at a certain date.
This feature is facilitated by the PlanCommand
class.
Implementation
This section explains how the plan
command is implemented.
-
User specified arguments are passed to the
PlanCommandParser
which usesArgumentTokenizer
andArgumentMultimap
to break up the user input. -
The arguments are parsed by
ParserUtil
and if no invalid inputs were found, aPlanCommand
object will be created. -
PlanCommand#execute()
gets the latest list of recipes fromModel
. -
For every
Index
, a newPlan
object is created and added into theModel
. This is done by passing thePlan
and theRecipe
that is being planned into theUniquePlannedList
andPlannedRecipeMap
. -
The
Plan
is added to theUniquePlannedList
and thePlan
is added to the list of plans at theRecipe
key in thePlannedRecipeMap
. -
The success message will be returned to the user by the
CommandResult
.
The diagram below summarises the steps taken:
The lifeline for EditCommandParser should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram. |
Design Considerations
Aspect: Data structure to support plans
-
Alternative 1 (current choice): Use a
UniquePlannedList
with anObservableList
to display the list of plans, and an internalPlannedRecipeMap
that maintains the mapping between aRecipe
and all plans that were made for the recipe.-
Pros: The
UniquePlannedList
provides the list of plans and updates the UI for every change in plan. In the background, thePlannedRecipeMap
is maintained and used to ease the cost of iterating through an entire list of plans to search for all the plans that uses a specificRecipe
. -
Cons: Performance might not be optimised as
UniqueRecipeList
still uses a list.
-
-
Alternative 2: Maintain the recipes and plans in one
ObservableMap
instead.-
Pros: Performance will be better by using a Map than a List.
-
Cons: There are no official javafx classes that supports an sorted
ObservableMap
or a filteredObservableMap
. We will have to write and maintain our own implementation or import from other libraries.
-
We decided to use alternative 1, as the cons of alternative 2 are too heavy. The plans need to be sorted
in a chronological order, and future implementations of the viewWeek
and viewMonth
command will require the plans
to be filtered as well.
Additionally, we would not have enough time in the scope of this project to write a fully functional
implementation, and importing from other libraries introduces the risk of running into bugs if the the dependencies
were not maintained in the future.