RecipeDetailsAddedProduct
Added
To create your own recipe detail added product template you create a class that implements RecipeDetailsAddedProductProtocol
- Boilerplate
- Full Example
import SwiftUI
import MealziOSSDK
import mealzcore
public struct MyCustomRecipeDetailsAddedProductView: RecipeDetailsAddedProductProtocol {
public func content(params: RecipeDetailsAddedProductParameters) -> some View {
// Your custom design here
}
}
import SwiftUI
import MealziOSSDK
import mealzcore
public let mealzProductHeight: CGFloat = 230
@available(iOS 14, *)
public struct MealzRecipeDetailsAddedProductView: RecipeDetailsAddedProductProtocol {
public init() {}
let dim = Dimension.sharedInstance
public func content(params: RecipeDetailsAddedProductParameters) -> some View {
VStack {
HStack {
Text(params.data.ingredientName.capitalizingFirstLetter())
.padding(dim.mPadding)
.miamFontStyle(style: MiamFontStyleProvider.sharedInstance.bodyBigBoldStyle)
Spacer()
if let unit = params.data.ingredientUnit {
Text(QuantityFormatter.companion.readableFloatNumber(value: params.data.ingredientQuantity, unit: unit))
.padding(dim.mPadding)
.miamFontStyle(style: MiamFontStyleProvider.sharedInstance.bodyMediumStyle)
}
}
.foregroundColor(Color.mealzColor(.white))
.frame(height: 40)
.background(Color.mealzColor(.primary))
.cornerRadius(dim.mCornerRadius, corners: .top)
HStack {
if let pictureURL = URL(string: params.data.pictureURL) {
AsyncImage(url: pictureURL) { image in
image
.resizable()
.aspectRatio(contentMode: .fill)
}
.frame(width: 72, height: 72)
.padding(dim.mPadding)
}
VStack(alignment: .leading) {
if let brand = params.data.brand {
Text(brand)
.miamFontStyle(style: MiamFontStyleProvider.sharedInstance.bodySmallBoldStyle)
}
Text(params.data.name)
.miamFontStyle(style: MiamFontStyleProvider.sharedInstance.bodySmallStyle)
HStack {
IngredientUnitBubble(capacity: params.data.capacity)
if params.data.isSponsored {
MealzSponsoredTag()
}
}
Button(action: params.onChangeProduct, label: {
Text(Localization.myBudget.replaceItem.localised)
.miamFontStyle(style: MiamFontStyleProvider.sharedInstance.bodyMediumBoldStyle)
.foregroundColor(Color.mealzColor(.primary))
})
}
.frame(maxWidth: .infinity,alignment: .leading)
.padding(.horizontal, dim.mlPadding)
.padding(.top, dim.mPadding)
}
HStack {
Text(params.data.formattedProductPrice)
.miamFontStyle(style: MiamFontStyleProvider.sharedInstance.titleBigStyle)
.padding(.horizontal, 12)
.foregroundColor(Color.mealzColor(.primaryText))
Spacer()
HStack {
Button {
if params.data.productQuantity == 1 {
params.onDeleteProduct()
} else {
params.updateProductQuantity(params.data.productQuantity - 1)
}
} label: {
Image.mealzIcon(icon: .minus)
.renderingMode(.template)
.foregroundColor(Color.mealzColor(.primary))
}
if params.updatingQuantity {
ProgressLoader(color: Color.mealzColor(.standardDarkText), size: 10)
} else {
Text(String(params.data.productQuantity)).frame(minWidth: 10, alignment: .center)
}
Button {
params.updateProductQuantity(params.data.productQuantity + 1)
} label: {
Image.mealzIcon(icon: .plus)
.renderingMode(.template)
.foregroundColor(Color.mealzColor(.primary))
}
}
.padding(dim.mPadding)
}
Spacer()
if params.data.numberOfOtherRecipesSharingThisIngredient > 1 {
HStack(alignment: .center) {
Text(
String(format: String.localizedStringWithFormat(
Localization.ingredient.productsSharedRecipe(
numberOfProducts: Int32(params.data.numberOfOtherRecipesSharingThisIngredient)
).localised,
params.data.numberOfOtherRecipesSharingThisIngredient),
params.data.numberOfOtherRecipesSharingThisIngredient)
)
.miamFontStyle(style: MiamFontStyleProvider.sharedInstance.bodySmallStyle)
.foregroundColor(Color.mealzColor(.grayText))
}
.frame(maxWidth: .infinity)
.padding(.vertical, Dimension.sharedInstance.mPadding)
.background(Color.mealzColor(.lightBackground))
}
}
.frame(height: mealzProductHeight)
.overlay( /// apply a rounded border
RoundedRectangle(cornerRadius: dim.mCornerRadius)
.stroke(Color.mealzColor(.primary), lineWidth: 1)
)
.padding(.horizontal, dim.mPadding)
}
}
with
public struct RecipeDetailsAddedProductParameters {
/// Contains all the info related to the product
public let data: RecipeProductData
/// Boolean on whether or not the recipe quantity is being updated
public let updatingQuantity: Bool
/// Boolean on whether or not the product quantity is being updated
@Binding public var productQuantityPressed: Bool
/// Closure to remove the product from your basket
public let onDeleteProduct: () -> Void
/// Closure to open the Item Selector
public let onChangeProduct: () -> Void
/// Closure to update the quantity of the product
public let updateProductQuantity: (Int) -> Void
where
public struct RecipeProductData {
/// The unit price of the product
public let unitPrice: Double
/// Name of the product
public let name: String
/// Brand of the product (if it has one)
public let brand: String?
/// How much the product contains (ex: 60 g)
public let capacity: String
/// The number of products
public let productQuantity: Int
/// The Unit of the product (ex: g, kg, etc)
public let productUnit: String
/// The formatted price (ex: $34.53 or €34.23)
public let formattedProductPrice: String
/// Checked imageURL of the product
public let pictureURL: String
/// The name of the specified ingredient (ex: banana)
public let ingredientName: String
/// The amount of products asked by the recipe
public let ingredientQuantity: Float
/// The unit used by the recipe for this ingredient (ex: g, kg, etc)
public let ingredientUnit: String?
/// If other recipes use this product as well, this variable tells how many recipes overall share
public let numberOfOtherRecipesSharingThisIngredient: Int
/// The number of guests for the recipe set by the user
public let guestsCount: Binding<Int>
/// The number of guests for the recipe set by the Recipe
public let defaultRecipeGuest: Int
/// If the product has been sponsored by one of Mealz's partners
public let isSponsored: Bool
/// The EAN (barcode number)
public let ean: String