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-27will 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 5will 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 cookedcommand 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 undothis 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 EditCommandParserand the arguments are broken up by theArgumentTokenizerandArgumentMultimap.
- 
The arguments will then be parsed by ParserUtiland passed intoEditRecipeDescriptor. An error will be thrown if the inputs were invalid or if no properties of the Recipe were edited.
- 
A new EditCommandobject will be created containing the new properties of theRecipe.
- 
EditCommand#execute()will then get the latest list of recipes fromModeland obtain theRecipethat is being edited.
- 
This Recipeis passed intoEditCommand#createEditedRecipe()which creates a newRecipewith the edited properties.
- 
Model#setRecipe()will then replace theRecipebeing edited with the newRecipeand 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 targetRecipewith the editedRecipe. (ModelManagerimplementsModel)
- 
The target and edited Recipeis passed intoRecipeBook#setRecipe()andUniqueRecipeList#setRecipe(), which will replace the target with the editedRecipein the recipe list.
- 
The same arguments are then passed into PlannedBook#setRecipe()which will get a list of all the plans that uses the targetRecipefromPlannedRecipeMap.
- 
If there are no plans that uses Recipe, the process stops. However if plans exists, thePlannedBookwill 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 EditRecipeDescriptorclass is used to make sense of user input and mimics theRecipeclass 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 Recipeto have its owneditcommand.- 
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 PlanCommandParserwhich usesArgumentTokenizerandArgumentMultimapto break up the user input.
- 
The arguments are parsed by ParserUtiland if no invalid inputs were found, aPlanCommandobject will be created.
- 
PlanCommand#execute()gets the latest list of recipes fromModel.
- 
For every Index, a newPlanobject is created and added into theModel. This is done by passing thePlanand theRecipethat is being planned into theUniquePlannedListandPlannedRecipeMap.
- 
The Planis added to theUniquePlannedListand thePlanis added to the list of plans at theRecipekey 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 UniquePlannedListwith anObservableListto display the list of plans, and an internalPlannedRecipeMapthat maintains the mapping between aRecipeand all plans that were made for the recipe.- 
Pros: The UniquePlannedListprovides the list of plans and updates the UI for every change in plan. In the background, thePlannedRecipeMapis 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 UniqueRecipeListstill uses a list.
 
- 
- 
Alternative 2: Maintain the recipes and plans in one ObservableMapinstead.- 
Pros: Performance will be better by using a Map than a List. 
- 
Cons: There are no official javafx classes that supports an sorted ObservableMapor 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.