Product Hydration

Introduction

Product hydration - is a process of updating information about products on the runtime. Firework SDK requests product hydration when a video associated with the products starts playing. To implement product hydration, the host app should override OnProductActionListener.onProductHydration() callback.

This callback has following parameters:

  • products - list of products for which hydration is requested.

  • hydrator - a builder that the host app should use to modify fields of a specific product.

  • videoInfo - information about the video which requested the hydration.

Without this, updated values will not be applied to Firework SDK.

Please refer to the sample app to see a complete example of the product hydration.

A simple example of product hydration may look like this:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        FireworkSdk.shopping.setOnProductHydrationListener { products, hydrator, videoInfo ->
                val firstProduct = products.first()
                // Hydrate the first product in the list
                hydrator.hydrate(firstProduct.id) {
                    name("Modified product name")
                    description("Modified product description.")
                    isAvailable(false)
                }
                // Tell the SDK that to apply hydration to the products
                hydrator.completeHydration()
            }
        }
    }

    override fun onDestroy() {
        // Remove OnCartActionListener from the SDK
        FireworkSdk.shopping.setOnProductHydrationListener(null)
        super.onDestroy()
    }
}

Remove a variant

Removes a specified variant from the product based on its unique identifier.

This method efficiently filters out the variant with the given ID from the product's list of variants. If the variant to be removed includes an associated image, this method also ensures that the image is removed from the product's images lists. This is crucial for maintaining data integrity and ensuring that all product representations are up-to-date and accurate.

fun setupShopping() {
   FireworkSdk.shopping.setOnProductHydrationListener { products, hydrator, 
videoInfo ->
       for (product in products) {
           if (product.id == "specific_id") {
               hydrateProduct(product, hydrator)
               //Must call completeHydration() to finish the hydration process
               hydrator.completeHydration()
           }
       }
   }
}


private fun hydrateProduct(
   product: Product,
   hydrator: ProductHydrator,
) {
   product.id?.let { id ->
       hydrator.hydrate(id) {
           for (unit in product.units){
               Log.d("hydrateProduct", "product unit id is $unit.id")
           }
           removeVariant("ProductUnit_Id")
       }
   }
}

Add a new variant

Adds a new variant to the product.

This method appends a new variant to the existing list of product variants. It handles image management by potentially adding a new image to the product's image collections if the variant includes an image. This is useful for expanding the product's variant offerings with additional options like sizes, colors, or configurations.

fun setupShopping() {
   FireworkSdk.shopping.setOnProductHydrationListener { products, hydrator, 
videoInfo ->
       for (product in products) {
           if (product.id == "specific_id") {
               hydrateProduct(product, hydrator)
               //Must call completeHydration() to finish the hydration process
               hydrator.completeHydration()
           }
       }
   }
}


private fun hydrateProduct(
   product: Product,
   hydrator: ProductHydrator,
) {
   product.id?.let { id ->
       hydrator.hydrate(id) {
           addVariant(
               ProductUnit(
                   id = "ProductUnit_Id",
                   name = "blue / l",
                   price = Money(amount = 19.0, CurrencyCode.USD),
                   originalPrice = Money(amount = 29.0, CurrencyCode.USD),
                   image = ProductImage("image_url"),
                   url = "product_unit_url",
                   options = mutableListOf(
                       ProductUnitOption(name = "color", value = "blue"),
                       ProductUnitOption(name = "size", value = "l"),
                   ),
               )
           )
       }
   }
}

Clear all existing variants

Clears all variants from the product, including their associated images.

This method removes all existing variants from the product's list of variants (units). It also removes any associated images from the product's images lists (unitsImages and images). This is useful when resetting the product specifications or before reconfiguring the product with a new set of variants.

fun setupShopping() {
   FireworkSdk.shopping.setOnProductHydrationListener { products, hydrator, videoInfo ->
       for (product in products) {
           if (product.id == "specific_id") {
               hydrateProduct(product, hydrator)
               //Must call completeHydration() to finish the hydration process
               hydrator.completeHydration()
           }
       }
   }
}


