From 9fdc134af246e09abe766089c0531621f9e542b4 Mon Sep 17 00:00:00 2001 From: Ryan Morales Date: Fri, 8 Nov 2024 13:12:37 -0800 Subject: [PATCH] initial batch of updates for android content card ui documentation --- gatsby-config.js | 164 ++++++++++++++++++ .../content-card-ui/Android/api-usage.md | 68 ++++++++ .../content-card-ui/Android/index.md | 77 ++++++++ .../Android/public-classes/aepui.md | 161 +++++++++++++++++ .../content-provider/aepuicontentprovider.md | 40 +++++ .../content-provider/contentcarduiprovider.md | 44 +++++ .../public-classes/contentcardmapper.md | 57 ++++++ .../contentcarduieventlistener.md | 92 ++++++++++ .../observers/aepuieventobserver.md | 26 +++ .../observers/contentcardeventobserver.md | 19 ++ .../public-classes/state/aepcarduistate.md | 18 ++ .../state/smallimagecarduistate.md | 18 ++ .../Android/public-classes/styles/README.md | 12 ++ .../public-classes/styles/aepbuttonstyle.md | 15 ++ .../public-classes/styles/aepcardstyle.md | 13 ++ .../public-classes/styles/aepcolumnstyle.md | 12 ++ .../public-classes/styles/aepiconstyle.md | 11 ++ .../public-classes/styles/aepimagestyle.md | 14 ++ .../public-classes/styles/aeprowstyle.md | 11 ++ .../public-classes/styles/aeptextstyle.md | 14 ++ .../styles/smallimageuistyle.md | 38 ++++ .../public-classes/ui-models/README.md | 11 ++ .../public-classes/ui-models/aepbutton.md | 11 ++ .../public-classes/ui-models/aepicon.md | 9 + .../public-classes/ui-models/aepimage.md | 10 ++ .../public-classes/ui-models/aeptext.md | 9 + .../public-classes/ui-models/aepuitemplate.md | 15 ++ .../ui-models/aepuitemplatetype.md | 11 ++ .../ui-models/smallimagetemplate.md | 27 +++ .../Android/public-classes/uiaction.md | 50 ++++++ .../Android/public-classes/uievent.md | 103 +++++++++++ .../customizing-content-card-templates.md | 63 +++++++ .../tutorial/displaying-content-cards.md | 136 +++++++++++++++ .../tutorial/listening-content-card-events.md | 117 +++++++++++++ .../SmallImageCard composable layout.png | Bin 0 -> 59768 bytes 35 files changed, 1496 insertions(+) create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/api-usage.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/index.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/aepui.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/content-provider/aepuicontentprovider.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/content-provider/contentcarduiprovider.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/contentcardmapper.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/contentcarduieventlistener.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/observers/aepuieventobserver.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/observers/contentcardeventobserver.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/state/aepcarduistate.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/state/smallimagecarduistate.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/README.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepbuttonstyle.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepcardstyle.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepcolumnstyle.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepiconstyle.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepimagestyle.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aeprowstyle.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aeptextstyle.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/smallimageuistyle.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/README.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aepbutton.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aepicon.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aepimage.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aeptext.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aepuitemplate.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aepuitemplatetype.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/smallimagetemplate.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/uiaction.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/uievent.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/tutorial/customizing-content-card-templates.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/tutorial/displaying-content-cards.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/tutorial/listening-content-card-events.md create mode 100644 src/pages/edge/adobe-journey-optimizer/content-card-ui/assets/Android/SmallImageCard composable layout.png diff --git a/gatsby-config.js b/gatsby-config.js index 67e5e40d89..1735389448 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -343,6 +343,170 @@ module.exports = { ] } ] + }, + { + title: "Android", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android", + pages: [ + { + title: "API Reference", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/api-usage.md" + }, + { + title: "Public Classes and Interfaces", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/aepui", + pages: [ + { + title: "AepUI", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/aepui", + }, + { + title: "ContentCardMapper", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/contentcardmapper", + }, + { + title: "ContentCardUIEventListener", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/contentcarduieventlistener", + }, + { + title: "UIAction", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/uiaction", + }, + { + title: "UIEvent", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/uievent", + } + ] + }, + { + title: "Content Provider", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/content-provider/aepuicontentprovider", + pages: [ + { + title: "AepUIContentProvider", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/content-provider/aepuicontentprovider", + }, + { + title: "ContentCardUIProvider", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/content-provider/contentcarduiprovider", + } + ] + }, + { + title: "Observers", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/observers/aepuieventobserver", + pages: [ + { + title: "AepUIContentProvider", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/observers/aepuieventobserver", + }, + { + title: "ContentCardUIProvider", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/observers/aepuieventobserver", + } + ] + }, + { + title: "State", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/state/aepcarduistate", + pages: [ + { + title: "AepCardUIState", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/state/aepcarduistate", + }, + { + title: "SmallImageCardUIState", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/state/smallimagecarduistate", + } + ] + }, + { + title: "Styles", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepbuttonstyle", + pages: [ + { + title: "AepButtonStyle", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepbuttonstyle", + }, + { + title: "AepCardStyle", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepcardstyle", + }, + { + title: "AepColumnStyle", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepcolumnstyle", + }, + { + title: "AepIconStyle", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepiconstyle", + }, + { + title: "AepImageStyle", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepimagestyle", + }, + { + title: "AepRowStyle", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aeprowstyle", + }, + { + title: "SmallImageUIStyle", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/smallimageuistyle", + } + ] + }, + { + title: "UI Models", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/", + pages: [ + { + title: "AEPButton", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aepbutton" + }, + { + title: "AEPIcon", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aepicon" + }, + { + title: "AEPImage", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aepimage" + }, + { + title: "AEPText", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aeptext" + }, + { + title: "AEPTemplate", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aeptemplate" + }, + { + title: "AEPTemplateType", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aeptemplatetype" + }, + { + title: "SmallImageTemplate", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/smallimagetemplate" + } + ] + }, + { + title: "Tutorials", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/tutorial/displaying-content-cards", + pages: [ + { + title: "Fetch and Display Content Cards", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/tutorial/displaying-content-cards", + }, + { + title: "Customizing Content Cards", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/tutorial/customizing-content-card-templates", + }, + { + title: "Listening to Content Card Events", + path: "/edge/adobe-journey-optimizer/content-card-ui/Android/tutorial/listening-content-card-events", + } + ] + } + ] } ] }, diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/api-usage.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/api-usage.md new file mode 100644 index 0000000000..702b5b3d07 --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/api-usage.md @@ -0,0 +1,68 @@ +--- +title: Content Card UI API Usage +description: Learn how to use the Messaging extension APIs to implement content card with UI. +keywords: +- Adobe Journey Optimizer +- Guide +- Content Card +- Messaging +- Customizing UI +- Card Templates +- Content Card Templates +- Small Image Template +- Android +--- + +# API Reference + +This document lists the public APIs available in the Messaging extension for implementing content card with UI. + +### getContentCardUI + +The `getContentCardUI` method retrieves a flow of [AepUI](./public-classes/aepui.md) objects for the provided surface. These `AepUI` objects represent templated content cards whose UI can be rendered using provided card composables. + + + +Calling this API will not download content cards from Adobe Journey Optimizer; it will only retrieve the content cards that are already downloaded and cached by the Messaging extension. You **must** call [`updatePropositionsForSurfaces`](../api-usage.md#updatePropositionsForSurfaces) API from the AEPMessaging extension with the desired surfaces prior to calling this API. + +#### Syntax + + + +#### Kotlin + +```kotlin +suspend fun getContentCardUI(): Flow>> +``` + +#### Example + + + +#### Kotlin + +```kotlin +// Download the content cards for homepage surface using Messaging extension +val surfaces = mutableListOf() +val surface = Surface("homepage") +surfaces.add(surface) +Messaging.updatePropositionsForSurfaces(surfaces) + +// Initialize the ContentCardUIProvider +val contentCardUIProvider = ContentCardUIProvider(surface) + +// get the content cards within a view model +class MyScreenViewModel : ViewModel { + private val contentCardUIProvider = MessagingContentCardProvider(...) + private val _aepUIList = MutableStateFlow>>(emptyList()) + val aepUIList: StateFlow>> = _aepUIList.asStateFlow() + + // fetch the list of cards when necessary + viewModelScope.launch { + contentCardUIProvider.getContentCardUI().collect { + aepUi -> + _aepUIList.value = aepUi + } + } +} +``` diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/index.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/index.md new file mode 100644 index 0000000000..4787abeca3 --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/index.md @@ -0,0 +1,77 @@ +--- +title: Content Card UI +description: These documents guide you to integrating a content card ui message with an Android app. +keywords: +- Adobe Journey Optimizer +- Guide +- Content Card +- Messaging +- Customizing UI +- Card Templates +- Content Card Templates +- Small Image Template +- Android +--- + +# Content Card UI + +## Requirements + +* Latest version of [Android Studio](https://developer.android.com/studio) +* Android API 21 (or newer) +* Kotlin 1.5.0 (or newer) +* App with support for [Jetpack Compose](https://developer.android.com/develop/ui/compose/setup) + +## API Reference + +* [Content Card API's](./api-usage.md) + +## Public Classes, Enums, and Interfaces + +- [Interface - AepUI](./public-classes/aepui.md) +- [Class - ContentCardMapper](./public-classes/contentcardmapper.md) +- [Interface - ContentCardUIEventListener](./public-classes/contentcarduieventlistener.md) +- [Class - UIAction](./public-classes/uiaction.md) +- [Class - UIEvent](./public-classes/uievent.md) + +## Content Provider + +- [AepUIContentProvider](./public-classes/content-provider/aepuicontentprovider.md) +- [ContentCardUIProvider](./public-classes/content-provider/contentcarduiprovider.md) + +## Observers + +- [AepUIEventObserver](./public-classes/observers/aepuieventobserver.md) +- [ContentCardEventObserver](./public-classes/observers/contentcardeventobserver.md) + +## State + +- [AepCardUIState](./public-classes/state/aepcarduistate.md) +- [SmallImageCardUIState](./public-classes/state/smallimagecarduistate.md) + +## Styles + +- [AepButtonStyle](./public-classes/styles/aepbuttonstyle.md) +- [AepCardStyle](./public-classes/styles/aepcardstyle.md) +- [AepColumnStyle](./public-classes/styles/aepcolumnstyle.md) +- [AepIconStyle](./public-classes/styles/aepiconstyle.md) +- [AepImageStyle](./public-classes/styles/aepimagestyle.md) +- [AepRowStyle](./public-classes/styles/aeprowstyle.md) +- [AepTextStyle](./public-classes/styles/aeptextstyle.md) +- [SmallImageUIStyle](./public-classes/styles/smallimageuistyle.md) + +## UI Models + +* [AepButton](./public-classes/ui-models/aepbutton.md) +* [AepIcon](./public-classes/ui-models/aepicon.md) +* [AepImage](./public-classes/ui-models/aepimage.md) +* [AepText](./public-classes/ui-models/aeptext.md) +* [AepUITemplate](./public-classes/ui-models/aepuitemplate.md) +* [AepUITemplateType](./public-classes/ui-models/aepuitemplatetype.md) +* [SmallImageTemplate](./public-classes/ui-models/smallimagetemplate.md) + +## Tutorials + +* [Fetch and Display Content Cards](./tutorial/displaying-content-cards.md) +* [Customizing Content Card Templates](./tutorial/customizing-content-card-templates.md) +* [Listening to Content Card Events](./tutorial/listening-content-card-events.md) diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/aepui.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/aepui.md new file mode 100644 index 0000000000..2e8148b8b4 --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/aepui.md @@ -0,0 +1,161 @@ +--- +title: AepUI +description: This document contains information regarding the AepUI interface and it's implementations. +keywords: +- Adobe Journey Optimizer +- Guide +- Content Card +- Messaging +- Customizing UI +- Card Templates +- Content Card Templates +- Small Image Template +- Android +--- + +# AepUI + +The `AepUI` interface represents a UI component that can be rendered using the AEP compose UI library. The AEP compose UI currently supports rendering the following UI templates: + +1. `SmallImageUI` which renders `Small Image template` + +## Interface Definition + + + +```kotlin +sealed interface AepUI { + fun getTemplate(): T + fun getState(): S + fun updateState(newState: S) +} +``` + +## Methods + +### getTemplate + +Retrieves the template associated with this UI component. + +#### Returns + +A template of type `T` which is an implementation of the `AepUITemplate` interface + +#### Syntax + + + +#### Kotlin + +``` kotlin +fun getTemplate(): T +``` + +### getState + +Retrieves the current state of the UI component. + +#### Returns + +A state of type `S` which is a subclass of the `AepCardUIState` class. + +#### Syntax + + + +#### Kotlin + +``` kotlin +fun getState(): S +``` + +### updateState + +Updates the state of the UI component with a new state. + +#### Parameters + +- _newState_ - The new state of type `S` to update within the UI component. + +#### Syntax + + + +#### Kotlin + +``` kotlin +fun updateState(newState: S) +``` + +# Implementing Classes + +## SmallImageUI + +Implementation of the [AepUI](./aepui.md#Sealed Interface - AepUI) interface used in rendering a UI for a [SmallImageTemplate](./UIModels/smallimagetemplate.md). + +## Class Definition + + + +```kotlin +class SmallImageUI( + private val template: SmallImageTemplate, + state: SmallImageCardUIState +) : AepUI +``` + +## Methods + +### getTemplate + +Retrieves the template associated with the small image UI. + +#### Returns + +The small image template. + +#### Syntax + + + +#### Kotlin + +``` kotlin +override fun getTemplate(): SmallImageTemplate +``` + +### getState + +Retrieves the current state of the small image UI. + +#### Returns + +The current SmallImageCardUIState. + +#### Syntax + + + +#### Kotlin + +``` kotlin +override fun getState(): SmallImageCardUIState +``` + +### updateState + +Updates the current state of the small image UI. + +#### Parameters + +- _newState_ - The new state of type `SmallImageCardUIState` to update within the UI component. + +#### Syntax + + + +#### Kotlin + +``` kotlin +override fun updateState(newState: SmallImageCardUIState) +``` diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/content-provider/aepuicontentprovider.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/content-provider/aepuicontentprovider.md new file mode 100644 index 0000000000..dcb399431f --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/content-provider/aepuicontentprovider.md @@ -0,0 +1,40 @@ +# Interface - AepUIContentProvider + +Responsible for retrieving and refreshing data as required by the UI. + +Classes implementing this interface will define a strategy to provide content for rendering the UI. + +## Interface Definition + +```kotlin +interface AepUIContentProvider { + suspend fun getContent(): Flow> + suspend fun refreshContent() +} +``` + +## Methods + +### getContent + +Retrieves the content for the UI. + +#### Returns + +The content for the UI as a flow of [AepUITemplate](../UIModels/aepuitemplate.md)s. + +#### Syntax + +```kotlin +suspend fun getContent(): Flow> +``` + +### refreshContent + +Refreshes the content for the UI. Implementations should update the data into the flow returned by [getContent](./aepuicontentprovider.md#getContent). + +#### Syntax + +```kotlin +suspend fun refreshContent() +``` \ No newline at end of file diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/content-provider/contentcarduiprovider.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/content-provider/contentcarduiprovider.md new file mode 100644 index 0000000000..aff9d50ce4 --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/content-provider/contentcarduiprovider.md @@ -0,0 +1,44 @@ +# Class - ContentCardUIProvider + +Messaging extension implementation of [AepUIContentProvider](./aepuicontentprovider.md). ContentCardUiProvider is responsible for fetching and managing the content for a given surface. It uses Adobe Messaging APIs to retrieve propositions and transform them into UI templates for display. + +## Methods + +### getContent + +Retrieves a flow of AepUITemplate lists for the given surface. The flow emits updates whenever new content is fetched. + +#### Returns + +A flow that emits lists of [AepUITemplate](../UIModels/aepuitemplate.md)s. + +#### Syntax + +```kotlin +override suspend fun getContent(): Flow> +``` + +### getContentCardUI + +Retrieves a flow of AepUI instances for the given surface. This function initiates the content fetch using [getContent](./contentcarduiprovider.md#getcontent) and then returns a flow of AepUI instances that represent the UI templates. The flow emits updates whenever new content is fetched or any changes occur. + +#### Returns + +A [Flow](https://developer.android.com/kotlin/flow) that emits a list of AepUI instances. + +#### Syntax + +```kotlin +suspend fun getContentCardUI(): Flow>> +``` + +### refreshContent + +Updates the flow returned by [getContent](#getContent) with the latest cached content cards for the given surface. + +#### Syntax + +```kotlin +override suspend fun refreshContent() +``` + diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/contentcardmapper.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/contentcardmapper.md new file mode 100644 index 0000000000..6917edd6c9 --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/contentcardmapper.md @@ -0,0 +1,57 @@ +--- +title: ContentCardMapper +description: This document contains information regarding the usage of the Content Card Mapper. +keywords: +- Adobe Journey Optimizer +- Guide +- Content Card +- Messaging +- Customizing UI +- Card Templates +- Content Card Templates +- Small Image Template +- Android +--- + +# ContentCardMapper + +Singleton class used to store a mapping between valid [ContentCardSchemaData](../../../public-classes/content-card-schema-data.md) and unique proposition id's. The schema data is used when sending proposition track requests to AJO. + +## Class Definition + + + +```kotlin +class ContentCardMapper private constructor() { + private val contentCardSchemaDataMap: MutableMap = HashMap() + + companion object { + @JvmStatic + val instance: ContentCardMapper by lazy { ContentCardMapper() } + } +} +``` + +## Methods + +### getContentCardSchemaData + +Returns a `ContentCardSchemaData` object for the given proposition id. + +#### Parameters + +- _propositionId_ - the proposition id to use as a key in the `ContentCardSchemaData` map. + +#### Returns + +The `ContentCardSchemaData` for the given proposition id, or null if not found + +#### Syntax + + + +#### Kotlin + +```kotlin +fun getContentCardSchemaData(propositionId: String): ContentCardSchemaData? +``` diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/contentcarduieventlistener.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/contentcarduieventlistener.md new file mode 100644 index 0000000000..5c6138b518 --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/contentcarduieventlistener.md @@ -0,0 +1,92 @@ +--- +title: ContentCardUIEventListener +description: This document contains information regarding the ContentCardUIEventListener and its callback functions. +keywords: +- Adobe Journey Optimizer +- Guide +- Content Card +- Messaging +- Customizing UI +- Card Templates +- Content Card Templates +- Small Image Template +- Android +--- + +# ContentCardUIEventListener + +Interface to handle different callback events which can occur for a displayed content card. + +## Interface Definition + + + +```kotlin +interface ContentCardUIEventListener { + fun onDisplay(aepUI: AepUI<*, *>,) + fun onDismiss(aepUI: AepUI<*, *>,) + fun onInteract(aepUI: AepUI<*, *>, interactionId: String?, actionUrl: String?): Boolean +} +``` + +## Methods + +### onDisplay + +Callback to invoke when a content card is displayed. + +#### Parameters + +- _aepUI_ - The [AepUI](./aepui.md) instance that was displayed. + +#### Syntax + + + +#### Kotlin + +```kotlin +fun onDisplay(aepUI: AepUI<*, *>,) +``` + +### onDismiss + +Callback to invoke when a content card is dismissed. + +#### Parameters + +- _aepUI_ - The [AepUI](./aepui.md) instance that was dismissed. + +#### Syntax + + + +#### Kotlin + +```kotlin +fun onDismiss(aepUI: AepUI<*, *>,) +``` + +### onInteract + +Callback to invoke when a content card is interacted with. + +#### Parameters + +- _aepUI_ - The [AepUI](./aepui.md) instance that was interacted with. +- _interactionId_ - An optional string identifier for the interaction event. +- _actionUrl_ - An optional URL associated with the interaction. + +#### Returns + +A boolean value indicating whether the interaction event was handled. Return `true` if the client app has handled the `actionUrl` associated with the interaction. Return `false` if the SDK should handle the `actionUrl`. + +#### Syntax + + + +#### Kotlin + +```kotlin +fun onInteract(aepUI: AepUI<*, *>, interactionId: String?, actionUrl: String?): Boolean +``` \ No newline at end of file diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/observers/aepuieventobserver.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/observers/aepuieventobserver.md new file mode 100644 index 0000000000..2d7ceb8289 --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/observers/aepuieventobserver.md @@ -0,0 +1,26 @@ +# Interface - AepUIEventObserver + +Interface for observing events related to AEP UI components. This interface defines a mechanism for handling various types of events triggered by lifecycle changes or user interactions with UI elements, such as display, dismiss, or user interaction events. +## Interface Definition + +```kotlin +interface AepUIEventObserver { + fun onEvent(event: UIEvent<*, *>) +} +``` + +## Methods + +### onEvent + +Called when an event related to a UI template occurs. + +#### Parameters + +- _event_ - The event to handle. Implementers can provide specific logic based on the type of UIEvent + +#### Syntax + +```kotlin +fun onEvent(event: UIEvent<*, *>) +``` diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/observers/contentcardeventobserver.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/observers/contentcardeventobserver.md new file mode 100644 index 0000000000..90711483b1 --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/observers/contentcardeventobserver.md @@ -0,0 +1,19 @@ +# Class - ContentCardEventObserver + +Messaging implementation of [AepUIEventObserver](./aepuieventobserver.md) for handling content card events. + +#### Class Parameters + +- _callback_ - An optional [ContentCardUIEventListener](../contentcarduieventlistener.md) to invoke when a content card event occurs. + +## Methods + +### onEvent + +Called when an event related to a Content Card UI template occurs. + +#### Syntax + +```kotlin +override fun onEvent(event: UIEvent<*, *>) +``` diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/state/aepcarduistate.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/state/aepcarduistate.md new file mode 100644 index 0000000000..6a815aaf78 --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/state/aepcarduistate.md @@ -0,0 +1,18 @@ +# Open Class - AepCardUIState + +Class representing the state of an AEP card. This class includes the common properties `dismissed` and `displayed` which are common across different card states. +## Class Definition + +```kotlin +open class AepCardUIState( + open val dismissed: Boolean = false, + open val displayed: Boolean = false +) +``` + +## Public Properties + +| Property | Type | Description | +| --------- | ------- | ---------------------------------------------- | +| dismissed | Boolean | Indicates whether the card has been dismissed. | +| displayed | Boolean | Indicates whether the card has been displayed. | diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/state/smallimagecarduistate.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/state/smallimagecarduistate.md new file mode 100644 index 0000000000..8802dde199 --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/state/smallimagecarduistate.md @@ -0,0 +1,18 @@ +# Data Class - SmallImageCardUIState + +Class representing the UI state of a Small Image template card. +## Class Definition + +```kotlin +data class SmallImageCardUIState( + override val dismissed: Boolean = false, + override val displayed: Boolean = false +) : AepCardUIState() +``` + +## Public Properties + +| Property | Type | Description | +| --------- | ------- | ---------------------------------------------- | +| dismissed | Boolean | Indicates whether the card has been dismissed. | +| displayed | Boolean | Indicates whether the card has been displayed. | diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/README.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/README.md new file mode 100644 index 0000000000..aa16a5fa9f --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/README.md @@ -0,0 +1,12 @@ +# Styles + +Messaging provides the following styles that can be used to customize the UI elements of content cards: + +- [AepButtonStyle](./aepbuttonstyle.md) +- [AepCardStyle](./aepcardstyle.md) +- [AepColumnStyle](./aepcolumnstyle.md) +- [AepIconStyle](./aepiconstyle.md) +- [AepImageStyle](./aepimagestyle.md) +- [AepRowStyle](./aeprowstyle.md) +- [AepTextStyle](./aeptextstyle.md) +- [SmallImageUIStyle](./smallimageuistyle.md) diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepbuttonstyle.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepbuttonstyle.md new file mode 100644 index 0000000000..501fe8abb7 --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepbuttonstyle.md @@ -0,0 +1,15 @@ +# Class - AepButtonStyle + +Class representing the style of an AEPButton Composable. + +## Public Properties + +| Property | Type | Description | +| -------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| modifier | [Modifier](https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier)? | The modifier to be applied to the button. | +| enabled | Boolean? | The enabled state of the button. | +| elevation | [ButtonElevation](https://developer.android.com/reference/kotlin/androidx/compose/material3/ButtonElevation?hl=en)? | The elevation of the button. | +| shape | [Shape](https://developer.android.com/reference/kotlin/androidx/compose/ui/graphics/Shape?hl=en)? | The shape of the button. | +| border | [BorderStroke](https://developer.android.com/reference/kotlin/androidx/compose/foundation/BorderStroke?hl=en)? | The border to draw around the container of this button. | +| colors | [ButtonColors](https://developer.android.com/reference/kotlin/androidx/compose/material3/ButtonColors?hl=en)? | The colors that will be used for this button in different states. | +| contentPadding | [PaddingValues](https://developer.android.com/reference/kotlin/androidx/compose/foundation/layout/PaddingValues?hl=en)? | The spacing values to apply internally between the container and the text. | diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepcardstyle.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepcardstyle.md new file mode 100644 index 0000000000..d9651010f0 --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepcardstyle.md @@ -0,0 +1,13 @@ +# Class - AepCardStyle + +Class representing the style for a Card Composable. + +## Public Properties + +| Property | Type | Description | +| --------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| modifier | [Modifier](https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier)? | The modifier to be applied to the card. | +| shape | [Shape](https://developer.android.com/reference/kotlin/androidx/compose/ui/graphics/Shape?hl=en)? | The shape of the card. | +| colors | [CardColors](https://developer.android.com/reference/kotlin/androidx/compose/material3/CardColors?hl=en)? | The colors that will be used to resolve the colors for this card in different states. | +| elevation | [CardElevation](https://developer.android.com/reference/kotlin/androidx/compose/material3/CardElevation?hl=en)? | The elevation of the button. | +| border | [BorderStroke](https://developer.android.com/reference/kotlin/androidx/compose/foundation/BorderStroke?hl=en)? | The border to draw around the container of this button. | diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepcolumnstyle.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepcolumnstyle.md new file mode 100644 index 0000000000..c5450fa224 --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepcolumnstyle.md @@ -0,0 +1,12 @@ +# Class - AepColumnStyle + +Class representing the style for a column AEP UI. + +## Public Properties + +| Property | Type | Description | +| ------------------- | ------------------------------------------------------------ | ---------------------------------------- | +| modifier | [Modifier](https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier)? | The modifier for the column. | +| verticalArrangement | [Arrangement.Vertical](https://developer.android.com/reference/kotlin/androidx/compose/foundation/layout/Arrangement.Vertical)? | The vertical arrangement for the column. | +| horizontalAlignment | [Alignment.Horizontal](https://developer.android.com/reference/kotlin/androidx/compose/ui/Alignment.Horizontal?hl=en)? | The horizontal alignment for the column. | + diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepiconstyle.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepiconstyle.md new file mode 100644 index 0000000000..c84124469a --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepiconstyle.md @@ -0,0 +1,11 @@ +# Class - AepIconStyle + +Class representing the style for an AepIcon composable. + +## Public Properties + +| Property | Type | Description | +| ------------------ | ------------------------------------------------------------ | ------------------------------------- | +| modifier | [Modifier](https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier)? | The modifier for the icon. | +| contentDescription | String? | The content description for the icon. | +| tint | [ColorProducer](https://developer.android.com/reference/kotlin/androidx/compose/ui/graphics/ColorProducer?hl=en)? | The tint color for the icon. | diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepimagestyle.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepimagestyle.md new file mode 100644 index 0000000000..69bdc76785 --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aepimagestyle.md @@ -0,0 +1,14 @@ +# Class - AepImageStyle + +Class representing the style for an AepImage composable. + +## Public Properties + +| Property | Type | Description | +| ------------------ | ------------------------------------------------------------ | -------------------------------------- | +| modifier | [Modifier](https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier)? | The modifier for the image. | +| contentDescription | String? | The content description for the image. | +| alignment | [Alignment](https://developer.android.com/reference/kotlin/androidx/compose/ui/Alignment)? | The alignment for the image. | +| contentScale | [ContentScale](https://developer.android.com/reference/kotlin/androidx/compose/ui/layout/ContentScale?hl=en)? | The content scale for the image. | +| alpha | Float? | The alpha value for the image. | +| colorFilter | [ColorFilter](https://developer.android.com/reference/kotlin/androidx/compose/ui/graphics/ColorFilter?hl=en)? | The color filter for the image. | diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aeprowstyle.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aeprowstyle.md new file mode 100644 index 0000000000..c2992af709 --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aeprowstyle.md @@ -0,0 +1,11 @@ +# Class - AepRowStyle + +Class representing the style for a row AEP UI. + +## Public Properties + +| Property | Type | Description | +| --------------------- | ------------------------------------------------------------ | --------------------------------------- | +| modifier | [Modifier](https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier)? | The modifier for the row. | +| horizontalArrangement | [Arrangement.Horizontal](https://developer.android.com/reference/kotlin/androidx/compose/foundation/layout/Arrangement.Horizontal?hl=en)? | The horizontal arrangement for the row. | +| verticalAlignment | [Alignment.Vertical](https://developer.android.com/reference/kotlin/androidx/compose/ui/Alignment.Vertical?hl=en)? | The vertical alignment for the row. | diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aeptextstyle.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aeptextstyle.md new file mode 100644 index 0000000000..5f83d13ebb --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/aeptextstyle.md @@ -0,0 +1,14 @@ +# Class - AepTextStyle + +Class representing the style of an AEPText Composable. + +## Public Properties + +| Property | Type | Description | +| --------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| modifier | [Modifier](https://developer.android.com/reference/kotlin/androidx/compose/ui/Modifier)? | The modifier to be applied to the text. | +| textStyle | [TextStyle](https://developer.android.com/reference/kotlin/androidx/compose/ui/text/TextStyle)? | The style configuration for the text such as color, font, line height etc. | +| overflow | [TextOverflow](https://developer.android.com/reference/kotlin/androidx/compose/ui/text/style/TextOverflow?hl=en)? | The overflow strategy for the text. | +| softWrap | Boolean? | Whether the text should break at soft line breaks. | +| maxLines | Int? | The maximum number of lines to display. | +| minLines | Int? | The minimum number of lines to display. | diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/smallimageuistyle.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/smallimageuistyle.md new file mode 100644 index 0000000000..b260a68171 --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/styles/smallimageuistyle.md @@ -0,0 +1,38 @@ +# Class - SmallImageUIStyle + +Class representing the style for a small image AEP UI. + +![Small Image Card Composeable Layout](../../../assets/Android/SmallImageCard composable layout.png) + +## Public Properties + +| Property | Type | Description | +| ---------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | +| cardStyle | [AepCardStyle](./aepcardstyle.md) | The style for the card. | +| rootRowStyle | [AepRowStyle](./aeprowstyle.md) | The style for the root row. | +| imageStyle | [AepImageStyle](./aepimagestyle,md) | The style for the image. | +| textColumnStyle | [AepColumnStyle](./aepcolumnstyle.md) | The style for the column containing the title, body and buttons. | +| titleTextStyle | [AepTextStyle](./aeptextstyle.md) | The text style for the title. | +| bodyTextStyle | [AepTextStyle](./aeptextstyle.md) | The text style for the body. | +| buttonRowStyle | [AepRowStyle](./aeprowstyle.md) | The style for the row containing the buttons. | +| buttonStyle | Array> | The style for the buttons. | +| dismissButtonStyle | [AepIconStyle](./aepiconstyle.md) | The style for the dismiss button. | +| dismissButtonAlignment | [Alignment](https://developer.android.com/reference/kotlin/androidx/compose/ui/Alignment) | The alignment for the dismiss button. | + +## Customization + +The `SmallImageUIStyle` is created using a builder. Here's an example: + +```kotlin +// Displaying content cards in a Row +// create a custom style for the small image card in row +val smallImageCardStyleRow = SmallImageUIStyle.Builder() + .cardStyle(AepCardStyle(modifier = Modifier.width(400.dp).height(200.dp))) + .rootRowStyle( + AepRowStyle( + modifier = Modifier.fillMaxSize() + ) + ) + .titleAepTextStyle(AepTextStyle(textStyle = TextStyle(Color.Green))) + .build() +``` \ No newline at end of file diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/README.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/README.md new file mode 100644 index 0000000000..a64baec861 --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/README.md @@ -0,0 +1,11 @@ +# UI Models + +Messaging provides the following UI Models that act as building blocks for creating templated content cards: + +- [AepButton](./aepbutton.md) +- [AepIcon](./aepicon.md) +- [AepImage](./aepimage.md) +- [AepText](./aeptext.md) +- [AepUITemplate](./aepuitemplate.md) +- [AepUITemplateType](./aepuitemplatetype.md) +- [SmallImageTemplate](./smallimagetemplate.md) diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aepbutton.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aepbutton.md new file mode 100644 index 0000000000..fe82475edb --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aepbutton.md @@ -0,0 +1,11 @@ +# Data Class - AepButton + +Data class representing a button element in the UI. + +## Public Properties + +| Property | Type | Description | +| --- | --- | --- | +| Id | String | The unique ID for the button. | +| actionUrl | String | The URL to be opened when the button is clicked. | +| text | [AepText](./aeptext.md) | The text to be displayed on the button, represented by an AepText object. | diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aepicon.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aepicon.md new file mode 100644 index 0000000000..44a1321805 --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aepicon.md @@ -0,0 +1,9 @@ +# Data Class - AepIcon + +Data class representing an icon element in the UI. + +## Public Properties + +| Property | Type | Description | +| --- | --- | --- | +| drawableId | Int | The drawable resource ID for the icon. | diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aepimage.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aepimage.md new file mode 100644 index 0000000000..a773a3dddd --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aepimage.md @@ -0,0 +1,10 @@ +# Data Class - AepImage + +Data class representing an image element in the UI. + +## Public Properties + +| Property | Type | Description | +| --- | --- | --- | +| url | String? | The URL of the image. | +| darkUrl | String? | The URL of the image for dark mode. | diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aeptext.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aeptext.md new file mode 100644 index 0000000000..1d590b087b --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aeptext.md @@ -0,0 +1,9 @@ +# Data Class - AepText + +Data class representing a text element in the UI. + +## Public Properties + +| Property | Type | Description | +| --- | --- | --- | +| content | String | The content of the text. | diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aepuitemplate.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aepuitemplate.md new file mode 100644 index 0000000000..c417e5b18d --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aepuitemplate.md @@ -0,0 +1,15 @@ +# Interface - AepUITemplate + +Interface representing a generic UI template in AEP. + +## Methods + +### getType + +Gets the type of the UI template. + +#### Syntax + +``` kotlin +fun getType(): AepUITemplateType +``` \ No newline at end of file diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aepuitemplatetype.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aepuitemplatetype.md new file mode 100644 index 0000000000..460162be96 --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/aepuitemplatetype.md @@ -0,0 +1,11 @@ +# Enum - AepUITemplateType + +An enumeration of the different types of content card templates supported by the Messaging framework. + +Each case corresponds to a specific template type, identified by its JSON string value. + +## Enumeration Cases + +| Case | Raw Value | Description | +| ----------- | ------------ | ------------------------------------------------------------ | +| SMALL_IMAGE | `SmallImage` | Represents [SmallImageTemplate](../UIModels/smallimagetemplate.md). | diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/smallimagetemplate.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/smallimagetemplate.md new file mode 100644 index 0000000000..909bc63edf --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/ui-models/smallimagetemplate.md @@ -0,0 +1,27 @@ +# Data Class - SmallImageTemplate + +Class representing a small image template, which implements the [AepUITemplate](aepuitemplate.md) interface. + +## Public Properties + +| Property | Type | Description | +| ---------- | ---------------------------------- | ------------------------------------------------------------ | +| id | String | The unique identifier for this template. | +| title | [AepText](./aeptext.md) | The title text and display settings. | +| body | [AepText](./aeptext.md)? | The body text and display settings. | +| image | [AepImage](./aepimage.md)? | The details of the image to be displayed. | +| actionUrl | String? | The URL to be opened when the the small image card is clicked. | +| buttons | List<[AepButton](./aepbutton.md)>? | The details for the small image template buttons. | +| dismissBtn | [AepIcon](./aepicon.md)? | The details for the small image template dismiss button. | + +## Methods + +### getType + +Returns the type of this template, which is [AepUITemplateType](aepuitemplatetype.md).SMALL_IMAGE. + +#### Syntax + +``` kotlin +override fun getType() = AepUITemplateType.SMALL_IMAGE +``` \ No newline at end of file diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/uiaction.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/uiaction.md new file mode 100644 index 0000000000..e935f920f3 --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/uiaction.md @@ -0,0 +1,50 @@ +--- +title: UIAction +description: This document contains information regarding UIActio and it's action types. +keywords: +- Adobe Journey Optimizer +- Guide +- Content Card +- Messaging +- Customizing UI +- Card Templates +- Content Card Templates +- Small Image Template +- Android +--- + +# UIAction + +Represents an action that can be performed on a UI component. + +#### Syntax + + + +#### Kotlin + +``` kotlin +sealed class UIAction +``` + +## Data Class - Click + +Represents a click UIAction that can be performed on a UI component. + +#### Public Properties + +| Property | Type | Description | +| --------- | ------- | ---------------------------------------------------------- | +| id | String | unique identifier of the UI component | +| actionUrl | String? | optional URL to be opened when the UI component is clicked | + +#### Syntax + + + +#### Kotlin + +``` kotlin +data class Click(val id: String, val actionUrl: String?) : UIAction() +``` + diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/uievent.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/uievent.md new file mode 100644 index 0000000000..dd00260cb9 --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/public-classes/uievent.md @@ -0,0 +1,103 @@ +--- +title: UIEvent +description: This document contains information regarding UIEvent and its supported event types. +keywords: +- Adobe Journey Optimizer +- Guide +- Content Card +- Messaging +- Customizing UI +- Card Templates +- Content Card Templates +- Small Image Template +- Android +--- + +# Class - UIEvent + +Represents different types of UI events that can be triggered by the user interaction on the UI templates. +#### Class Parameters + +| Parameter | Type | Description | +| --------- | -------------------------------------------- | ------------------------------------------------------------ | +| T | [AepUITemplate](./UIModels/aepuitemplate.md) | Represents a UI template model which backs the composable on which the event has occurred. | +| S | [AepCardUIState](./State/aepcarduistate.md) | Represents the state of the AEP card composable on which the event has occurred. | + +#### Syntax + + + +#### Kotlin + +``` kotlin +sealed class UIEvent(open val aepUi: AepUI) +``` + +#### Public Properties + +| Property | Type | Description | +| -------- | ------------------- | ------------------------------------ | +| aepUI | [AepUI](./aepui.md) | The AepUI associated with the event. | + +## Data Class - Display + +Event that represents the display of a UI element. + +#### Syntax + + + +#### Kotlin + +``` kotlin +data class Display(override val aepUi: AepUI) : + UIEvent(aepUi) +``` + +## Data Class - Interact + +Event that represents a user interaction with a UI element. The `Interact` event captures the different types of interactions that a user can have with a UI component. Currently supported interactions types are can be seen in [UIAction](./uiaction.md) documentation. + +#### Public Properties + +| Property | Type | Description | +| -------- | ------------------------- | --------------------------- | +| action | [UIAction](./uiaction.md) | The UIAction that occurred. | + +#### Syntax + + + +#### Kotlin + +``` kotlin +data class Interact( + override val aepUi: AepUI, + val action: UIAction + ) : UIEvent(aepUi) +``` + +#### Example + + + +#### Kotlin + +```kotlin +observer?.onEvent(AepUiEvent.Interact(ui, UIAction.Click(id = "purchaseID", actionUrl = "https://www.adobe.com")) +``` + +## Data Class - Dismiss + +Event that represents the dismissal of a UI element. + +#### Syntax + + + +#### Kotlin + +``` kotlin +data class Dismiss(override val aepUi: AepUI) : + UIEvent(aepUi) +``` diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/tutorial/customizing-content-card-templates.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/tutorial/customizing-content-card-templates.md new file mode 100644 index 0000000000..b2c5786356 --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/tutorial/customizing-content-card-templates.md @@ -0,0 +1,63 @@ +--- +title: Customizing Content Card Templates style +description: This document contains a tutorial on how to customize content card templates style. +keywords: +- Adobe Journey Optimizer +- Guide +- Messaging +- Tutorial +- Content Card +- UI +- Android +--- + +# Customizing Content Card Templates style + +This tutorial explains how to customize the UI of content cards in your application. + +## Overview + +The Messaging extension provides a way to customize content cards by using [Compose modifiers](https://developer.android.com/develop/ui/compose/modifiers?hl=en) in conjunction with additional parameters provided when creating a [style](../public-classes/Styles/README.md) object. Refer to each individual style class to see the customizable settings available for each style. + +## Setting custom style parameters when creating a `SmallImageUIStyle` + +Perform the following steps to customize content card templates: + +1. Create a style object with a `Modifier` as well as any additional customizations passed in as part of the constructor parameters (e.g. if customizing an [AepButtonStyle](../public-classes/Styles/aepbuttonstyle.md) , then along with the `Modifier`, the enabled state, elevation, shape, border, color, and padding can be customized if desired.) +2. Use the created style object when invoking the builder of the template style object (e.g. `SmallImageUIStyle`) + +Below is an example implementation: + +```kotlin +// create a custom style for the small image card in row +val smallImageCardStyleRow = SmallImageUIStyle.Builder() + .cardStyle(AepCardStyle(modifier = Modifier.width(400.dp).height(200.dp))) + .rootRowStyle(AepRowStyle(modifier = Modifier.fillMaxSize())) + .imageStyle(AepImageStyle(modifier = Modifier.width(100.dp).height(100.dp))) + .buttonRowStyle(AepRowStyle(modifier = Modifier.fillMaxSize())) + .buttonStyle(arrayOf(Pair(AepButtonStyle(modifier = Modifier.padding(8.dp)), + AepTextStyle(textStyle = TextStyle(color = Color.Green, fontSize = 16.sp))))) + .dismissButtonStyle(AepIconStyle(modifier = Modifier.padding(8.dp))) + .dismissButtonAlignment(Alignment.TopEnd) + .textColumnStyle(AepColumnStyle(modifier = Modifier.fillMaxSize())) + .bodyAepTextStyle(AepTextStyle(textStyle = TextStyle(Color.Yellow))) + .titleAepTextStyle(AepTextStyle(textStyle = TextStyle(Color.Green))) + .build() + +// Create row with composables from AepUI instances +LazyRow { + items(reorderedAepUIList) { aepUI -> + when (aepUI) { + is SmallImageUI -> { + val state = aepUI.getState() + if (!state.dismissed) + { + SmallImageCard(ui = aepUI, + style = smallImageCardStyleRow, // setting the custom style here + observer = ContentCardEventObserver(contentCardCallback)) + } + } + } + } +} +``` diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/tutorial/displaying-content-cards.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/tutorial/displaying-content-cards.md new file mode 100644 index 0000000000..6a9d0c6cb3 --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/tutorial/displaying-content-cards.md @@ -0,0 +1,136 @@ +--- +title: Fetch and Display Content Cards +description: This document contains a tutorial on how to fetch and display content cards. +keywords: +- Adobe Journey Optimizer +- Guide +- Messaging +- Tutorial +- Content Card +- UI +- Android +--- + +# Fetch and Display Content Cards + +This tutorial explains how to fetch and display content cards in your application. + +## Pre-requisites + +[Integrate and register AEPMessaging extension](https://developer.adobe.com/client-sdks/edge/adobe-journey-optimizer/#implement-extension-in-mobile-app) in your app. + +## Fetch Content Cards + +To fetch the content cards for the surfaces configured in [Adobe Journey Optimizer](https://business.adobe.com/products/journey-optimizer/adobe-journey-optimizer.html) campaigns, call the [updatePropositionsForSurfaces](https://developer.adobe.com/client-sdks/edge/adobe-journey-optimizer/code-based/api-reference/#updatepropositionsforsurfaces) API. It's recommended to batch requests for multiple surfaces in a single API call when possible. The returned content cards are cached in-memory by the Messaging extension and persist through the application's lifecycle. + + + +#### Kotlin + +```kotlin +val surfaces = mutableListOf() +val surface = Surface("homepage") +Messaging.updatePropositionsForSurfaces(surfaces) +``` + +## Retrieve Content Cards + +To retrieve the content cards for a specific surface, call `getContentCardsUI`. This API returns a [flow](https://developer.android.com/kotlin/flow) of [AepUI](../public-classes/aepui.md) objects representing content cards for which the user is qualified. + +`AepUI` objects are created only for content cards with templates recognized by the Messaging extension. The flow of `AepUI` objects may contain multiple content card template types. + + + +#### Kotlin + +```kotlin +// create a view model or reuse existing one to hold the aepUIList +class AepContentCardViewModel(private val contentCardUIProvider: ContentCardUIProvider) : ViewModel() { + // State to hold AepUI list + private val _aepUIList = MutableStateFlow>>(emptyList()) + val aepUIList: StateFlow>> = _aepUIList.asStateFlow() + + init { + // Launch a coroutine to fetch the aepUIList from the ContentCardUIProvider + // when the ViewModel is created + viewModelScope.launch { + contentCardUIProvider.getContentCardUI().collect { aepUi -> + _aepUIList.value = aepUi + } + } + } + + // Function to refresh the aepUIList from the ContentCardUIProvider + fun refreshContent() { + viewModelScope.launch { + contentCardUIProvider.refreshContent() + } + } +} +``` + +> Note - only content cards for which the user has qualified are returned by the getContentCardUI API. Client-side rules are defined in the Adobe Journey Optimizer campaign. + +## Display Content Cards + +The Content Card user interface is implemented using Jetpack Compose, which is the recommended toolkit for Android development. To display content cards in your app, pass the `AepUI` objects returned by the `getContentCardUI` API to the appropriate Content Card composable. The currently supported composables are: +1. SmallImageCard composable for SmallImageUI + +### Display Content Cards in Compose UI application + +Below is an example of how to display content cards in a Compose UI application: + + + +#### Kotlin + +```kotlin +@Composable +private fun AepContentCardList(viewModel: AepContentCardViewModel) { + // Collect the state from ViewModel + val aepUiList by viewModel.aepUIList.collectAsStateWithLifecycle() + + // Create row with composables from AepUI instances + LazyRow { + items(reorderedAepUIList) { aepUI -> + when (aepUI) { + is SmallImageUI -> { + val state = aepUI.getState() + if (!state.dismissed) + { + SmallImageCard(ui = aepUI, + style = smallImageCardStyleRow, + observer = ContentCardEventObserver(contentCardCallback)) + } + } + } + } + } +} +``` + +Refer to this [TestApp](../../../../code/testapp/) for a complete example of how to display, customize and listen to UI events from content cards in a Compose UI application. + +#### Retrieve ContentCardSchemaData from the Messaging extension + +You may retrieve the `ContentCardSchemaData` for a Content Card using the template id using the [ContentCardMapper](../public-classes/contentcardmapper.md): + + + +#### Kotlin + +```kotlin +private fun AepContentCardList(viewModel: AepContentCardViewModel) { + // Collect the state from ViewModel + val aepUiList by viewModel.aepUIList.collectAsStateWithLifecycle() + + // Get the ContentCardSchemaData for the AepUI list if needed + val contentCardSchemaDataList = aepUiList.map { + when (it) { + is SmallImageUI -> + ContentCardMapper.Companion.instance.getContentCardSchemaData(it.getTemplate().id) + + else -> null + } + } +``` diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/tutorial/listening-content-card-events.md b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/tutorial/listening-content-card-events.md new file mode 100644 index 0000000000..cad88f646b --- /dev/null +++ b/src/pages/edge/adobe-journey-optimizer/content-card-ui/Android/tutorial/listening-content-card-events.md @@ -0,0 +1,117 @@ +--- +title: Listening to Content Card Events +description: This document contains a tutorial on how to listen to content cards. +keywords: +- Adobe Journey Optimizer +- Guide +- Messaging +- Tutorial +- Content Card +- UI +- Android +--- + +# Listening to Content Card Events + +This tutorial explains how to listen to content card events in your application. + +## Overview + +The Messaging extension provides a way to listen to events from content cards displayed in your application. The following functions can be implemented in conformance with the `ContentCardUIEventListener` interface: + +- `onDisplay` +- `onDismiss` +- `onInteract` + +## Implement ContentCardUIEventListener + +Complete the following steps to hear content card events: + +1. Implement the [ContentCardUIEventListener](../public-classes/contentcarduieventlistener.md) interface in your class. + + + +#### Kotlin + +```kotlin +class ContentCardCallback: ContentCardUIEventListener { + override fun onDisplay(aepUI: AepUI<*, *>) { + Log.d("ContentCardCallback", "onDisplay") + } + + override fun onDismiss(aepUI: AepUI<*, *>) { + Log.d("ContentCardCallback", "onDismiss") + } + + override fun onInteract( + aepUI: AepUI<*, *>, + interactionId: String?, + actionUrl: String? + ): Boolean { + Log.d("ContentCardCallback", "onInteract $interactionId $actionUrl") + // If the url is handled here, return true + return false + } +} +``` + +2. Pass the listener to the [ContentCardEventObservers](../public-classes/Observers/contentcardeventobserver.md) class when retrieving the card composable. + + + +#### Kotlin + +```kotlin +@Composable +private fun AepContentCardList(viewModel: AepContentCardViewModel) { + // Create the ContentCardUIEventListener + val contentCardCallback = ContentCardCallback() + // Collect the state from ViewModel + val aepUiList by viewModel.aepUIList.collectAsStateWithLifecycle() + + // Create row with composables from AepUI instances + LazyRow { + items(aepUiList) { aepUI -> + when (aepUI) { + is SmallImageUI -> { + val state = aepUI.getState() + if (!state.dismissed) { + SmallImageCard( + ui = aepUI, + style = smallImageCardStyleRow, + // provide the ContentCardUIEventListener as a parameter to the // ContentCardEventObserver + observer = ContentCardEventObserver(contentCardCallback) + ) + } + } + } + } + } +} +``` + +### Handling actionable URLs + +The `onInteract` method provides an optional `actionURL` parameter associated with the interaction event. The return value of this method determines how the URL is handled. + +- Return `true` if your application has successfully handled the URL. This indicates to the SDK that no further action is needed. + +- Return `false` to allow the SDK to process the URL. + + + +#### Kotlin + +```kotlin +override fun onInteract( + aepUI: AepUI<*, *>, + interactionId: String?, + actionUrl: String? +): Boolean { + actionUrl?.let { + // handle action url here + return true + } + return false +} +``` diff --git a/src/pages/edge/adobe-journey-optimizer/content-card-ui/assets/Android/SmallImageCard composable layout.png b/src/pages/edge/adobe-journey-optimizer/content-card-ui/assets/Android/SmallImageCard composable layout.png new file mode 100644 index 0000000000000000000000000000000000000000..ff3b52f0eb551f99b35fcffbd09240ff34e4d37e GIT binary patch literal 59768 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 literal 0 HcmV?d00001