Skip to content

Commit

Permalink
Merge pull request #489 from player-ui/android-expose-constantsContro…
Browse files Browse the repository at this point in the history
…ller

Android/JVM - expose constantController
  • Loading branch information
cehan-Chloe authored Aug 14, 2024
2 parents 1cc6018 + 16dbb91 commit 583b4c0
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import com.intuit.playerui.core.bridge.Completable
import com.intuit.playerui.core.bridge.format
import com.intuit.playerui.core.bridge.runtime.PlayerRuntimeConfig
import com.intuit.playerui.core.bridge.serialization.format.registerContextualSerializer
import com.intuit.playerui.core.constants.ConstantsController
import com.intuit.playerui.core.logger.TapableLogger
import com.intuit.playerui.core.player.HeadlessPlayer
import com.intuit.playerui.core.player.Player
Expand Down Expand Up @@ -89,6 +90,8 @@ public class AndroidPlayer private constructor(

override val logger: TapableLogger by player::logger

override val constantsController: ConstantsController by player::constantsController

public class Hooks internal constructor(hooks: Player.Hooks) : Player.Hooks by hooks {
public class ContextHook : SyncWaterfallHook<(HookContext, Context) -> Context, Context>() {
public fun call(context: Context): Context = super.call(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.intuit.playerui.core.constants
import com.intuit.playerui.core.bridge.Node
import com.intuit.playerui.core.bridge.NodeWrapper
import com.intuit.playerui.core.bridge.getInvokable
import com.intuit.playerui.core.bridge.serialization.serializers.NodeWrapperSerializer
import kotlinx.serialization.Serializable

@Serializable(with = ConstantsController.Serializer::class)
public class ConstantsController(override val node: Node) : NodeWrapper {
/**
* Function to add constants to the providers store
* @param data values to add to the constants store
* @param namespace namespace to add the constants under
*/
public fun addConstants(data: Map<String, Any>, namespace: String) {
node.getInvokable<Unit>("addConstants")?.invoke(data, namespace)
}

/**
* Function to retrieve constants from the providers store
* @param key Key used for the store access
* @param namespace namespace values were loaded under (defined in the plugin)
* @param fallback Optional - if key doesn't exist in namespace what to return (will return unknown if not provided)
*/
public fun getConstants(key: String, namespace: String, fallback: Any? = null): Any? {
return node.getInvokable<Any?>("getConstants")?.invoke(key, namespace, fallback)
}

/**
* Function to set values to temporarily override certain keys in the permanent store
* @param data values to override store with
* @param namespace namespace to override
*/
public fun setTemporaryValues(data: Any, namespace: String) {
node.getInvokable<Unit>("setTemporaryValues")?.invoke(data, namespace)
}

/**
* Clears any temporary values that were previously set
*/
public fun clearTemporaryValues() {
node.getInvokable<Unit>("clearTemporaryValues")?.invoke()
}

internal object Serializer : NodeWrapperSerializer<ConstantsController>(::ConstantsController)
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.intuit.playerui.core.bridge.runtime.ScriptContext
import com.intuit.playerui.core.bridge.runtime.add
import com.intuit.playerui.core.bridge.runtime.runtimeFactory
import com.intuit.playerui.core.bridge.serialization.serializers.NodeSerializableField
import com.intuit.playerui.core.constants.ConstantsController
import com.intuit.playerui.core.experimental.ExperimentalPlayerApi
import com.intuit.playerui.core.logger.TapableLogger
import com.intuit.playerui.core.player.HeadlessPlayer.Companion.bundledSource
Expand Down Expand Up @@ -77,6 +78,8 @@ public constructor(

override val hooks: Hooks by NodeSerializableField(Hooks.serializer(), NodeSerializableField.CacheStrategy.Full)

override val constantsController: ConstantsController by NodeSerializableField(ConstantsController.serializer(), NodeSerializableField.CacheStrategy.Full)

override val state: PlayerFlowState get() = if (player.isReleased()) {
ReleasedState
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.intuit.playerui.core.bridge.NodeWrapper
import com.intuit.playerui.core.bridge.hooks.NodeSyncHook1
import com.intuit.playerui.core.bridge.serialization.serializers.NodeSerializableField
import com.intuit.playerui.core.bridge.serialization.serializers.NodeWrapperSerializer
import com.intuit.playerui.core.constants.ConstantsController
import com.intuit.playerui.core.data.DataController
import com.intuit.playerui.core.experimental.ExperimentalPlayerApi
import com.intuit.playerui.core.expressions.ExpressionController
Expand Down Expand Up @@ -33,6 +34,8 @@ public abstract class Player : Pluggable {

public abstract val logger: TapableLogger

public abstract val constantsController: ConstantsController

/**
* Expose [PlayerHooks] which allow consumers to plug
* into the flow and subscribe to different events.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -455,4 +455,92 @@ internal class HeadlessPlayerTest : PlayerTest(), ThreadUtils {

assertTrue(player.state is ErrorState)
}

@TestTemplate
fun `test constantsController get and set`() = runBlockingTest {
val constantsController = player.constantsController

val data = mapOf(
"firstname" to "john",
"lastname" to "doe",
"favorite" to mapOf("color" to "red"),
"age" to 1,
)

constantsController.addConstants(data = data, namespace = "constants")

val firstname = constantsController.getConstants(key = "firstname", namespace = "constants")
assertEquals("john", firstname)

val middleName = constantsController.getConstants(key = "middlename", namespace = "constants")
assertNull(middleName)

val middleNameSafe = constantsController.getConstants(key = "middlename", namespace = "constants", fallback = "A")
assertEquals("A", middleNameSafe)

val favoriteColor = constantsController.getConstants(key = "favorite.color", namespace = "constants")
assertEquals("red", favoriteColor)

val age = constantsController.getConstants(key = "age", namespace = "constants")
assertEquals(1, age)

val nonExistentNamespace = constantsController.getConstants(key = "test", namespace = "foo")
assertNull(nonExistentNamespace)

val nonExistentNamespaceWithFallback = constantsController.getConstants(key = "test", namespace = "foo", fallback = "B")
assertEquals("B", nonExistentNamespaceWithFallback)

// Test and make sure keys override properly
val newData = mapOf(
"favorite" to mapOf("color" to "blue"),
)

constantsController.addConstants(data = newData, namespace = "constants")

val newFavoriteColor = constantsController.getConstants(key = "favorite.color", namespace = "constants")
assertEquals("blue", newFavoriteColor)
}

@TestTemplate
fun `test constantsController temp override functionality`() = runBlockingTest {
val constantsController = player.constantsController

// Add initial constants
val data = mapOf(
"firstname" to "john",
"lastname" to "doe",
"favorite" to mapOf("color" to "red"),
)
constantsController.addConstants(data = data, namespace = "constants")

// Override with temporary values
val tempData = mapOf(
"firstname" to "jane",
"favorite" to mapOf("color" to "blue"),
)
constantsController.setTemporaryValues(data = tempData, namespace = "constants")

// Test temporary override
val firstnameTemp = constantsController.getConstants(key = "firstname", namespace = "constants")
assertEquals("jane", firstnameTemp)

val favoriteColorTemp = constantsController.getConstants(key = "favorite.color", namespace = "constants")
assertEquals("blue", favoriteColorTemp)

// Test fallback to original values when temporary values are not present
val lastnameTemp = constantsController.getConstants(key = "lastname", namespace = "constants")
assertEquals("doe", lastnameTemp)

// Reset temp and values should be the same as the original data
constantsController.clearTemporaryValues()

val firstname = constantsController.getConstants(key = "firstname", namespace = "constants")
assertEquals("john", firstname)

val favoriteColor = constantsController.getConstants(key = "favorite.color", namespace = "constants")
assertEquals("red", favoriteColor)

val lastname = constantsController.getConstants(key = "lastname", namespace = "constants")
assertEquals("doe", lastname)
}
}

0 comments on commit 583b4c0

Please sign in to comment.