private fun hydrateProduct(
   product: Product,
   hydrator: ProductHydrator,
) {
   product.id?.let { id ->
       hydrator.hydrate(id) {
           // Clears all variants from the product, including their associated images.
           clearVariants()
	   //Sets the list of attribute names that are permissible for product variants.
           allowedVariantOptions(listOf("color,blue"))
           //You must add at least one variant to the product
           addVariant(
               ProductUnit(
                   id = "ProductUnit_Id",
                   name = "blue / l",
                   price = Money(amount = 19.0, CurrencyCode.USD),
                   originalPrice = Money(amount = 29.0, CurrencyCode.USD),
                   image = ProductImage("image_url"),
                   url = "product_unit_url",
                   options = mutableListOf(
                       ProductUnitOption(name = "color", value = "blue"),
                       ProductUnitOption(name = "size", value = "l"),
                   ),
               )
           )
       }
   }
}

Replace existing variants with new variants

Replaces the current list of product variants with a new list.

This method is used to update the entire set of variants for a product by clearing the existing variants and replacing them with a new list provided as an argument. This is particularly useful when there is a need to refresh the product's variant offerings due to changes in product specifications, discontinuations, or new variant introductions.

fun setupShopping() {
   FireworkSdk.shopping.setOnProductHydrationListener { products, hydrator, videoInfo ->
       for (product in products) {
           if (product.id == "specific_id") {
               hydrateProduct(product, hydrator)
               //Must call completeHydration() to finish the hydration process
               hydrator.completeHydration()
           }
       }
   }
}


private fun hydrateProduct(
   product: Product,
   hydrator: ProductHydrator,
) {
   product.id?.let { id ->
       hydrator.hydrate(id) {
           //Sets the list of attribute names that are permissible for product variants.
           allowedVariantOptions(listOf("color","size"))
           val options = mutableListOf<ProductUnitOption>()
           options.add(ProductUnitOption("color", "Blue"))
           options.add(ProductUnitOption("size", "L"))
           val variant = ProductUnit(
               //must setup your unique ProductUnit id
               id = "ProductUnit_Id",
               name = "Blue / L",
               price = Money(amount = 19.0, CurrencyCode.USD),
               originalPrice = Money(amount = 29.0, CurrencyCode.USD),
               image = ProductImage("image_url"),
               url = "product_unit_url",
               options = options,
           )
           //Replaces the current list of product variants with a new list.
           replaceVariants(listOf(variant))
       }
   }
}

Modify existing variants

Modifies an existing variant of the product using a builder block for detailed configuration.

This method locates a variant by its unique identifier and applies a configuration block to it, allowing for detailed custom modifications. If the variant with the specified ID is found, the method uses a builder pattern to apply changes and then updates the product's list of variants with the modified version. This method is ideal for updating specific properties of a variant without altering other variants.

fun setupShopping() {
   FireworkSdk.shopping.setOnProductHydrationListener { products, hydrator, videoInfo ->
       for (product in products) {
           if (product.id == "specific_id") {
               hydrateProduct(product, hydrator)
               //Must call completeHydration() to finish the hydration process
               hydrator.completeHydration()
           }
       }
   }
}


private fun hydrateProduct(
   product: Product,
   hydrator: ProductHydrator,
) {
   product.id?.let { id ->
       hydrator.hydrate(id) {
           //Sets the list of attribute names that are permissible for product variants.
           product.units.forEach { unit ->
               unit.id?.let { variantId ->
                   variant(variantId) {
                       //Sets the name of the product variant.
                       name("Variants name")
                       //Sets or updates the price of the product variant.
                       price(30.0)
                       //Sets or updates the `originalPrice` of the product variant.
                       originalPrice(40.0)
                       //Updates the currency code for both the current price and the original price (if set) of the product variant.
                       currency(CurrencyCode.USD)
                       //Updates the URL associated with the product variant.
                       url("url")
                       //Updates or sets the image URL for the product variant.
                       imageUrl("image_url")
                       //Sets the availability status of the product variant
                       isAvailable(true)


                       val options = mutableListOf<ProductUnitOption>()
                       options.add(ProductUnitOption(name = "color", value = "blue"))
                       options.add(ProductUnitOption(name = "size", value = "l"))
                       //Update the options for the product variant.
                       unitOptions(options)
                   }
               }
           }
           this
       }
   }
}

Please note:

allowedVariantOptions

Sets the list of attribute names that are permissible for product variants.

