3 min read

Common customisations

Add SlotsContent to a domain model

If you want to add Dynamic content to a domain model and start receiving content through the API, you need to:

Add a new Slot to a screen

If you want to add a new Slot to a screen where the domain model already contains SlotsContents, you need to use different components depending if you will add it to Compose, a View or a RecyclerView.

Compose

  • Add UiSlotsContent to your UI state model mapping it from SlotsContent using DomainToUiSlotsContentMapper.
  • On your composable, get the UiSlotComponent from the UiSlotsContent.components Map using the slot id for the slot to render.
  • Use SlotComponentComposable to display your UiSlotComponent.

View

  • Expose UiSlotsContent on your ViewModel mapping it from SlotsContent using DomainToUiSlotsContentMapper.
  • Add PoqSlotComponentView to your view hierarchy.
  • Use the binding adapter to send the appropiate UiSlotComponent:
    <com.poqstudio.platform.content.dynamiccontent.ui.PoqSlotComponentView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:slot='@{"top"}' // Use your SlotId
    app:slotsContent="@{viewModel.slots}" />

RecyclerView

  • Add UiSlotComponent to your the RecyclerView UI model mapping it from SlotsContent.component using DomainToUiSlotComponentMapper using the appropriate slot id for your slot.
  • Use SlotComponentViewHolderFactory to create a BaseSlotComponentViewHolder.
  • Call BaseSlotComponentViewHolder.onBind passing the appropriate UiSlotComponent:
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
    return when (viewType) {
    TYPE_SLOT_COMPONENT -> slotComponentViewHolderFactory.create(parent)
    ...
    }
    }
    override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) {
    when (getItemViewType(position)) {
    TYPE_SLOT_COMPONENT -> (viewHolder as BaseSlotComponentViewHolder).onBind(
    (getItem(position) as YourUiModel.SlotComponent).component,
    )
    ...
    }
    }

Create a new SlotComponent

Dynamic content supports custom SlotComponents. To create a new SlotComponent you need to:

  • Define the network model for your new SlotComponent.
  • Define your domain model that implements SlotComponentCustomCustomData which your new Composable will receive.
  • Define your network to domain mapper that implements NetworkToDomainSlotComponentCustomMapper. content: Any can be safely cast to your network model.
  • To support DynamicAction.UpdateComponent, you need to:
    • Define your update model that implements SlotComponentCustomUpdateCustomData which usually is a copy of your domain model with all fields nullable.
    • Define your update to domain mapper that implements SlotComponentCustomUpdateToCustomDataMapper where you create a new SlotComponentCustomCustomData updating the existing one with the new field received on SlotComponentCustomUpdateCustomData
  • Create your new Composable component that receives a Modifier and the UiSlotComponent.
  • Create an object of CustomSlotComponentRegister.Default in your Application.onCreate:
    CustomSlotComponentRegister.Default(
    slotComponentType = "your slot component type identifier",
    networkToDomainMapper = inject<MyNetworkToDomainlotComponentCustomMapper>(),
    networkModelClass = MyNetworkSlotComponent::class.java,
    updateMapper = inject<MySlotComponentCustomUpdateToCustomDataMapper>(),
    composable = { modifier, slotComponent -> MySlotComponent(modifier, slotComponent.customData as MyDomainModel) },
    ).register()

Custom SlotComponent with validation

If your new SlotComponent requires validation rules (such as a mandatory text field), your domain model needs to also implement UiValidationComponent

Create a new SlotComponent Container

Dynamic content supports custom SlotComponents Container, a specialized component that shows other components (like a column or a row). To create a new SlotComponent.Container, the steps are the same as create a default SlotComponent with these differences:

  • Your network to domain mapper needs to implement NetworkToDomainSlotComponentCustomContainerMapper
  • Create an object of CustomSlotComponentRegister.Container in your Application.onCreate:
    CustomSlotComponentRegister.Container(
    slotComponentType = "your slot component type identifier",
    networkToDomainMapper = inject<MyNetworkToDomainSlotComponentCustomContainerMapper>(),
    networkModelClass = MyNetworkSlotComponent::class.java,
    updateMapper = inject<MySlotComponentCustomUpdateToCustomDataMapper>(),
    composable = { modifier, slotComponent -> MySlotComponent(modifier, slotComponent.customData as MyDomainModel) },
    ).register()

Create a new Modifier

Dynamic content supports the creation of custom modifiers. To create a new Modifier, you need to:

  • Define your network model that implements NetworkSlotComponentModifiersCustomData defining all your new Modifiers.
  • Define your domain model that implements SlotComponentModifierCustomCustomData defining all your new Modifiers.
  • Define your network to domain mapper that implements NetworkToDomainSlotComponentCustomDataMapper and provide your implementation via Koin.
  • Define your domain to UI mapper that implements DomainToUiModifierCustomMapper returning all your new modifiers as a single Compose modifier. Provide your mapper implementation via Koin.

How to add a new headers to Dynamic content requests

Dynamic content supports adding new headers to all requests. To add a new headers, you need to:

  • Define your domain modile that implements DynamicContentRequestCustomData defining your extra header data.
  • Decorate GetDynamicContentRequest to include your new data into DynamicContentRequest.
  • Decorate MapDynamicContentHeaders to map your new header and merge it with result from the PoqSDK implementation.

How to add a new custom conditions to the existing header

Dynamic content supports conditions to personalize the content. To add custom conditions, you need to include them into DynamicContentRequest.customConditions, the PoqSDK takes care of the rest. You can include your custom conditions decorating GetDynamicContentRequest if you want to include them to all Dynamic content requests.

How to add a new Dynamic content provider

Dynamic content supports the personalisation of the content via API headers defined with DynamicContentUser. If you need to add a new Dynamic content provider, you need to:

Create a new Dynamic action

Dynamic content supports custom DynamicAction. To create a new DynamicAction you need to:

  • Define the network model for your new DynamicAction.
  • Define your domain model that implements DynamicActionCustomCustomData which your new action will receive.
  • Define your network to domain mapper that implements NetworkToDomainDynamicActionCustomMapper. content: Any can be safely cast to your network model.
  • You can create these custom actions:
    • Default: a generic DynamicAction. You need to implement defaultAction function.
    • Navigation: a DynamicAction to navigate the user. You need to implement navigate function with your navigation logic.
    • Suspend: a DynamicAction to long operation which requires show a loading to the user. You need to implement suspendAction function
  • Create an object of CustomDynamicActionRegister in your Application.onCreate:
    CustomSlotComponentRegister.{Type}(
    action = "your new action type identifier",
    networkToDomainMapper = inject<MyNetworkToDomainDynamicActionCustomMapper>(),
    networkModelClass = MyNetworkDynamicActionClass::class.java,
    action = { ... },
    ).register()

How to support Dynamic actions on a new screen

If you are adding slots to a new screen and you want to support dynamic actions on that screen, you need to:

  • Implement DynamicActionHost on your ViewModel where:
    • dynamicPageId: String?: unique id for your screen
    • dynamicContext: MutableDynamicContext: usually an empty mutable map.
    • setIsLoading(isLoading: Boolean): add logic to hide/show a loading state
    • setError(poqError: PoqError): add logic to show an error state
    • navigate(action: DynamicAction.Navigation): add logic to Navigate, you can use DynamicActionNavigator
    • onDynamicAction(actions: List<DynamicAction>): add logic to handle dynamic actions using DynamicActionListHandler
  • Send your instance of your DynamicActionHost to the UiSlotComponents, usually using DomainToUiSlotComponentMapper