diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index eef332251..66698eb83 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -96,4 +96,4 @@ jobs: repo, comment_id: context.payload.comment.id, content: "confused", - }); \ No newline at end of file + }); diff --git a/android/demo/src/androidTest/java/com/intuit/playerui/android/reference/demo/test/fragment/PlayerFragmentScrollingTest.kt b/android/demo/src/androidTest/java/com/intuit/playerui/android/reference/demo/test/fragment/PlayerFragmentScrollingTest.kt index 7c80728d6..a4d950635 100644 --- a/android/demo/src/androidTest/java/com/intuit/playerui/android/reference/demo/test/fragment/PlayerFragmentScrollingTest.kt +++ b/android/demo/src/androidTest/java/com/intuit/playerui/android/reference/demo/test/fragment/PlayerFragmentScrollingTest.kt @@ -7,8 +7,6 @@ import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.withText import com.intuit.playerui.android.reference.demo.test.base.ComposeUITest -import androidx.compose.ui.test.onNodeWithText -import androidx.compose.ui.test.performClick import com.intuit.playerui.android.reference.demo.test.base.waitForViewInRoot import org.junit.Test diff --git a/android/player/src/main/java/com/intuit/playerui/android/AndroidPlayer.kt b/android/player/src/main/java/com/intuit/playerui/android/AndroidPlayer.kt index dfae5a8b0..6446915db 100644 --- a/android/player/src/main/java/com/intuit/playerui/android/AndroidPlayer.kt +++ b/android/player/src/main/java/com/intuit/playerui/android/AndroidPlayer.kt @@ -2,6 +2,7 @@ package com.intuit.playerui.android import android.content.Context import android.view.View +import androidx.compose.runtime.ProvidedValue import com.intuit.hooks.BailResult import com.intuit.hooks.HookContext import com.intuit.hooks.SyncBailHook @@ -122,8 +123,13 @@ public class AndroidPlayer private constructor( ) } + public class CompositionLocalProvidedValuesHook : SyncHook<(HookContext, (List>) -> Unit) -> Unit>() { + public fun call(hookContext: HookContext, updateProvidedValues: (List>) -> Unit) = super.call { f, context -> f(context, updateProvidedValues) } + } + public val context: ContextHook = ContextHook() public val update: UpdateHook = UpdateHook() + public val compositionLocalProvidedValues: CompositionLocalProvidedValuesHook = CompositionLocalProvidedValuesHook() internal val recycle: RecycleHook = RecycleHook() internal val release: ReleaseHook = ReleaseHook() } @@ -206,6 +212,9 @@ public class AndroidPlayer private constructor( context.overlayStyles(styles) } + /** List of provided values to pass into the CompositionLocalProvider that wraps all compose assets */ + internal var providedValues: MutableList> = mutableListOf() + /** * Cache [AssetContext]-[View] pairs against the [AssetContext.id]. The [AssetContext] is * cached to enable checking if the [View] has been hydrated with the latest [Asset]. diff --git a/android/player/src/main/java/com/intuit/playerui/android/compose/ComposableAsset.kt b/android/player/src/main/java/com/intuit/playerui/android/compose/ComposableAsset.kt index 65f669fad..cd6aa0f53 100644 --- a/android/player/src/main/java/com/intuit/playerui/android/compose/ComposableAsset.kt +++ b/android/player/src/main/java/com/intuit/playerui/android/compose/ComposableAsset.kt @@ -5,6 +5,7 @@ import android.widget.FrameLayout import androidx.compose.material.LocalTextStyle import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.ProvidedValue import androidx.compose.runtime.getValue import androidx.compose.runtime.produceState import androidx.compose.ui.Modifier @@ -47,13 +48,24 @@ public abstract class ComposableAsset ( } } + fun updateProvidedValues(values: List>) { + // Update the internal state or perform actions with the new values + player.providedValues.addAll(values) + } + @Composable fun compose(modifier: Modifier? = Modifier, data: Data? = null) { val data: Data? by produceState(initialValue = data, key1 = this) { value = getData() } - data?.let { content(modifier ?: Modifier, it) } + data?.let { + // Getting the local values provided by the plugin hook + player.hooks.compositionLocalProvidedValues.call(hashMapOf(), ::updateProvidedValues) + CompositionLocalProvider(*(player.providedValues).toTypedArray()) { + content(modifier ?: Modifier, it) + } + } } @Composable diff --git a/docs/site/src/content/docs/assets/custom.mdx b/docs/site/src/content/docs/assets/custom.mdx index abb8be0f2..0f5d0a931 100644 --- a/docs/site/src/content/docs/assets/custom.mdx +++ b/docs/site/src/content/docs/assets/custom.mdx @@ -391,8 +391,16 @@ interface AssetStyle { ``` This interface optionally accepts compose TextStyle and xmlStyles. In order to reduce defining both these styles separately, we recommend implementing a custom converter that converts one style to another. -As an example, our reference assets implement an XmlStyleParser that parses an XML style and returns its equivalent Compose TextStyle. +As an example, our reference assets implement an XmlStyleParser that parses an XML style and returns its equivalent Compose TextStyle. An instance of this style can be passed in the `compose` call to render child assets. +#### Theming +In order to support theming and allow consumers to set values in a CompositionLocalProvider, AndroidPlayer now exposes a hook called `compositionLocalProvidedValues`. As an example, you can use it to set LocalColorScheme as follows: + +``` +androidPlayer.hooks.compositionLocalProvidedValues.tap("CG Theme") { _, updateProvidedValues -> + updateProvidedValues(listOf(LocalColorScheme provides customColorScheme)) +} +```