/**
* Sets the list of attribute names that are permissible for product variants.
*
* This method updates the product's internal configuration to only allow variants that have attributes specified
* in the given list. This is essential for maintaining a consistent set of variant attributes such as color, size,
* material, etc., and ensures that all product variants conform to the expected attributes.
*
* @param options A list of strings representing the attribute names allowed for the product variants. Each string
*                should clearly define the attribute type that the product variants can possess.
* @return Returns this `ProductBuilder` instance to enable method chaining.
*
* Usage Notes:
* - This function is crucial when setting up or modifying the product's configuration to ensure that all variants
*   comply with predefined attribute specifications.
* - It is recommended to review and possibly update this list before adding new variants to the product to ensure
*   compatibility and consistency.
*/
fun allowedVariantOptions(options: List<String>): ProductBuilder

API Doc for Product Hydration

interface ProductHydrator {
   /**
    * Initializes the hydration process for a specific product by its ID and applies custom modifications through a builder pattern.
    *
    * This method is designed to start the hydration (or data filling) process for a product identified by its unique ID.
    * It uses a lambda function, `builderBlock`, which allows for custom modifications to the product during the hydration process.
    * This function operates on a `ProductBuilder` instance which facilitates the detailed configuration of the product's properties.
    *
    * @param productId The unique identifier of the product to be hydrated. This ID is used to fetch and populate the product data.
    * @param builderBlock A lambda function with receiver type `ProductBuilder`. This function is intended to modify the ProductBuilder,
    *                     allowing for custom configuration of the product. It should return the modified `ProductBuilder` instance.
    * @return Returns nothing (Unit) as the main purpose is to initiate the hydration process which is handled internally.
    */
   fun hydrate(
       productId: String,
       builderBlock: ProductBuilder.() -> ProductBuilder,
   )


   /**
    * Should be called after hydration is completed
    * @return Hydrated products
    */
   fun completeHydration(): List<Product>


   class ProductBuilder() {


       /**
        * Sets or updates the name of the product.
        *
        * This method allows for setting or updating the name of the product.
        *
        * @param name A string representing the new name for the product.
        * @return Returns this `ProductBuilder` instance to enable method chaining.
        */
       fun name(name: String): ProductBuilder 
       /**
        * Sets the description of the product.
        * @param description The new description of the product.
        * @return The ProductBuilder instance for chaining.
        */
       fun description(description: String): ProductBuilder 
       /**
        * Sets the availability status of the product.
        * @param isAvailable The availability status to set (true if available, false otherwise).
        * @return The ProductBuilder instance for chaining.
        */
       fun isAvailable(isAvailable: Boolean): ProductBuilder 


       /**
        * Replaces the current list of product variants with a new list.
        *
        * This method is used to update the entire set of variants for a product by clearing the existing variants and
        * replacing them with a new list provided as an argument. This is particularly useful when there is a need to
        * refresh the product's variant offerings due to changes in product specifications, discontinuations, or new variant
        * introductions.
        *
        * @param variants A list of `ProductUnit` objects representing the new variants to be associated with the product.
        *                 Each `ProductUnit` should be fully defined and ready to be displayed or used in transactions.
        * @return Returns this `ProductBuilder` instance to enable method chaining. This allows for sequential updates to
        *         the product in a fluent and readable manner.
        *
        * Usage Notes:
        * - Ensure that all variants provided are complete and accurately reflect the product options available to customers.
        * - This method first clears all existing variants, so it should be used with caution to avoid unintentional data loss.
        */
       fun replaceVariants(variants: List<ProductUnit>): ProductBuilder 


       /**
        * Adds a new variant to the product.
        *
        * This method appends a new variant to the existing list of product variants. It handles image management by
        * potentially adding a new image to the product's image collections if the variant includes an image. This is
        * useful for expanding the product's variant offerings with additional options like sizes, colors, or configurations.
        *
        * @param variant A `ProductUnit` object representing the new variant to be added to the product. The variant
        *                should include any necessary details such as pricing, descriptions, and possibly an image.
        * @return Returns this `ProductBuilder` instance to enable method chaining. This facilitates the sequential addition
        *         of multiple variants or other modifications to the product in a fluent and readable manner.
        *
        * Usage Notes:
        * - If the provided variant includes an image, this method will generate a new `ProductImage` with an updated index
        *   and add it to both the `unitsImages` and `images` lists of the product.
        * - This method automatically handles the inclusion of the new image in the product's data structure, ensuring
        *   consistency across product representations.
        */
       fun addVariant(variant: ProductUnit): ProductBuilder 


