mirror of
https://github.com/divkit/divkit.git
synced 2026-05-07 20:02:32 +00:00
Added unhandled actions handling
commit_hash:f7b6e386eb6f815b56a0fadd8644c44c84e21cf5
This commit is contained in:
+2
-1
@@ -614,7 +614,8 @@
|
||||
"client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/DivActionData.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/DivActionData.kt",
|
||||
"client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/DivActionHandler.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/DivActionHandler.kt",
|
||||
"client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/DivActionHandlingContext.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/DivActionHandlingContext.kt",
|
||||
"client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/DivCustomActionHandler.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/DivCustomActionHandler.kt",
|
||||
"client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/DivCustomActionData.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/DivCustomActionData.kt",
|
||||
"client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/DivExternalActionHandler.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/DivExternalActionHandler.kt",
|
||||
"client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/SetVariableActionHandler.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/SetVariableActionHandler.kt",
|
||||
"client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/UpdateStructureActionHandler.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/UpdateStructureActionHandler.kt",
|
||||
"client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivLocalContext.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivLocalContext.kt",
|
||||
|
||||
+3
-10
@@ -5,9 +5,7 @@ import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import coil3.ImageLoader
|
||||
import coil3.request.allowHardware
|
||||
import com.yandex.div.compose.actions.DivActionData
|
||||
import com.yandex.div.compose.actions.DivActionHandlingContext
|
||||
import com.yandex.div.compose.actions.DivCustomActionHandler
|
||||
import com.yandex.div.compose.actions.DivExternalActionHandler
|
||||
import com.yandex.div.compose.dagger.Names
|
||||
import com.yandex.div.compose.dagger.`Yatagan$DivContextComponent`
|
||||
import com.yandex.div.compose.internal.ImageLoaderProvider
|
||||
@@ -35,7 +33,7 @@ import javax.inject.Named
|
||||
@PublicApi
|
||||
class DivComposeConfiguration(
|
||||
@get:Provides
|
||||
val customActionHandler: DivCustomActionHandler = defaultCustomActionHandler,
|
||||
val actionHandler: DivExternalActionHandler = defaultActionHandler,
|
||||
|
||||
@get:Provides
|
||||
val fontFamilyProvider: DivFontFamilyProvider = defaultFontFamilyProvider,
|
||||
@@ -66,12 +64,7 @@ private val defaultImageLoaderProvider = ImageLoaderProvider { context ->
|
||||
.build()
|
||||
}
|
||||
|
||||
private val defaultCustomActionHandler = object : DivCustomActionHandler {
|
||||
override fun handle(
|
||||
context: DivActionHandlingContext,
|
||||
action: DivActionData
|
||||
) = Unit
|
||||
}
|
||||
private val defaultActionHandler = object : DivExternalActionHandler {}
|
||||
|
||||
private val defaultFontFamilyProvider = object : DivFontFamilyProvider {
|
||||
override fun getFontFamily(fontFamilyName: String?, weight: FontWeight): FontFamily {
|
||||
|
||||
+3
-2
@@ -5,10 +5,11 @@ import com.yandex.div.core.annotations.PublicApi
|
||||
import org.json.JSONObject
|
||||
|
||||
/**
|
||||
* Data associated with a custom DivKit action.
|
||||
* Data associated with a DivKit action.
|
||||
*/
|
||||
@PublicApi
|
||||
class DivActionData(
|
||||
data class DivActionData(
|
||||
val id: String,
|
||||
val payload: JSONObject?,
|
||||
val url: Uri?
|
||||
)
|
||||
|
||||
+25
-8
@@ -3,13 +3,14 @@ package com.yandex.div.compose.actions
|
||||
import com.yandex.div.compose.DivReporter
|
||||
import com.yandex.div.compose.dagger.DivContextScope
|
||||
import com.yandex.div.internal.actions.DivUntypedAction
|
||||
import com.yandex.div.internal.actions.isDivAction
|
||||
import com.yandex.div2.DivAction
|
||||
import com.yandex.div2.DivActionTyped
|
||||
import javax.inject.Inject
|
||||
|
||||
@DivContextScope
|
||||
internal class DivActionHandler @Inject constructor(
|
||||
private val customActionHandler: DivCustomActionHandler,
|
||||
private val externalActionHandler: DivExternalActionHandler,
|
||||
private val reporter: DivReporter,
|
||||
private val arrayActionsHandler: ArrayActionsHandler,
|
||||
private val dictSetValueActionHandler: DictSetValueActionHandler,
|
||||
@@ -18,14 +19,30 @@ internal class DivActionHandler @Inject constructor(
|
||||
) {
|
||||
|
||||
fun handle(context: DivActionHandlingContext, action: DivAction) {
|
||||
val expressionResolver = context.expressionResolver
|
||||
if (!action.isEnabled.evaluate(expressionResolver)) {
|
||||
return
|
||||
}
|
||||
|
||||
action.typed?.let {
|
||||
handle(context = context, action = it, baseAction = action)
|
||||
return
|
||||
}
|
||||
|
||||
val uri = action.url?.evaluate(context.expressionResolver) ?: return
|
||||
DivUntypedAction.parse(uri)?.let {
|
||||
handle(context = context, action = it)
|
||||
val url = action.url?.evaluate(expressionResolver) ?: return
|
||||
if (url.isDivAction) {
|
||||
DivUntypedAction.parse(url)?.let {
|
||||
handle(context = context, action = it)
|
||||
}
|
||||
} else {
|
||||
externalActionHandler.handle(
|
||||
context = context,
|
||||
action = DivActionData(
|
||||
id = action.logId.evaluate(expressionResolver),
|
||||
payload = action.payload,
|
||||
url = action.url?.evaluate(expressionResolver)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,11 +66,11 @@ internal class DivActionHandler @Inject constructor(
|
||||
is DivActionTyped.ClearFocus -> notSupported()
|
||||
is DivActionTyped.CopyToClipboard -> notSupported()
|
||||
is DivActionTyped.Custom ->
|
||||
customActionHandler.handle(
|
||||
externalActionHandler.handleCustomAction(
|
||||
context = context,
|
||||
action = DivActionData(
|
||||
payload = baseAction.payload,
|
||||
url = baseAction.url?.evaluate(context.expressionResolver)
|
||||
action = DivCustomActionData(
|
||||
id = baseAction.logId.evaluate(context.expressionResolver),
|
||||
payload = baseAction.payload
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
package com.yandex.div.compose.actions
|
||||
|
||||
import com.yandex.div.core.annotations.PublicApi
|
||||
import org.json.JSONObject
|
||||
|
||||
/**
|
||||
* Data associated with a custom DivKit action (action with `"type": "custom"`).
|
||||
*/
|
||||
@PublicApi
|
||||
data class DivCustomActionData(
|
||||
val id: String,
|
||||
val payload: JSONObject?
|
||||
)
|
||||
-19
@@ -1,19 +0,0 @@
|
||||
package com.yandex.div.compose.actions
|
||||
|
||||
import com.yandex.div.core.annotations.PublicApi
|
||||
|
||||
/**
|
||||
* Handler for custom DivKit actions (actions with `"type": "custom"`).
|
||||
*
|
||||
* Implement this interface to handle application-specific actions.
|
||||
*
|
||||
* @see com.yandex.div.compose.DivComposeConfiguration
|
||||
*/
|
||||
@PublicApi
|
||||
interface DivCustomActionHandler {
|
||||
|
||||
/**
|
||||
* Called when a custom action is triggered.
|
||||
*/
|
||||
fun handle(context: DivActionHandlingContext, action: DivActionData)
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package com.yandex.div.compose.actions
|
||||
|
||||
import com.yandex.div.core.annotations.PublicApi
|
||||
|
||||
/**
|
||||
* Handler for actions that DivKit does not handle internally.
|
||||
*
|
||||
* Implement this interface to handle application-specific actions.
|
||||
*
|
||||
* @see com.yandex.div.compose.DivComposeConfiguration
|
||||
*/
|
||||
@PublicApi
|
||||
interface DivExternalActionHandler {
|
||||
|
||||
/**
|
||||
* Called when an action that does not handled by DivKit is triggered.
|
||||
*
|
||||
* DivKit handles actions with `typed` parameter and actions with `url` that starts with
|
||||
* `div-action:` only.
|
||||
*/
|
||||
fun handle(context: DivActionHandlingContext, action: DivActionData) = Unit
|
||||
|
||||
/**
|
||||
* Called when a custom action (action with `"type": "custom"`) is triggered.
|
||||
*/
|
||||
fun handleCustomAction(context: DivActionHandlingContext, action: DivCustomActionData) = Unit
|
||||
}
|
||||
+2
-2
@@ -19,14 +19,14 @@ internal class ActionHandlerEnvironment {
|
||||
)
|
||||
|
||||
fun createActionHandler(
|
||||
customActionHandler: DivCustomActionHandler = mock(),
|
||||
externalActionHandler: DivExternalActionHandler = mock(),
|
||||
arrayActionsHandler: ArrayActionsHandler = mock(),
|
||||
dictSetValueActionHandler: DictSetValueActionHandler = mock(),
|
||||
setVariableActionHandler: SetVariableActionHandler = mock(),
|
||||
updateStructureActionHandler: UpdateStructureActionHandler = mock()
|
||||
): DivActionHandler {
|
||||
return DivActionHandler(
|
||||
customActionHandler = customActionHandler,
|
||||
externalActionHandler = externalActionHandler,
|
||||
reporter = reporter,
|
||||
arrayActionsHandler = arrayActionsHandler,
|
||||
dictSetValueActionHandler = dictSetValueActionHandler,
|
||||
|
||||
+57
-15
@@ -1,38 +1,73 @@
|
||||
package com.yandex.div.compose.actions
|
||||
|
||||
import androidx.core.net.toUri
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.yandex.div.test.data.action
|
||||
import com.yandex.div.test.data.customAction
|
||||
import com.yandex.div2.DivAction
|
||||
import com.yandex.div2.DivActionCustom
|
||||
import com.yandex.div2.DivActionTyped
|
||||
import org.json.JSONObject
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class DivActionHandlerTest {
|
||||
private val actionHandlerEnvironment = ActionHandlerEnvironment()
|
||||
private val customActionHandler = CustomActionHandler()
|
||||
private val externalActionHandler = TestExternalActionHandler()
|
||||
|
||||
private val actionHandler = actionHandlerEnvironment.createActionHandler(
|
||||
customActionHandler = customActionHandler
|
||||
externalActionHandler = externalActionHandler
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `handle custom action`() {
|
||||
val payload = JSONObject().apply {
|
||||
put("key", "value")
|
||||
}
|
||||
fun `not enabled action is not handled`() {
|
||||
handle(action(isEnabled = false, typed = customAction()))
|
||||
|
||||
assertNull(externalActionHandler.lastCustomAction)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `unhandled action is passed to the external action handler`() {
|
||||
val payload = JSONObject(mapOf("key" to "value"))
|
||||
|
||||
handle(
|
||||
action(
|
||||
id = "test",
|
||||
payload = payload,
|
||||
typed = DivActionTyped.Custom(DivActionCustom())
|
||||
url = "custom://url"
|
||||
)
|
||||
)
|
||||
|
||||
assertEquals(payload, customActionHandler.lastAction?.payload)
|
||||
assertEquals(
|
||||
DivActionData(
|
||||
id = "test",
|
||||
payload = payload,
|
||||
url = "custom://url".toUri()
|
||||
),
|
||||
externalActionHandler.lastAction
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `custom action is passed to the external action handler`() {
|
||||
val payload = JSONObject(mapOf("key" to "value"))
|
||||
|
||||
handle(
|
||||
action(
|
||||
id = "test",
|
||||
payload = payload,
|
||||
typed = customAction()
|
||||
)
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
DivCustomActionData(
|
||||
id = "test",
|
||||
payload = payload
|
||||
),
|
||||
externalActionHandler.lastCustomAction
|
||||
)
|
||||
}
|
||||
|
||||
private fun handle(action: DivAction) {
|
||||
@@ -40,14 +75,21 @@ class DivActionHandlerTest {
|
||||
}
|
||||
}
|
||||
|
||||
private class CustomActionHandler : DivCustomActionHandler {
|
||||
private class TestExternalActionHandler : DivExternalActionHandler {
|
||||
var lastAction: DivActionData? = null
|
||||
private set
|
||||
|
||||
override fun handle(
|
||||
context: DivActionHandlingContext,
|
||||
action: DivActionData
|
||||
) {
|
||||
var lastCustomAction: DivCustomActionData? = null
|
||||
private set
|
||||
|
||||
override fun handle(context: DivActionHandlingContext, action: DivActionData) {
|
||||
lastAction = action
|
||||
}
|
||||
|
||||
override fun handleCustomAction(
|
||||
context: DivActionHandlingContext,
|
||||
action: DivCustomActionData
|
||||
) {
|
||||
lastCustomAction = action
|
||||
}
|
||||
}
|
||||
|
||||
+5
-1
@@ -47,7 +47,7 @@ sealed class DivUntypedAction {
|
||||
|
||||
@JvmStatic
|
||||
fun parse(uri: Uri): DivUntypedAction? {
|
||||
if (uri.scheme != "div-action") {
|
||||
if (!uri.isDivAction) {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -111,3 +111,7 @@ sealed class DivUntypedAction {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@InternalApi
|
||||
val Uri.isDivAction: Boolean
|
||||
get() = scheme == "div-action"
|
||||
|
||||
+8
-2
@@ -5,6 +5,7 @@ import com.yandex.div2.DivAction
|
||||
import com.yandex.div2.DivActionArrayInsertValue
|
||||
import com.yandex.div2.DivActionArrayRemoveValue
|
||||
import com.yandex.div2.DivActionArraySetValue
|
||||
import com.yandex.div2.DivActionCustom
|
||||
import com.yandex.div2.DivActionDictSetValue
|
||||
import com.yandex.div2.DivActionSetVariable
|
||||
import com.yandex.div2.DivActionTyped
|
||||
@@ -13,12 +14,15 @@ import com.yandex.div2.DivTypedValue
|
||||
import org.json.JSONObject
|
||||
|
||||
fun action(
|
||||
typed: DivActionTyped? = null,
|
||||
id: String = "test",
|
||||
isEnabled: Boolean = true,
|
||||
payload: JSONObject? = null,
|
||||
typed: DivActionTyped? = null,
|
||||
url: String? = null,
|
||||
): DivAction {
|
||||
return DivAction(
|
||||
logId = constant("test"),
|
||||
isEnabled = constant(isEnabled),
|
||||
logId = constant(id),
|
||||
payload = payload,
|
||||
typed = typed,
|
||||
url = url?.let { constant(it.toUri()) }
|
||||
@@ -65,6 +69,8 @@ fun arraySetValueAction(
|
||||
)
|
||||
}
|
||||
|
||||
fun customAction(): DivActionTyped = DivActionTyped.Custom(DivActionCustom())
|
||||
|
||||
fun dictSetValueAction(
|
||||
name: String,
|
||||
key: String,
|
||||
|
||||
Reference in New Issue
Block a user