Overview
Souschef is a desktop smart cooking sidekick, offering personalised guidance every step of the way. From recipe recommendations just for you, to meal planning and inventory management, SousChef has everything you need to improve life in the kitchen.
Our users interact via CLI and GUI created with JavaFX. Written in Java, experience what many are enjoying.
Summary of contributions
-
Code contributed: [Functional code]
-
Major enhancement: added the Meal Planner feature.
-
What it does: Allows users to add their desired recipes to a Meal Planner so that they can plan their days' meals.
-
Justification: This feature improves the product significantly because a user can not only browse recipes, but also keep a record of the recipes they want to try on which specific days.
-
Highlights: This enhancement was originally unsupported by the AB4 code; it is a completely new component feature.
-
-
Major enhancement: restructured and modularised UI component and implemented panel switching between different features.
-
Justification: This was to allow easy and efficient integration for the UI aspect across multiple features through the use of general classes, as well as to allow switching between the display panels of different features.
-
Highlights: This enables both modularised and efficient integration of features into UI and allowed easy switching between different feature panels through the use of Universal Commands.
-
-
Minor enhancement: Implemented cross-model deletion and clearing in order to maintain data consistency across the different models.
-
Justification: There are some scenarios to consider where modifying one model has to affect one or more other models.
-
Recipe that is already planned in the Meal Planner is deleted from the recipe model.
In this scenario, the deleted recipe will now also be removed from the days in the Meal Planner where it was previously planned, and also from the day planned in the Health Planner. -
3 recipes that have been planned in a single day are deleted from the recipe model.
In this scenario, the day in the Meal Planner which has had all its recipes removed will also be deleted from the Meal Planner. This then cascades on to the Health Planner, and the deleted day will be removed from any health plans where it was previously added to. -
A day from the Meal Planner that has been added to a health plan in the Health Planner is deleted from the Meal Planner.
In this scenario, the deleted day will now also be removed from the health plans in the Health Planner where it was previously added. -
Clearing the Meal Planner while days have been added to health plans in the Health Planner.
In this scenario, all the health plans in the Health Planner will now have all their previously added days removed. -
A recipe that is already planned in the Meal Planner is edited.
In this scenario, the recipe’s changes will now also be reflected in the Meal Planner and also in the Health Planner if the day has been added to a health plan.
-
-
Highlights: This ensures that the different types of data across the different models in SousChef all remain in synchronization and logically correct.
-
-
Other contributions:
-
General/Team Enhancements:
-
Documentation (see Contributions to Developer Guide for details):
-
Update UI class diagram to reflect new generic classes.
-
Documented and explained modularisation of UI component, including creating class diagrams to show new classes
-
Documented and explained implementation of MealPlanner component.
-
-
Enhancements to new features:
-
Wrote additional tests for Meal Planner component to increase coverage.
-
-
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. |
Meal Planner Commands (Only applicable in meal planner context)
Delete recipe: delete
After displaying the meal planner, deletes the specified day.
Format: delete INDEX
Clears all the meal slots of the meal planner.
Format: clear
Select recipe: select
Selects and views the details of a recipe at a specified meal slot of a specified day.
Format: select INDEX MEAL
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. |
Meal Planner feature
Current Implementation
Model
The Meal Planner feature is supported by the classes Meal and Day.
Class diagram:
Brief explanation:
Meal Planner is currently implemented as a list of non-empty Day objects. This is ensured as Day objects are only instantiated when recipes are added to a certain date, with that date being assigned to its Day object. When all the recipes are deleted from a certain Day, the Day object is removed from the Meal Planner. Day objects in the Meal Planner list panel are sorted in chronological order according to their dates. This is done by sorting the list when instantiated and when Day objects are added or removed.
Logic
For Meal Planner commands to be accessible, context has to be switched to "Meal Planner
via the command -mealplanner
(except for the case of the plan
command for adding recipes
to the Meal Planner, which has to be done in the recipe context since the user needs to be able
to see the recipes). From there, the Meal Planner commands can be used and
AppContentParser will redirect the different commands to their respective CommandParser.
Plan Command: plan
The plan command adds a recipe from the recipeModel to the mealPlannerModel. Therefore both models have to be passed to PlanMealCommandParser.
Within PlanMealCommandParser, it parses the target date from a String into a LocalDate. Only dates from the present or future are allowed to be entered. This LocalDate object is then used to find out whether mealPlannerModel currently contains a Day with the target date. If such a Day object already exists, it is taken from mealPlannerModel to be used in PlanMealCommand. Else, a new Day object is instantiated with the target LocalDate date. The target meal is then taken from the Day object. mealPlannerModel, target day target recipe and target meal are then passed to PlanMealCommand.
Within the execute method of PlanMealCommand, target recipe is then added the target meal and target day is then added to mealPlannerModel.
Finally, the new content is committed via mealPlannerModel.commitAppContent().
Select Command: select
The select command selects a recipe of a specified meal of a specified day and displays the details
of the recipe (ingredients, instructions, etc) in the DetailPanel.
MealPlannerParser invokes the parseMealRecipe() command of SelectCommandParser. The desired
index and meal index are parsed from the user input and used to extract the recipe from the
specified day’s desired meal index. Using this recipe, the recipeModel is searched and the
index of the matching recipe is returned.
The index and the recipeModel are then passed to
a SelectCommand which executes the displaying of the recipe details in the same manner as
in the recipe context.
Clear Command: clear
The clear command simply clears the Meal Planner of all days.
This is done by setting (i.e. replacing) the existing UniqueList of mealPlannerModel
with a new empty UniqueList.
Delete Command: delete
The delete command deletes a specified Day from the mealPlannerModel along with all its meals.
The Day is specified by its index as seen on the list panel.
MealPlannerParser invokes the parseMealPlan() method of DeleteCommandParser. The user input
is then parsed to get the index of the Day to be deleted. The Day object at the given index
of the mealPlannerModel list is then deleted.
Alternative implementation
Earlier MealPlanner implementation used a ObservableHashMap with LocalDate and Day as the key and value
pairs, each LocalDate being the key for the Day with the same LocalDate. Theoretically, this
would work as well. However, this was scrapped as a simple ObservableList of Days would work
equally well. In addition, since AB4 already has an implemented UniqueList, using a simple
List makes it easier to integrate the Meal Planner into the existing infrastructure.
HashMaps are mainly used as they give a time complexity advantage, having an O(1) time complexity.
However, that advantage is not present here since our Lists usually access elements by index,
and thus also have a time complexity of O(1).
Meal Planner
Priority | As a … | I want to … | So that I can… |
---|---|---|---|
|
user |
plan my meals for breakfast, lunch and dinner |
I can remember my meals for each day |
|
fickle-minded user |
edit my meal plans |
I can add different recipes if I change my mind |
|
efficient user |
clear the meal planner immediately at the end of the week |
I can save time |
|
health-conscious user |
view the nutritional value of each recipe |
I can choose recipes according to my nutritional needs |
|
meticulous user |
view the time taken for each recipe |
I can plan ahead for meal preparations to fit my schedule |
Explanation of the modularisation of the UI component
Modularisation
List Panel
Brief overview: Many of the features (such as MealPlanner, HealPlan, IngredientManager, Recipes, Favourites) need to use the list panel section to display their own UniqueType classes. Therefore, this has been abstracted and modularised for easier implementation of usage and for any future implementation of new components which may need to use the list panel. This is done by inserting generic classes into the hierarchy.
Old Hierarchy:
New Hierachy:
Not all the components are shown, only MealPlanner and Recipe components are shown in the diagram as an example. Notice how the new generic abstract classes are simply inserted between the superclass and subclass of the old hierarchy to give the new hierarchy. |
Explanation:
With the GenericListPanel, GenericCard and GenericPanelSelectionChangedEvent classes, new features which wish to use the UI list panel simply have to have their respective classes extend these three abstract classes and implement their methods accordingly. Then the respective fxml files for [feature]ListPanel and [feature]Card have to be created.
MainWindow.java and ListPanelSwitchEvent.java:
ListPanelSwitchEvent encapsulates an event where the list panel needs to change context.
It extends BaseEvent and contains a Context attribute to store information on which context
the list panel needs to switch to.
To switch between different list panels for different features, switchTo[feature]ListPanel()
methods have to be implemented in MainWindow. This method gets the respective filteredList
from the model within modelSet within logic and uses it to change the generalListPanel.
The handleListPanelSwitchEvent() method is invoked when a ListPanelSwitchEvent is posted
to the EventsCenter, and the method then checks the context attribute of the ListPanelSwitchEvent
object to determine which context the list panel needs to switch to, and then calls the correct method.
Usage:
Now in order to switch between the different feature list panels, the developer just has to create their handler method, instantiating a ListPanelSwitchEvent with their desired context and then raising the event by posting it to the EventsCenter.