       /**
        * Removes a specified variant from the product based on its unique identifier.
        *
        * This method efficiently filters out the variant with the given ID from the product's list of variants. If the
        * variant to be removed includes an associated image, this method also ensures that the image is removed from the
        * product's images lists. This is crucial for maintaining data integrity and ensuring that all product representations
        * are up-to-date and accurate.
        *
        * @param id The unique identifier (String) of the variant to be removed from the product.
        * @return Returns this `ProductBuilder` instance to enable method chaining. This allows for the sequential removal
        *         of variants or other updates to the product in a fluent and readable manner.
        *
        * Usage Notes:
        * - If the variant is found and has an associated image, both the variant and its image will be removed from their
        *   respective lists.
        * - If no image is associated with the variant, only the variant itself is removed from the list of units.
        */
       fun removeVariant(id: String): ProductBuilder




       /**
        * Clears all variants from the product, including their associated images.
        *
        * This method removes all existing variants from the product's list of variants (`units`). It also removes any
        * associated images from the product's images lists (`unitsImages` and `images`). This is useful when resetting
        * the product specifications or before reconfiguring the product with a new set of variants.
        *
        * @return Returns this `ProductBuilder` instance to enable method chaining. This allows for the sequential
        *         rebuilding of the product's variant configuration in a fluent and readable manner.
        *
        * Usage Notes:
        * - This method ensures that all references to the variants and their images are cleanly removed, preventing
        *   any orphaned data.
        * - It is recommended to use this function with caution as it will remove all variants and their images, which
        *   might not be recoverable unless re-added.
        */
       fun clearVariants(): ProductBuilder 




       /**
        * Sets the list of attribute names that are permissible for product variants.
        *
        * This method updates the product's internal configuration to only allow variants that have attributes specified
        * in the given list. This is essential for maintaining a consistent set of variant attributes such as color, size,
        * material, etc., and ensures that all product variants conform to the expected attributes.
        *
        * @param options A list of strings representing the attribute names allowed for the product variants. Each string
        *                should clearly define the attribute type that the product variants can possess.
        * @return Returns this `ProductBuilder` instance to enable method chaining.
        *
        * Usage Notes:
        * - This function is crucial when setting up or modifying the product's configuration to ensure that all variants
        *   comply with predefined attribute specifications.
        * - It is recommended to review and possibly update this list before adding new variants to the product to ensure
        *   compatibility and consistency.
        */
       fun allowedVariantOptions(options: List<String>): ProductBuilder 




       /**
        * Modifies an existing variant of the product using a builder block for detailed configuration.
        *
        * This method locates a variant by its unique identifier and applies a configuration block to it, allowing for
        * detailed custom modifications. If the variant with the specified ID is found, the method uses a builder pattern
        * to apply changes and then updates the product's list of variants with the modified version. This method is ideal
        * for updating specific properties of a variant without altering other variants.
        *
        * @param id The unique identifier of the variant to be modified.
        * @param builderBlock A lambda function receiving `ProductVariantBuilder` and returning it, used for configuring
        *                     the found variant. This block allows for fluent and flexible modifications.
        * @return Returns this `ProductBuilder` instance to enable method chaining.
        *
        * Usage Notes:
        * - If no variant with the given ID is found, the method returns the current instance without making any changes,
        *   effectively acting as a no-operation in such cases.
        * - The method leverages a mutable list for variant manipulation, ensuring that the original list remains unaltered
        *   until the update is confirmed.
        */
       fun variant(
           id: String,
           builderBlock: ProductVariantBuilder.() -> ProductVariantBuilder,
       ): ProductBuilder    
}


   class ProductVariantBuilder() {


       /**
        * Sets the name of the product variant.
        * @param name The new name for the product variant.
        * @return The ProductVariantBuilder instance for chaining.
        */
       fun name(name: String): ProductVariantBuilder 


       /**
        * Sets or updates the price of the product variant.
        *
        * This method allows for setting or updating the price of a specific product variant. It adjusts the price
        * without affecting other attributes of the product. This is particularly useful for scenarios where pricing
        * adjustments are needed due to changes in market conditions, promotional strategies, or cost changes.
        *
        * @param price A double value representing the new price to be set for the product variant. The value should
        *              reflect the intended selling price in the appropriate currency unit, though currency handling
        *              is not directly managed by this method.
        * @return Returns this `ProductVariantBuilder` instance to enable method chaining. This allows for sequential
        *         updates to the product variant in a fluent and readable manner.
        *
        * Usage Notes:
        * - This method only updates the price attribute and does not affect any other properties of the product variant.
        * - Ensure that the input price aligns with overall pricing strategies and is consistent with marketplace expectations.
        */
       fun price(price: Double): ProductVariantBuilder 






