From db930d8f016a948013dfbd7a3bd06bf0f4ce57f5 Mon Sep 17 00:00:00 2001 From: pkurchatov Date: Tue, 14 Apr 2026 17:35:47 +0300 Subject: [PATCH] Added DivViewComponent commit_hash:145be58fb45e34d115aeae19a4e8ba9f4ce4b96a --- .mapping.json | 6 +- .../com/yandex/div/compose/DivContext.kt | 77 +------- .../kotlin/com/yandex/div/compose/DivView.kt | 7 +- .../actions/DivActionHandlingContext.kt | 4 +- .../actions/VisibilityActionTracker.kt | 4 +- .../context/DivLocalComponentStorage.kt | 19 ++ .../div/compose/context/DivLocalContext.kt | 47 ----- .../compose/context/DivLocalContextStorage.kt | 15 -- .../div/compose/context/DivViewContext.kt | 84 ++++++++- .../div/compose/dagger/DivContextComponent.kt | 20 +- .../div/compose/dagger/DivLocalComponent.kt | 49 ++++- .../div/compose/dagger/DivViewComponent.kt | 25 +++ .../yandex/div/compose/dagger/DivViewScope.kt | 7 + .../div/compose/internal/DivDebugFeatures.kt | 4 +- .../com/yandex/div/compose/utils/Context.kt | 12 +- .../compose/variables/DivVariableAdapter.kt | 4 +- .../yandex/div/compose/views/DivBlockView.kt | 6 +- .../views/modifiers/ActionModifiers.kt | 4 +- .../modifiers/VisibilityActionModifiers.kt | 14 +- .../compose/views/state/ObserveActiveState.kt | 4 +- ...ithVisibilityActionsRecomompositionTest.kt | 174 ++++++++++++++++++ .../utils/DivVariableControllerTest.kt | 22 +-- .../div/compose/utils/ExpressionUtilsTest.kt | 20 +- .../views/state/ObserveActiveStateTest.kt | 22 +-- 24 files changed, 421 insertions(+), 229 deletions(-) create mode 100644 client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivLocalComponentStorage.kt delete mode 100644 client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivLocalContext.kt delete mode 100644 client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivLocalContextStorage.kt create mode 100644 client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivViewComponent.kt create mode 100644 client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivViewScope.kt create mode 100644 client/android/compose/src/test/kotlin/com/yandex/div/compose/DivViewWithVisibilityActionsRecomompositionTest.kt diff --git a/.mapping.json b/.mapping.json index e84e80c54..089381180 100644 --- a/.mapping.json +++ b/.mapping.json @@ -620,8 +620,7 @@ "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/actions/VisibilityActionTracker.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/VisibilityActionTracker.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", - "client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivLocalContextStorage.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivLocalContextStorage.kt", + "client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivLocalComponentStorage.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivLocalComponentStorage.kt", "client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivViewContext.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivViewContext.kt", "client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivViewContextStorage.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivViewContextStorage.kt", "client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivContextComponent.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivContextComponent.kt", @@ -630,6 +629,8 @@ "client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivLocalComponent.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivLocalComponent.kt", "client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivLocalModule.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivLocalModule.kt", "client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivLocalScope.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivLocalScope.kt", + "client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivViewComponent.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivViewComponent.kt", + "client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivViewScope.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivViewScope.kt", "client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/Names.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/Names.kt", "client/android/compose/src/main/kotlin/com/yandex/div/compose/expressions/DivComposeExpressionResolver.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/expressions/DivComposeExpressionResolver.kt", "client/android/compose/src/main/kotlin/com/yandex/div/compose/expressions/EvaluatorWarningSender.kt":"divkit/public/client/android/compose/src/main/kotlin/com/yandex/div/compose/expressions/EvaluatorWarningSender.kt", @@ -692,6 +693,7 @@ "client/android/compose/src/test/kotlin/com/yandex/div/compose/DivViewTest.kt":"divkit/public/client/android/compose/src/test/kotlin/com/yandex/div/compose/DivViewTest.kt", "client/android/compose/src/test/kotlin/com/yandex/div/compose/DivViewWithFunctionsTest.kt":"divkit/public/client/android/compose/src/test/kotlin/com/yandex/div/compose/DivViewWithFunctionsTest.kt", "client/android/compose/src/test/kotlin/com/yandex/div/compose/DivViewWithTriggersTest.kt":"divkit/public/client/android/compose/src/test/kotlin/com/yandex/div/compose/DivViewWithTriggersTest.kt", + "client/android/compose/src/test/kotlin/com/yandex/div/compose/DivViewWithVisibilityActionsRecomompositionTest.kt":"divkit/public/client/android/compose/src/test/kotlin/com/yandex/div/compose/DivViewWithVisibilityActionsRecomompositionTest.kt", "client/android/compose/src/test/kotlin/com/yandex/div/compose/DivViewWithVisibilityActionsTest.kt":"divkit/public/client/android/compose/src/test/kotlin/com/yandex/div/compose/DivViewWithVisibilityActionsTest.kt", "client/android/compose/src/test/kotlin/com/yandex/div/compose/IntegrationTest.kt":"divkit/public/client/android/compose/src/test/kotlin/com/yandex/div/compose/IntegrationTest.kt", "client/android/compose/src/test/kotlin/com/yandex/div/compose/TestReporter.kt":"divkit/public/client/android/compose/src/test/kotlin/com/yandex/div/compose/TestReporter.kt", diff --git a/client/android/compose/src/main/kotlin/com/yandex/div/compose/DivContext.kt b/client/android/compose/src/main/kotlin/com/yandex/div/compose/DivContext.kt index 094ee4bc2..97504a5ae 100644 --- a/client/android/compose/src/main/kotlin/com/yandex/div/compose/DivContext.kt +++ b/client/android/compose/src/main/kotlin/com/yandex/div/compose/DivContext.kt @@ -3,7 +3,6 @@ package com.yandex.div.compose import android.content.Context import android.content.ContextWrapper import androidx.annotation.VisibleForTesting -import com.yandex.div.compose.context.DivLocalContext import com.yandex.div.compose.context.DivViewContext import com.yandex.div.compose.dagger.DivContextComponent import com.yandex.div.compose.dagger.`Yatagan$DivContextComponent` @@ -11,14 +10,7 @@ import com.yandex.div.compose.internal.DivDebugConfiguration import com.yandex.div.compose.internal.DivDebugFeatures import com.yandex.div.core.annotations.ExperimentalApi import com.yandex.div.core.annotations.InternalApi -import com.yandex.div.core.expression.variables.DivVariableController -import com.yandex.div.evaluable.function.GeneratedBuiltinFunctionProvider -import com.yandex.div.internal.expressions.FunctionProviderDecorator -import com.yandex.div.internal.expressions.toLocalFunctions -import com.yandex.div2.DivBase import com.yandex.div2.DivData -import com.yandex.div2.DivTrigger -import com.yandex.div2.DivVariable /** * An implementation of [android.content.Context] that must be used for composing [DivView]s. @@ -70,68 +62,13 @@ class DivContext private constructor( return it } - val baseFunctionProvider = FunctionProviderDecorator(GeneratedBuiltinFunctionProvider) - val functions = data.functions.orEmpty().toLocalFunctions() return DivViewContext( - rootLocalContext = createLocalContext( - variableController = DivVariableController(component.variableController), - functionProvider = baseFunctionProvider + functions, - triggers = data.variableTriggers.orEmpty(), - variables = data.variables.orEmpty() - ) + data = data, + component = component.viewComponent().build() ).also { component.viewContextStorage.put(data, it) } } - - internal fun getLocalContext( - data: DivBase, - viewContext: DivViewContext, - parentContext: DivLocalContext - ): DivLocalContext { - viewContext.localContextStorage.get(data)?.let { - return it - } - - val functions = data.functions.orEmpty().toLocalFunctions() - val variables = data.variables.orEmpty() - return createLocalContext( - variableController = if (variables.isEmpty()) { - parentContext.variableController - } else { - DivVariableController(parentContext.variableController) - }, - functionProvider = parentContext.functionProvider + functions, - triggers = data.variableTriggers.orEmpty(), - variables = variables - ).also { - viewContext.localContextStorage.put(data, it) - } - } - - private fun createLocalContext( - variableController: DivVariableController, - functionProvider: FunctionProviderDecorator, - triggers: List, - variables: List, - ): DivLocalContext { - val localComponent = component.localComponent() - .functionProvider(functionProvider) - .variableController(variableController) - .build() - - variables.forEach { variableData -> - localComponent.variableAdapter.convert(variableData)?.let { - variableController.declare(it) - } - } - - triggers.forEach { - localComponent.triggerStorage.add(it) - } - - return localComponent.context - } } private fun createComponent( @@ -139,9 +76,9 @@ private fun createComponent( configuration: DivComposeConfiguration, debugConfiguration: DivDebugConfiguration ): DivContextComponent { - return `Yatagan$DivContextComponent`.builder() - .baseContext(baseContext) - .configuration(configuration) - .debugConfiguration(debugConfiguration) - .build() + return `Yatagan$DivContextComponent`.builder().build( + baseContext = baseContext, + configuration = configuration, + debugConfiguration = debugConfiguration + ) } diff --git a/client/android/compose/src/main/kotlin/com/yandex/div/compose/DivView.kt b/client/android/compose/src/main/kotlin/com/yandex/div/compose/DivView.kt index dcfb66b83..3842ef71b 100644 --- a/client/android/compose/src/main/kotlin/com/yandex/div/compose/DivView.kt +++ b/client/android/compose/src/main/kotlin/com/yandex/div/compose/DivView.kt @@ -3,8 +3,8 @@ package com.yandex.div.compose import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.Modifier -import com.yandex.div.compose.context.LocalDivContext import com.yandex.div.compose.context.LocalDivViewContext +import com.yandex.div.compose.dagger.LocalComponent import com.yandex.div.compose.triggers.observe import com.yandex.div.compose.utils.divContext import com.yandex.div.compose.utils.reporter @@ -46,10 +46,11 @@ fun DivView( } val viewContext = divContext.getViewContext(data) - viewContext.rootLocalContext.triggerStorage.observe() + val localComponent = viewContext.rootLocalComponent + localComponent.triggerStorage.observe() CompositionLocalProvider( LocalDivViewContext provides viewContext, - LocalDivContext provides viewContext.rootLocalContext + LocalComponent provides localComponent ) { DivBlockView( data = div, diff --git a/client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/DivActionHandlingContext.kt b/client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/DivActionHandlingContext.kt index 19aeefff9..3cbdc2305 100644 --- a/client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/DivActionHandlingContext.kt +++ b/client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/DivActionHandlingContext.kt @@ -1,7 +1,7 @@ package com.yandex.div.compose.actions +import com.yandex.div.compose.dagger.DivLocalScope import com.yandex.div.core.annotations.ExperimentalApi -import com.yandex.div.core.annotations.Mockable import com.yandex.div.json.expressions.ExpressionResolver import javax.inject.Inject @@ -9,7 +9,7 @@ import javax.inject.Inject * Context passed to action handlers. Provides access to DivKit components * scoped to the element that triggered the action. */ -@Mockable +@DivLocalScope @ExperimentalApi class DivActionHandlingContext @Inject internal constructor( val expressionResolver: ExpressionResolver diff --git a/client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/VisibilityActionTracker.kt b/client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/VisibilityActionTracker.kt index 6cd7549eb..d5e4f13dd 100644 --- a/client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/VisibilityActionTracker.kt +++ b/client/android/compose/src/main/kotlin/com/yandex/div/compose/actions/VisibilityActionTracker.kt @@ -1,6 +1,6 @@ package com.yandex.div.compose.actions -import com.yandex.div.compose.dagger.DivContextScope +import com.yandex.div.compose.dagger.DivViewScope import com.yandex.div2.DivDisappearAction import com.yandex.div2.DivSightAction import com.yandex.div2.DivVisibilityAction @@ -10,7 +10,7 @@ import kotlinx.coroutines.delay import kotlinx.coroutines.launch import javax.inject.Inject -@DivContextScope +@DivViewScope internal class VisibilityActionTracker @Inject constructor( private val actionHandler: DivActionHandler, private val coroutineScope: CoroutineScope diff --git a/client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivLocalComponentStorage.kt b/client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivLocalComponentStorage.kt new file mode 100644 index 000000000..5cdb16b79 --- /dev/null +++ b/client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivLocalComponentStorage.kt @@ -0,0 +1,19 @@ +package com.yandex.div.compose.context + +import com.yandex.div.compose.dagger.DivLocalComponent +import com.yandex.div.compose.dagger.DivViewScope +import com.yandex.div2.DivBase +import javax.inject.Inject + +@DivViewScope +internal class DivLocalComponentStorage @Inject constructor() { + private val items = mutableMapOf() + + fun get(div: DivBase): DivLocalComponent? { + return items[div] + } + + fun put(div: DivBase, context: DivLocalComponent) { + items[div] = context + } +} diff --git a/client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivLocalContext.kt b/client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivLocalContext.kt deleted file mode 100644 index 6615224cc..000000000 --- a/client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivLocalContext.kt +++ /dev/null @@ -1,47 +0,0 @@ -package com.yandex.div.compose.context - -import androidx.compose.runtime.Composable -import androidx.compose.runtime.CompositionLocalProvider -import androidx.compose.runtime.compositionLocalOf -import com.yandex.div.compose.DivException -import com.yandex.div.compose.actions.DivActionHandlingContext -import com.yandex.div.compose.dagger.DivLocalScope -import com.yandex.div.compose.triggers.DivTriggerStorage -import com.yandex.div.compose.triggers.observe -import com.yandex.div.compose.utils.divContext -import com.yandex.div.core.expression.variables.DivVariableController -import com.yandex.div.internal.expressions.FunctionProviderDecorator -import com.yandex.div.json.expressions.ExpressionResolver -import com.yandex.div2.DivBase -import javax.inject.Inject - -@DivLocalScope -internal class DivLocalContext @Inject constructor( - val actionHandlingContext: DivActionHandlingContext, - val expressionResolver: ExpressionResolver, - val functionProvider: FunctionProviderDecorator, - val triggerStorage: DivTriggerStorage, - val variableController: DivVariableController -) - -internal val LocalDivContext = compositionLocalOf { - throw DivException("DivLocalContext not provided") -} - -@Composable -internal fun WithLocalDivContext(data: DivBase, content: @Composable () -> Unit) { - val functions = data.functions.orEmpty() - val variables = data.variables.orEmpty() - val triggers = data.variableTriggers.orEmpty() - if (functions.isEmpty() && variables.isEmpty() && triggers.isEmpty()) { - return content() - } - - val localContext = divContext.getLocalContext( - data, - viewContext = LocalDivViewContext.current, - parentContext = LocalDivContext.current - ) - localContext.triggerStorage.observe() - CompositionLocalProvider(LocalDivContext provides localContext, content) -} diff --git a/client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivLocalContextStorage.kt b/client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivLocalContextStorage.kt deleted file mode 100644 index e29991c19..000000000 --- a/client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivLocalContextStorage.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.yandex.div.compose.context - -import com.yandex.div2.DivBase - -internal class DivLocalContextStorage() { - private val items = mutableMapOf() - - fun get(div: DivBase): DivLocalContext? { - return items[div] - } - - fun put(div: DivBase, context: DivLocalContext) { - items[div] = context - } -} diff --git a/client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivViewContext.kt b/client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivViewContext.kt index d03481657..79233591a 100644 --- a/client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivViewContext.kt +++ b/client/android/compose/src/main/kotlin/com/yandex/div/compose/context/DivViewContext.kt @@ -2,14 +2,88 @@ package com.yandex.div.compose.context import androidx.compose.runtime.compositionLocalOf import com.yandex.div.compose.DivException +import com.yandex.div.compose.actions.VisibilityActionTracker +import com.yandex.div.compose.dagger.DivLocalComponent +import com.yandex.div.compose.dagger.DivViewComponent +import com.yandex.div.core.expression.variables.DivVariableController +import com.yandex.div.evaluable.function.GeneratedBuiltinFunctionProvider +import com.yandex.div.internal.expressions.FunctionProviderDecorator +import com.yandex.div.internal.expressions.toLocalFunctions +import com.yandex.div2.DivBase +import com.yandex.div2.DivData +import com.yandex.div2.DivTrigger +import com.yandex.div2.DivVariable +import kotlin.collections.forEach +import kotlin.collections.orEmpty internal class DivViewContext( - val rootLocalContext: DivLocalContext + data: DivData, + private val component: DivViewComponent ) { - /** - * Stores [DivLocalContext]s for view elements. - */ - val localContextStorage = DivLocalContextStorage() + + val rootLocalComponent: DivLocalComponent + + val visibilityActionTracker: VisibilityActionTracker + get() = component.visibilityActionTracker + + init { + val baseFunctionProvider = FunctionProviderDecorator(GeneratedBuiltinFunctionProvider) + val functions = data.functions.orEmpty().toLocalFunctions() + rootLocalComponent = createLocalComponent( + variableController = DivVariableController(component.variableController), + functionProvider = baseFunctionProvider + functions, + triggers = data.variableTriggers.orEmpty(), + variables = data.variables.orEmpty() + ) + } + + fun getLocalComponent( + data: DivBase, + parentComponent: DivLocalComponent + ): DivLocalComponent { + component.localComponentStorage.get(data)?.let { + return it + } + + val functions = data.functions.orEmpty().toLocalFunctions() + val variables = data.variables.orEmpty() + return createLocalComponent( + variableController = if (variables.isEmpty()) { + parentComponent.variableController + } else { + DivVariableController(parentComponent.variableController) + }, + functionProvider = parentComponent.functionProvider + functions, + triggers = data.variableTriggers.orEmpty(), + variables = variables + ).also { + component.localComponentStorage.put(data, it) + } + } + + private fun createLocalComponent( + variableController: DivVariableController, + functionProvider: FunctionProviderDecorator, + triggers: List, + variables: List, + ): DivLocalComponent { + val localComponent = component.localComponent().build( + functionProvider = functionProvider, + variableController = variableController + ) + + variables.forEach { variableData -> + localComponent.variableAdapter.convert(variableData)?.let { + variableController.declare(it) + } + } + + triggers.forEach { + localComponent.triggerStorage.add(it) + } + + return localComponent + } } internal val LocalDivViewContext = compositionLocalOf { diff --git a/client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivContextComponent.kt b/client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivContextComponent.kt index 60ed404d0..000f91609 100644 --- a/client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivContextComponent.kt +++ b/client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivContextComponent.kt @@ -6,7 +6,6 @@ import com.yandex.div.compose.DivComposeConfiguration import com.yandex.div.compose.DivFontFamilyProvider import com.yandex.div.compose.DivReporter import com.yandex.div.compose.actions.DivActionHandler -import com.yandex.div.compose.actions.VisibilityActionTracker import com.yandex.div.compose.context.DivViewContextStorage import com.yandex.div.compose.internal.DivDebugConfiguration import com.yandex.div.compose.internal.DivDebugFeatures @@ -31,25 +30,18 @@ internal interface DivContextComponent { val imageLoader: ImageLoader val reporter: DivReporter val viewContextStorage: DivViewContextStorage - val visibilityActionTracker: VisibilityActionTracker @get:Named(Names.HOST_VARIABLES) val variableController: DivVariableController - fun localComponent(): DivLocalComponent.Builder + fun viewComponent(): DivViewComponent.Builder @Component.Builder interface Builder { - - @BindsInstance - fun baseContext(baseContext: Context): Builder - - @BindsInstance - fun configuration(configuration: DivComposeConfiguration): Builder - - @BindsInstance - fun debugConfiguration(configuration: DivDebugConfiguration): Builder - - fun build(): DivContextComponent + fun build( + @BindsInstance baseContext: Context, + @BindsInstance configuration: DivComposeConfiguration, + @BindsInstance debugConfiguration: DivDebugConfiguration + ): DivContextComponent } } diff --git a/client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivLocalComponent.kt b/client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivLocalComponent.kt index 3cf436aa7..0ae3b349f 100644 --- a/client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivLocalComponent.kt +++ b/client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivLocalComponent.kt @@ -1,12 +1,21 @@ package com.yandex.div.compose.dagger +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.compositionLocalOf +import com.yandex.div.compose.DivException +import com.yandex.div.compose.actions.DivActionHandlingContext +import com.yandex.div.compose.context.LocalDivViewContext import com.yandex.div.compose.triggers.DivTriggerStorage +import com.yandex.div.compose.triggers.observe import com.yandex.div.compose.variables.DivVariableAdapter -import com.yandex.div.compose.context.DivLocalContext import com.yandex.div.core.expression.variables.DivVariableController import com.yandex.div.internal.expressions.FunctionProviderDecorator +import com.yandex.div.json.expressions.ExpressionResolver +import com.yandex.div2.DivBase import com.yandex.yatagan.BindsInstance import com.yandex.yatagan.Component +import kotlin.collections.orEmpty @DivLocalScope @Component( @@ -17,19 +26,39 @@ import com.yandex.yatagan.Component ) internal interface DivLocalComponent { - val context: DivLocalContext + val actionHandlingContext: DivActionHandlingContext + val expressionResolver: ExpressionResolver + val functionProvider: FunctionProviderDecorator val triggerStorage: DivTriggerStorage val variableAdapter: DivVariableAdapter + val variableController: DivVariableController @Component.Builder interface Builder { - - @BindsInstance - fun functionProvider(functionProvider: FunctionProviderDecorator): Builder - - @BindsInstance - fun variableController(variableController: DivVariableController): Builder - - fun build(): DivLocalComponent + fun build( + @BindsInstance functionProvider: FunctionProviderDecorator, + @BindsInstance variableController: DivVariableController + ): DivLocalComponent } } + +internal val LocalComponent = compositionLocalOf { + throw DivException("DivLocalComponent not provided") +} + +@Composable +internal fun WithLocalComponent(data: DivBase, content: @Composable () -> Unit) { + val functions = data.functions.orEmpty() + val variables = data.variables.orEmpty() + val triggers = data.variableTriggers.orEmpty() + if (functions.isEmpty() && variables.isEmpty() && triggers.isEmpty()) { + return content() + } + + val localComponent = LocalDivViewContext.current.getLocalComponent( + data, + parentComponent = LocalComponent.current + ) + localComponent.triggerStorage.observe() + CompositionLocalProvider(LocalComponent provides localComponent, content) +} diff --git a/client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivViewComponent.kt b/client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivViewComponent.kt new file mode 100644 index 000000000..2294af53c --- /dev/null +++ b/client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivViewComponent.kt @@ -0,0 +1,25 @@ +package com.yandex.div.compose.dagger + +import com.yandex.div.compose.actions.VisibilityActionTracker +import com.yandex.div.compose.context.DivLocalComponentStorage +import com.yandex.div.core.expression.variables.DivVariableController +import com.yandex.yatagan.Component +import javax.inject.Named + +@DivViewScope +@Component(isRoot = false) +internal interface DivViewComponent { + + val localComponentStorage: DivLocalComponentStorage + val visibilityActionTracker: VisibilityActionTracker + + @get:Named(Names.HOST_VARIABLES) + val variableController: DivVariableController + + fun localComponent(): DivLocalComponent.Builder + + @Component.Builder + interface Builder { + fun build(): DivViewComponent + } +} diff --git a/client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivViewScope.kt b/client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivViewScope.kt new file mode 100644 index 000000000..39202043a --- /dev/null +++ b/client/android/compose/src/main/kotlin/com/yandex/div/compose/dagger/DivViewScope.kt @@ -0,0 +1,7 @@ +package com.yandex.div.compose.dagger + +import javax.inject.Scope + +@Scope +@Retention(AnnotationRetention.RUNTIME) +internal annotation class DivViewScope diff --git a/client/android/compose/src/main/kotlin/com/yandex/div/compose/internal/DivDebugFeatures.kt b/client/android/compose/src/main/kotlin/com/yandex/div/compose/internal/DivDebugFeatures.kt index 8eae6d2ea..0804797ab 100644 --- a/client/android/compose/src/main/kotlin/com/yandex/div/compose/internal/DivDebugFeatures.kt +++ b/client/android/compose/src/main/kotlin/com/yandex/div/compose/internal/DivDebugFeatures.kt @@ -26,7 +26,7 @@ class DivDebugFeatures @Inject internal constructor( * Returns [ExpressionResolver] associated with the given [DivData]. */ fun getExpressionResolver(data: DivData): ExpressionResolver? { - return viewContextStorage.get(data)?.rootLocalContext?.expressionResolver + return viewContextStorage.get(data)?.rootLocalComponent?.expressionResolver } /** @@ -36,7 +36,7 @@ class DivDebugFeatures @Inject internal constructor( fun performAction(data: DivData, action: DivAction) { viewContextStorage.get(data)?.let { actionHandler.handle( - context = it.rootLocalContext.actionHandlingContext, + context = it.rootLocalComponent.actionHandlingContext, action = action, source = DivActionSource.EXTERNAL ) diff --git a/client/android/compose/src/main/kotlin/com/yandex/div/compose/utils/Context.kt b/client/android/compose/src/main/kotlin/com/yandex/div/compose/utils/Context.kt index 5cf304b82..42fad7cf3 100644 --- a/client/android/compose/src/main/kotlin/com/yandex/div/compose/utils/Context.kt +++ b/client/android/compose/src/main/kotlin/com/yandex/div/compose/utils/Context.kt @@ -6,13 +6,17 @@ import coil3.ImageLoader import com.yandex.div.compose.DivContext import com.yandex.div.compose.DivFontFamilyProvider import com.yandex.div.compose.DivReporter -import com.yandex.div.compose.context.LocalDivContext +import com.yandex.div.compose.dagger.LocalComponent import com.yandex.div.json.expressions.ExpressionResolver internal val divContext: DivContext @Composable get() = LocalContext.current as DivContext +internal val fontFamilyProvider: DivFontFamilyProvider + @Composable + get() = divContext.component.fontFamilyProvider + internal val imageLoader: ImageLoader @Composable get() = divContext.component.imageLoader @@ -21,10 +25,6 @@ internal val reporter: DivReporter @Composable get() = divContext.component.reporter -internal val fontFamilyProvider: DivFontFamilyProvider - @Composable - get() = divContext.component.fontFamilyProvider - internal val expressionResolver: ExpressionResolver @Composable - get() = LocalDivContext.current.expressionResolver + get() = LocalComponent.current.expressionResolver diff --git a/client/android/compose/src/main/kotlin/com/yandex/div/compose/variables/DivVariableAdapter.kt b/client/android/compose/src/main/kotlin/com/yandex/div/compose/variables/DivVariableAdapter.kt index a9b81731f..18797dd1f 100644 --- a/client/android/compose/src/main/kotlin/com/yandex/div/compose/variables/DivVariableAdapter.kt +++ b/client/android/compose/src/main/kotlin/com/yandex/div/compose/variables/DivVariableAdapter.kt @@ -1,6 +1,6 @@ package com.yandex.div.compose.variables -import com.yandex.div.core.annotations.Mockable +import com.yandex.div.compose.dagger.DivLocalScope import com.yandex.div.data.Variable import com.yandex.div.internal.data.PropertyVariableExecutor import com.yandex.div.internal.variables.toVariable @@ -9,7 +9,7 @@ import com.yandex.div.json.expressions.ExpressionResolver import com.yandex.div2.DivVariable import javax.inject.Inject -@Mockable +@DivLocalScope internal class DivVariableAdapter @Inject constructor( private val expressionResolver: ExpressionResolver, private val parsingErrorLogger: ParsingErrorLogger diff --git a/client/android/compose/src/main/kotlin/com/yandex/div/compose/views/DivBlockView.kt b/client/android/compose/src/main/kotlin/com/yandex/div/compose/views/DivBlockView.kt index cbd96d9f2..04939c165 100644 --- a/client/android/compose/src/main/kotlin/com/yandex/div/compose/views/DivBlockView.kt +++ b/client/android/compose/src/main/kotlin/com/yandex/div/compose/views/DivBlockView.kt @@ -2,7 +2,7 @@ package com.yandex.div.compose.views import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import com.yandex.div.compose.context.WithLocalDivContext +import com.yandex.div.compose.dagger.WithLocalComponent import com.yandex.div.compose.views.container.DivContainerView import com.yandex.div.compose.views.gallery.DivGalleryView import com.yandex.div.compose.views.image.DivImageView @@ -21,9 +21,9 @@ internal fun DivBlockView( modifier: Modifier = Modifier, applyMargins: Boolean = true, ) { - WithLocalDivContext(data.value()) { + WithLocalComponent(data.value()) { if (data.value().visibility.observedValue() == DivVisibility.GONE) { - return@WithLocalDivContext + return@WithLocalComponent } val modifier = modifier.apply(data, applyMargins = applyMargins) diff --git a/client/android/compose/src/main/kotlin/com/yandex/div/compose/views/modifiers/ActionModifiers.kt b/client/android/compose/src/main/kotlin/com/yandex/div/compose/views/modifiers/ActionModifiers.kt index b88312c5b..9a66132e6 100644 --- a/client/android/compose/src/main/kotlin/com/yandex/div/compose/views/modifiers/ActionModifiers.kt +++ b/client/android/compose/src/main/kotlin/com/yandex/div/compose/views/modifiers/ActionModifiers.kt @@ -12,11 +12,11 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.graphicsLayer import com.yandex.div.compose.actions.DivActionSource +import com.yandex.div.compose.dagger.LocalComponent import com.yandex.div.compose.utils.observedFloatValue import com.yandex.div.compose.utils.observedIntValue import com.yandex.div.compose.utils.observedValue import com.yandex.div.compose.utils.reporter -import com.yandex.div.compose.context.LocalDivContext import com.yandex.div.compose.utils.divContext import com.yandex.div2.Div import com.yandex.div2.DivAction @@ -32,7 +32,7 @@ internal fun Modifier.actions(data: Div): Modifier { } val actionHandler = divContext.component.actionHandler - val actionHandlingContext = LocalDivContext.current.actionHandlingContext + val actionHandlingContext = LocalComponent.current.actionHandlingContext val onClick: () -> Unit = { actionHandler.handle(actionHandlingContext, actions, source = DivActionSource.TAP) } diff --git a/client/android/compose/src/main/kotlin/com/yandex/div/compose/views/modifiers/VisibilityActionModifiers.kt b/client/android/compose/src/main/kotlin/com/yandex/div/compose/views/modifiers/VisibilityActionModifiers.kt index 3c6426fa4..5197370d4 100644 --- a/client/android/compose/src/main/kotlin/com/yandex/div/compose/views/modifiers/VisibilityActionModifiers.kt +++ b/client/android/compose/src/main/kotlin/com/yandex/div/compose/views/modifiers/VisibilityActionModifiers.kt @@ -3,8 +3,8 @@ package com.yandex.div.compose.views.modifiers import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.layout.onVisibilityChanged -import com.yandex.div.compose.context.LocalDivContext -import com.yandex.div.compose.utils.divContext +import com.yandex.div.compose.context.LocalDivViewContext +import com.yandex.div.compose.dagger.LocalComponent import com.yandex.div.compose.utils.observedIntValue import com.yandex.div.compose.utils.observedValue import com.yandex.div2.DivBase @@ -24,8 +24,8 @@ internal fun Modifier.visibilityActions(data: DivBase): Modifier { @Composable private fun Modifier.visibilityActions(actions: List): Modifier { - val visibilityActionTracker = divContext.component.visibilityActionTracker - val actionHandlingContext = LocalDivContext.current.actionHandlingContext + val visibilityActionTracker = LocalDivViewContext.current.visibilityActionTracker + val actionHandlingContext = LocalComponent.current.actionHandlingContext var modifier = this actions .filter { shouldRegisterVisibilityCallback(it) } @@ -46,8 +46,8 @@ private fun Modifier.visibilityActions(actions: List): Modi @Composable private fun Modifier.disappearActions(actions: List): Modifier { - val visibilityActionTracker = divContext.component.visibilityActionTracker - val actionHandlingContext = LocalDivContext.current.actionHandlingContext + val visibilityActionTracker = LocalDivViewContext.current.visibilityActionTracker + val actionHandlingContext = LocalComponent.current.actionHandlingContext var modifier = this actions .filter { shouldRegisterVisibilityCallback(it) } @@ -67,7 +67,7 @@ private fun Modifier.disappearActions(actions: List): Modifi @Composable private fun shouldRegisterVisibilityCallback(action: DivSightAction): Boolean { - return !divContext.component.visibilityActionTracker.isLimitReached( + return !LocalDivViewContext.current.visibilityActionTracker.isLimitReached( action = action, limit = action.logLimit.observedIntValue() ) diff --git a/client/android/compose/src/main/kotlin/com/yandex/div/compose/views/state/ObserveActiveState.kt b/client/android/compose/src/main/kotlin/com/yandex/div/compose/views/state/ObserveActiveState.kt index 17c7b6d90..e2fe1512a 100644 --- a/client/android/compose/src/main/kotlin/com/yandex/div/compose/views/state/ObserveActiveState.kt +++ b/client/android/compose/src/main/kotlin/com/yandex/div/compose/views/state/ObserveActiveState.kt @@ -2,7 +2,7 @@ package com.yandex.div.compose.views.state import androidx.compose.runtime.Composable import androidx.compose.runtime.remember -import com.yandex.div.compose.context.LocalDivContext +import com.yandex.div.compose.dagger.LocalComponent import com.yandex.div.compose.utils.expressionResolver import com.yandex.div.compose.utils.observedVariableValue import com.yandex.div.compose.utils.reporter @@ -16,7 +16,7 @@ internal fun DivState.observeActiveState(): DivState.State? { } val activeStateId = stateVariable?.let { - LocalDivContext.current.variableController.observedVariableValue(it) + LocalComponent.current.variableController.observedVariableValue(it) } val resolver = expressionResolver diff --git a/client/android/compose/src/test/kotlin/com/yandex/div/compose/DivViewWithVisibilityActionsRecomompositionTest.kt b/client/android/compose/src/test/kotlin/com/yandex/div/compose/DivViewWithVisibilityActionsRecomompositionTest.kt new file mode 100644 index 000000000..afe52be90 --- /dev/null +++ b/client/android/compose/src/test/kotlin/com/yandex/div/compose/DivViewWithVisibilityActionsRecomompositionTest.kt @@ -0,0 +1,174 @@ +package com.yandex.div.compose + +import android.view.View +import androidx.activity.ComponentActivity +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.test.assertIsDisplayed +import androidx.compose.ui.test.assertTextEquals +import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.onNodeWithTag +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.yandex.div.compose.internal.DivDebugConfiguration +import com.yandex.div.core.expression.variables.DivVariableController +import com.yandex.div.data.Variable +import com.yandex.div.test.data.data +import com.yandex.div.test.data.expression +import com.yandex.div.test.data.intExpression +import com.yandex.div.test.data.setVariableAction +import com.yandex.div.test.data.text +import com.yandex.div.test.data.typedValue +import com.yandex.div.test.data.visibilityAction +import com.yandex.div.test.data.visibilityExpression +import com.yandex.div2.DivActionTyped +import com.yandex.div2.DivData +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import kotlin.math.min + +@RunWith(AndroidJUnit4::class) +class DivViewWithVisibilityActionsRecompositionTest { + + @get:Rule + val rule = createAndroidComposeRule().apply { + mainClock.autoAdvance = false + } + + private val activity: ComponentActivity + get() = rule.activity + + private val counter = Variable.IntegerVariable("counter", 0) + private val visibility = Variable.StringVariable("visibility", "visible") + + private val variableController = DivVariableController().apply { + declare(counter, visibility) + } + + private val testScope = TestScope() + + private lateinit var divContext: DivContext + + @Before + fun setUp() { + divContext = DivContext( + baseContext = activity, + configuration = DivComposeConfiguration( + reporter = TestReporter(), + variableController = variableController + ), + debugConfiguration = DivDebugConfiguration( + coroutineScope = testScope + ) + ) + } + + @Test + fun `visibility action limit does not reset when ComposeView is recreated with the same context`() { + val data = data( + content = text( + id = "counter", + text = expression("counter = @{counter}"), + visibility = visibilityExpression("@{visibility}"), + visibilityActions = listOf( + visibilityAction(delayMs = 500, limit = 2, typed = incrementCounterAction()) + ) + ) + ) + + setContent(data) + + rule.onNodeWithTag("counter").assertTextEquals("counter = 0") + advanceTimeBy(500) + rule.onNodeWithTag("counter").assertTextEquals("counter = 1") + + activity.setContentView(View(activity)) + setContent(data) + + rule.onNodeWithTag("counter").assertTextEquals("counter = 1") + advanceTimeBy(500) + + repeat(5) { + rule.onNodeWithTag("counter").assertTextEquals("counter = 2") + hideCounter() + showCounter() + advanceTimeBy(500) + } + } + + @Test + fun `visibility action limit resets when the view context was cleared`() { + val data = data( + content = text( + id = "counter", + text = expression("counter = @{counter}"), + visibility = visibilityExpression("@{visibility}"), + visibilityActions = listOf( + visibilityAction(delayMs = 500, limit = 3, typed = incrementCounterAction()) + ) + ) + ) + + setContent(data) + + rule.onNodeWithTag("counter").assertTextEquals("counter = 0") + advanceTimeBy(500) + rule.onNodeWithTag("counter").assertTextEquals("counter = 1") + + activity.setContentView(View(activity)) + divContext.clearViewContext(data) + counter.set(0) + setContent(data) + + repeat(5) { + rule.onNodeWithTag("counter").assertTextEquals("counter = ${min(it, 3)}") + hideCounter() + showCounter() + advanceTimeBy(500) + } + } + + private fun setContent(data: DivData) { + activity.setContentView( + ComposeView(divContext).apply { + setContent { + DivView(data) + } + } + ) + } + + private fun showCounter() { + withAutoAdvance { + visibility.set("visible") + rule.onNodeWithTag("counter").assertIsDisplayed() + } + } + + private fun hideCounter() { + withAutoAdvance { + visibility.set("gone") + rule.onNodeWithTag("counter").assertDoesNotExist() + } + } + + @OptIn(ExperimentalCoroutinesApi::class) + private fun advanceTimeBy(duration: Long) { + testScope.testScheduler.advanceTimeBy(duration) + testScope.testScheduler.runCurrent() + rule.mainClock.advanceTimeBy(duration) + rule.mainClock.advanceTimeByFrame() + } + + private fun withAutoAdvance(block: () -> Unit) { + rule.mainClock.autoAdvance = true + block() + rule.mainClock.autoAdvance = false + } +} + +private fun incrementCounterAction(): DivActionTyped { + return setVariableAction("counter", typedValue(intExpression("@{counter + 1}"))) +} diff --git a/client/android/compose/src/test/kotlin/com/yandex/div/compose/utils/DivVariableControllerTest.kt b/client/android/compose/src/test/kotlin/com/yandex/div/compose/utils/DivVariableControllerTest.kt index 235ec9f80..578c19d90 100644 --- a/client/android/compose/src/test/kotlin/com/yandex/div/compose/utils/DivVariableControllerTest.kt +++ b/client/android/compose/src/test/kotlin/com/yandex/div/compose/utils/DivVariableControllerTest.kt @@ -11,9 +11,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.yandex.div.compose.DivComposeConfiguration import com.yandex.div.compose.DivContext import com.yandex.div.compose.TestReporter -import com.yandex.div.compose.context.DivLocalContext -import com.yandex.div.compose.context.LocalDivContext import com.yandex.div.compose.createExpressionResolver +import com.yandex.div.compose.dagger.DivLocalComponent +import com.yandex.div.compose.dagger.LocalComponent import com.yandex.div.core.expression.variables.DivVariableController import com.yandex.div.data.Variable import org.junit.Assert.assertEquals @@ -21,6 +21,7 @@ import org.junit.Assert.assertNull import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock @RunWith(AndroidJUnit4::class) @@ -29,19 +30,16 @@ class DivVariableControllerTest { @get:Rule val composeRule = createComposeRule() - private val variableController = DivVariableController() private val reporter = TestReporter() + private val variableController = DivVariableController() - private val localContext = DivLocalContext( - actionHandlingContext = mock(), - expressionResolver = createExpressionResolver( + private val localComponent = mock { + on { expressionResolver } doReturn createExpressionResolver( reporter = reporter, variableController = variableController - ), - functionProvider = mock(), - triggerStorage = mock(), - variableController = variableController - ) + ) + on { variableController } doReturn variableController + } @Test fun `returns current value of string variable`() { @@ -156,7 +154,7 @@ class DivVariableControllerTest { ) CompositionLocalProvider( LocalContext provides divContext, - LocalDivContext provides localContext, + LocalComponent provides localComponent, ) { content() } diff --git a/client/android/compose/src/test/kotlin/com/yandex/div/compose/utils/ExpressionUtilsTest.kt b/client/android/compose/src/test/kotlin/com/yandex/div/compose/utils/ExpressionUtilsTest.kt index 8fa2738c9..1b9a35120 100644 --- a/client/android/compose/src/test/kotlin/com/yandex/div/compose/utils/ExpressionUtilsTest.kt +++ b/client/android/compose/src/test/kotlin/com/yandex/div/compose/utils/ExpressionUtilsTest.kt @@ -10,8 +10,8 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.test.junit4.createComposeRule import androidx.test.ext.junit.runners.AndroidJUnit4 import com.yandex.div.compose.createExpressionResolver -import com.yandex.div.compose.context.DivLocalContext -import com.yandex.div.compose.context.LocalDivContext +import com.yandex.div.compose.dagger.DivLocalComponent +import com.yandex.div.compose.dagger.LocalComponent import com.yandex.div.core.expression.variables.DivVariableController import com.yandex.div.data.Variable import com.yandex.div.json.expressions.Expression @@ -20,6 +20,7 @@ import org.junit.Assert.assertEquals import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock @RunWith(AndroidJUnit4::class) @@ -30,15 +31,12 @@ class ExpressionUtilsTest { private val variableController = DivVariableController() - private val localContext = DivLocalContext( - actionHandlingContext = mock(), - expressionResolver = createExpressionResolver( + private val localComponent = mock { + on { expressionResolver } doReturn createExpressionResolver( variableController = variableController - ), - functionProvider = mock(), - triggerStorage = mock(), - variableController = variableController - ) + ) + on { variableController } doReturn variableController + } @Test fun `observed value changes when variable changes`() { @@ -213,7 +211,7 @@ class ExpressionUtilsTest { private fun setContent(content: @Composable () -> Unit) { composeRule.setContent { - CompositionLocalProvider(LocalDivContext provides localContext) { + CompositionLocalProvider(LocalComponent provides localComponent) { content() } } diff --git a/client/android/compose/src/test/kotlin/com/yandex/div/compose/views/state/ObserveActiveStateTest.kt b/client/android/compose/src/test/kotlin/com/yandex/div/compose/views/state/ObserveActiveStateTest.kt index dbf619f1c..e959144de 100644 --- a/client/android/compose/src/test/kotlin/com/yandex/div/compose/views/state/ObserveActiveStateTest.kt +++ b/client/android/compose/src/test/kotlin/com/yandex/div/compose/views/state/ObserveActiveStateTest.kt @@ -11,9 +11,9 @@ import androidx.test.ext.junit.runners.AndroidJUnit4 import com.yandex.div.compose.DivComposeConfiguration import com.yandex.div.compose.DivContext import com.yandex.div.compose.TestReporter -import com.yandex.div.compose.context.DivLocalContext -import com.yandex.div.compose.context.LocalDivContext import com.yandex.div.compose.createExpressionResolver +import com.yandex.div.compose.dagger.DivLocalComponent +import com.yandex.div.compose.dagger.LocalComponent import com.yandex.div.core.expression.variables.DivVariableController import com.yandex.div.data.DivModelInternalApi import com.yandex.div.data.Variable @@ -26,6 +26,7 @@ import org.junit.Assert.assertNotNull import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith +import org.mockito.kotlin.doReturn import org.mockito.kotlin.mock @OptIn(DivModelInternalApi::class) @@ -35,19 +36,16 @@ class ObserveActiveStateTest { @get:Rule val composeRule = createComposeRule() - private val variableController = DivVariableController() private val reporter = TestReporter() + private val variableController = DivVariableController() - private val localContext = DivLocalContext( - actionHandlingContext = mock(), - expressionResolver = createExpressionResolver( + private val localComponent = mock { + on { expressionResolver } doReturn createExpressionResolver( reporter = reporter, variableController = variableController - ), - functionProvider = mock(), - triggerStorage = mock(), - variableController = variableController - ) + ) + on { variableController } doReturn variableController + } @Test fun `resolves state by stateIdVariable`() { @@ -200,7 +198,7 @@ class ObserveActiveStateTest { ) CompositionLocalProvider( LocalContext provides divContext, - LocalDivContext provides localContext, + LocalComponent provides localComponent, ) { content() }