Skip to main content
Version: 4.1

Custom Navigation

If you don't want to use the provided Mealz navigation, you can recreate the navigation yourself. We have documented a simple walkthrough, but feel free to implement your practice of Coordinators.

Steps

1. Create MyMeals page

Again, if you've already completed the Catalog Feature, you'll already have the ViewController or page set up.

The only new aspect is navigating to the Catalog Feature when the user does not have any recipes in their basket.

The first thing to be done is to create a MyMealsViewController or MyMealsView standalone page. The only parameters this page may expect are those related to navigating to the Catalog Feature. For example, you may want to pass a Navigation Delegate or a binding of the current tab.

MyMeals expects params: MyMealsParameters & basketRecipesParams: BasketRecipeParameters. It also expects a gridConfig: BasketRecipesGridConfig.

MyMealsParameters

For the CatalogFeature, the onNoResultsRedirect can just redirect to the view that called it. However, if MyMeals is a standalone page, this should navigate to the Catalog Feature when there are no recipes here.

MyMealsParameters(
actions: MyMealsActions(
onNoResultsRedirect: { [weak self] in
guard let strongSelf = self else { return }
strongSelf.navigationController?.popViewController(animated: true)
}
)
)

BasketRecipeParameters

BasketRecipeParameters(
onReplaceProduct: { [weak self] recipeId in
guard let strongSelf = self else { return }
strongSelf.navigationController?.pushViewController(ItemSelectorViewController(recipeId), animated: true)
},
onShowRecipeDetails: { [weak self] recipeId in
guard let strongSelf = self else { return }
strongSelf.navigationController?.pushViewController(RecipeDetailsViewController(recipeId), animated: true)
})

BasketRecipesGridConfig

BasketRecipesGridConfig(
recipeSpacing: CGSize(width: 5, height: 5),
productSpacing: CGSize(width: 6, height: 6),
recipeOverviewDimensions: CGSize(width: 300, height: 150),
isExpandable: true)

Putting it all together

Now we have all the parameters we need for the MyMeals.

MyMeals(
params: /* the RecipeDetailParameters we just made */,
basketRecipesParams: /* the BasketRecipeParameters we just made */,
gridConfig: /* the BasketRecipesGridConfig we just made */

2. Create ItemSelector page

Again, if you've already completed the Catalog Feature, you'll already have the ViewController or page set up. You have nothing more to do for this.

The first thing to be done is to create a ItemSelectorViewController or ItemSelectorView standalone page. The only parameters this page may expect are those related to navigating back to the MyMeals page.

ItemSelector expects a recipeId string. ItemSelector also expects params: ItemSelectorParameters.

ItemSelectorParameters

ItemSelectorParameters(
actions: ItemSelectorActions(
onItemSelected: { [weak self] in
guard let strongSelf = self else { return }
strongSelf.navigationController?.popViewController(animated: true)
}
)
)

Putting it all together

Now we have all the parameters we need for the ItemSelector.

ItemSelector(
params: /* the ItemSelectorParameters we just made */,
recipeId: recipeId /* the callback navigating to this view will provide this */
)

3. Create Recipe Details page

Again, if you've already completed the Catalog Feature, you'll already have the ViewController or page set up. You have nothing more to do for this.

The first thing to be done is to create a RecipeDetailsViewController or RecipeDetailsView standalone page. The only parameters this page may expect are those related to navigating back to the MyMeals page. The navigation to the basket can be ignored as that Call To Action will not be shown as the product is already in the basket.

The RecipeDetails Page expects a recipeId string. RecipeDetails also expects params: RecipeDetailParameters.

Additionally, RecipeDetails has an optional parameter isForMealPlanner that defaults to false. If you are not implementing Meal Planner now or in the future, you can ignore this.

RecipeDetailParameters

RecipeDetailParameters(
actions: RecipeDetailsActions(
onClosed: { [weak self] in
guard let strongSelf = self else { return }
strongSelf.navigationController?.popViewController(animated: true)
},
onSponsorDetailsTapped: { [weak self] sponsor in
guard let strongSelf = self else { return }
strongSelf.navigationController?.pushViewController(SponsorDetailsViewController(sponsor: sponsor), animated: true)
},
onContinueToBasket: { [weak self] in // this is ignored if the Recipe is already in the basket
guard let strongSelf = self else { return }
strongSelf.navigationController?.pushViewController(MyMealsViewController(), animated: true)
}
)
),

Putting it all together

Now we have all the parameters we need for the RecipeDetails.

RecipeDetails(
params: /* the RecipeDetailParameters we just made */,
recipeId: recipeId /* the callback navigating to this view will provide this */,
isForMealPlanner: isForMealPlanner // defaults to false
)

The default Miam Neutral Recipe Details Footer will NOT show the Call To Action if the item is already in the basket. If you customize your footer, make sure you implement this same functionality.

4. Create Sponsor Details page

Again, if you've already completed the Catalog Feature, you'll already have the ViewController or page set up. You have nothing more to do for this.

The first thing to be done is to create a SponsorDetailsViewController or SponsorDetailsView standalone page. The only parameters this page may expect are those related to navigating back to the MyMeals page.

After the RecipeDetails, implement the SponsorDetails Page. SponsorDetails expects a sponsor object. SponsorDetails also expects params: SponsorDetailsParameters.

SponsorDetailsParameters

SponsorDetailsParameters does not expect navigation functions, so you don't need to implement anything unless you add custom views.

Putting it all together

Now we have all the parameters we need for the SponsorDetails.

SponsorDetails(
params: SponsorDetailsParameters() /* default */,
sponsor: sponsor /* the callback navigating to this view will provide this */
)