       /**
        * Sets or updates the `originalPrice` of the product variant.
        *
        * This method determines if the `originalPrice` is already set for the `productUnit`.
        * If `originalPrice` exists, it updates the existing `Money` instance with the new price amount.
        * If it does not exist, it creates a new `Money` instance using the provided price and the
        * currency code from the current price of the product variant.
        *
        * The method ensures that changes are applied immutably by returning a new modified instance
        * of `productUnit`.
        *
        * @param price The new price value to set for `originalPrice`. This must be a non-negative number.
        * @return Returns this `ProductVariantBuilder` instance to allow for method chaining.
        */
       fun originalPrice(price: Double): ProductVariantBuilder 






       /**
        * Updates the currency code for both the current price and the original price (if set) of the product variant.
        *
        * This method sets the currency code for the product variant's `price`. If an `originalPrice` is present,
        * it also updates its currency code to maintain consistency between the current and original prices.
        * The `productUnit` is immutably updated by creating a new instance with the modified prices.
        *
        * @param currencyCode The new currency code to be set. It should be a valid `CurrencyCode` enum value
        *                     representing the desired currency for the product prices.
        * @return Returns this `ProductVariantBuilder` instance to allow for method chaining. This enables
        *         the caller to chain multiple modifications in a single statement.
        */
       fun currency(currencyCode: CurrencyCode): ProductVariantBuilder 






       /**
        * Updates the URL associated with the product variant.
        *
        * This method sets or updates the URL that points to the specific product variant's detail page or other relevant resources.
        * It is crucial for directing users to the correct location for more information or for purchasing the variant. This can
        * enhance navigation and user experience on e-commerce platforms by linking directly to detailed variant descriptions.
        *
        * @param url A string representing the new URL to be associated with the product variant. This should be a valid URL format.
        * @return Returns this `ProductVariantBuilder` instance to enable method chaining. This allows for sequential
        *         updates to the product variant in a fluent and readable manner.
        */
       fun url(url: String): ProductVariantBuilder 






       /**
        * Updates or sets the image URL for the product variant.
        *
        * This method is responsible for updating the URL of an existing image or adding a new image if none exists
        * for the product variant. It ensures that the product variant's visual representation is current and relevant.
        * The method handles both updating existing images and initializing a new image with the provided URL, thereby
        * maintaining the product's media consistency.
        *
        * @param url A string representing the new image URL for the product variant. This should be a valid URL format.
        * @return Returns this `ProductVariantBuilder` instance to enable method chaining. This allows for sequential
        *         updates to the product variant in a fluent and readable manner.
        *
        * Usage Notes:
        * - If the product variant already has an image, this method updates the existing image's URL.
        * - If the product variant does not have an image, this method creates a new image with the provided URL and
        *   adds it to the product's list of images and unit-specific images.
        */
       fun imageUrl(url: String): ProductVariantBuilder 






       /**
        * Sets the availability status of the product variant.
        *
        * This method updates the availability status of a specific product variant. Setting this to `true` indicates
        * that the variant is available for purchase, while `false` indicates it is not. This can be useful for inventory
        * management or controlling the display of product variants on e-commerce platforms.
        *
        * @param isAvailable A boolean value indicating the availability of the product variant. `true` for available,
        *                    `false` for not available.
        * @return Returns this `ProductVariantBuilder` instance to enable method chaining. This allows for sequential
        *         updates to the product variant in a fluent and readable manner.
        */
       fun isAvailable(isAvailable: Boolean): ProductVariantBuilder 




       /**
        * Sets the options for the product variant.
        *
        * This method configures the available options for a specific product variant. It replaces any existing
        * options with the new list provided. This is particularly useful for defining or updating attributes
        * like size, color, material, etc., that are available for a product variant.
        *
        * @param options A list of ProductUnitOption representing the available options for the variant.
        *                Each option can define attributes such as size, color, or other characteristics specific to the variant.
        * @return Returns this `ProductVariantBuilder` instance to enable method chaining. This allows for multiple
        *         modifications to be applied to the product variant in a fluent style.
        */
       fun unitOptions(options: List<ProductUnitOption>): ProductVariantBuilder 


   }
}

Last updated