Skip to main content
Version: 5.3

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

The RecipeCarousel has two potential mandatory parameters, a productId or criteria of type SuggestionsCriteria. Additionally, it expects RecipeCarouselParameters that implements navigation functions & has optional viewOptions for customizing views.

RecipeCarousel also expects a RecipesCarouselGridConfig which defines the number of rows, recipe card sizes, & spacing. The last parameter is numberOfResults that the Recipe Carousel should show.

RecipeCarouselParameters

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

RecipesCarouselGridConfig

RecipesCarouselGridConfig(
numberOfRows: 1,
spacing: CGSize(width: 6, height: 6),
recipeCardDimensions: CGSize(width: 200, height: 320))

Putting it all together

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

ProductID

When you would like to show recipes relating to a certain product, such as peanut butter, you can pass in just the productId. This will be a String.

RecipeCarousel(
params: /* RecipeCarouselParameters we just created */,
gridConfig: /* RecipesCarouselGridConfig we just created */,
numberOfResults: 10,
productId: productId
)
SuggestionsCriteria

When you would like to show recipes based on the result of a search, such as 'chicken' or products in the user's basket.

For example, all of these products are currently in your basket:

 let criteria = SuggestionsCriteria(
shelfIngredientsIds: nil, // ingredients on the shelf, great for search results & lists
currentIngredientsIds: nil, // very simialar to shelfIngredientsIds, used for generated recipes from smaller lists of products
basketIngredientsIds: ["5319173", "53755728", "53755778", "53755841", "53755837"], // products in basket
groupId: nil // depreciated, will always be nil
)

so

RecipeCarousel(
params: /* RecipeCarouselParameters we just created */,
gridConfig: /* RecipesCarouselGridConfig we just created */,
numberOfResults: 10,
criteria: criteria
)

If there is no Recipes returned the default (or your custom) EmptyProtocol will appear.

2. 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.

3. 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 */
)