diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt index 9071425a72..9ea060ef6c 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt @@ -383,7 +383,16 @@ class RoomDetailsFlowNode( knockRequestsListEntryPoint.createNode(this, buildContext) } NavTarget.SecurityAndPrivacy -> { - securityAndPrivacyEntryPoint.createNode(this, buildContext) + val callback = object : SecurityAndPrivacyEntryPoint.Callback { + override fun onDone() { + backstack.pop() + } + } + securityAndPrivacyEntryPoint.createNode( + parentNode = this, + buildContext = buildContext, + callback = callback, + ) } is NavTarget.VerifyUser -> { val params = OutgoingVerificationEntryPoint.Params( diff --git a/features/securityandprivacy/api/src/main/kotlin/io/element/android/features/securityandprivacy/api/SecurityAndPrivacyEntryPoint.kt b/features/securityandprivacy/api/src/main/kotlin/io/element/android/features/securityandprivacy/api/SecurityAndPrivacyEntryPoint.kt index 2c7c1cfd41..be2a4dc9e2 100644 --- a/features/securityandprivacy/api/src/main/kotlin/io/element/android/features/securityandprivacy/api/SecurityAndPrivacyEntryPoint.kt +++ b/features/securityandprivacy/api/src/main/kotlin/io/element/android/features/securityandprivacy/api/SecurityAndPrivacyEntryPoint.kt @@ -8,6 +8,19 @@ package io.element.android.features.securityandprivacy.api -import io.element.android.libraries.architecture.SimpleFeatureEntryPoint +import com.bumble.appyx.core.modality.BuildContext +import com.bumble.appyx.core.node.Node +import com.bumble.appyx.core.plugin.Plugin +import io.element.android.libraries.architecture.FeatureEntryPoint -fun interface SecurityAndPrivacyEntryPoint : SimpleFeatureEntryPoint +fun interface SecurityAndPrivacyEntryPoint : FeatureEntryPoint { + interface Callback : Plugin { + fun onDone() + } + + fun createNode( + parentNode: Node, + buildContext: BuildContext, + callback: Callback, + ): Node +} diff --git a/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/DefaultSecurityAndPrivacyEntryPoint.kt b/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/DefaultSecurityAndPrivacyEntryPoint.kt index 2d01ed4a83..d2a40c6836 100644 --- a/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/DefaultSecurityAndPrivacyEntryPoint.kt +++ b/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/DefaultSecurityAndPrivacyEntryPoint.kt @@ -17,7 +17,11 @@ import io.element.android.libraries.di.RoomScope @ContributesBinding(RoomScope::class) class DefaultSecurityAndPrivacyEntryPoint : SecurityAndPrivacyEntryPoint { - override fun createNode(parentNode: Node, buildContext: BuildContext): Node { - return parentNode.createNode(buildContext) + override fun createNode( + parentNode: Node, + buildContext: BuildContext, + callback: SecurityAndPrivacyEntryPoint.Callback, + ): Node { + return parentNode.createNode(buildContext, listOf(callback)) } } diff --git a/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/SecurityAndPrivacyFlowNode.kt b/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/SecurityAndPrivacyFlowNode.kt index 5dbc8dbb45..13c5b454a2 100644 --- a/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/SecurityAndPrivacyFlowNode.kt +++ b/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/SecurityAndPrivacyFlowNode.kt @@ -18,10 +18,12 @@ import com.bumble.appyx.navmodel.backstack.BackStack import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.AssistedInject import io.element.android.annotations.ContributesNode +import io.element.android.features.securityandprivacy.api.SecurityAndPrivacyEntryPoint import io.element.android.features.securityandprivacy.impl.editroomaddress.EditRoomAddressNode import io.element.android.features.securityandprivacy.impl.root.SecurityAndPrivacyNode import io.element.android.libraries.architecture.BackstackView import io.element.android.libraries.architecture.BaseFlowNode +import io.element.android.libraries.architecture.callback import io.element.android.libraries.architecture.createNode import io.element.android.libraries.di.RoomScope import kotlinx.parcelize.Parcelize @@ -47,7 +49,8 @@ class SecurityAndPrivacyFlowNode( data object EditRoomAddress : NavTarget } - private val navigator = BackstackSecurityAndPrivacyNavigator(backstack) + private val callback: SecurityAndPrivacyEntryPoint.Callback = callback() + private val navigator = BackstackSecurityAndPrivacyNavigator(callback, backstack) override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { return when (navTarget) { diff --git a/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/SecurityAndPrivacyNavigator.kt b/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/SecurityAndPrivacyNavigator.kt index 3b71868bbf..092da87943 100644 --- a/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/SecurityAndPrivacyNavigator.kt +++ b/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/SecurityAndPrivacyNavigator.kt @@ -12,15 +12,22 @@ import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.navmodel.backstack.BackStack import com.bumble.appyx.navmodel.backstack.operation.pop import com.bumble.appyx.navmodel.backstack.operation.push +import io.element.android.features.securityandprivacy.api.SecurityAndPrivacyEntryPoint interface SecurityAndPrivacyNavigator : Plugin { + fun onDone() fun openEditRoomAddress() fun closeEditRoomAddress() } class BackstackSecurityAndPrivacyNavigator( + private val callback: SecurityAndPrivacyEntryPoint.Callback, private val backStack: BackStack ) : SecurityAndPrivacyNavigator { + override fun onDone() { + callback.onDone() + } + override fun openEditRoomAddress() { backStack.push(SecurityAndPrivacyFlowNode.NavTarget.EditRoomAddress) } diff --git a/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyNode.kt b/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyNode.kt index 5e329a06f6..e173117431 100644 --- a/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyNode.kt +++ b/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyNode.kt @@ -40,7 +40,6 @@ class SecurityAndPrivacyNode( val state by stateFlow.collectAsState() SecurityAndPrivacyView( state = state, - onBackClick = this::navigateUp, modifier = modifier ) } diff --git a/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyPresenter.kt b/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyPresenter.kt index 43d8383b76..cdd70259c4 100644 --- a/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyPresenter.kt +++ b/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyPresenter.kt @@ -64,7 +64,6 @@ class SecurityAndPrivacyPresenter( featureFlagService.isFeatureEnabledFlow(FeatureFlags.Knock) }.collectAsState(false) val saveAction = remember { mutableStateOf>(AsyncAction.Uninitialized) } - var confirmExitAction by remember { mutableStateOf>(AsyncAction.Uninitialized) } val homeserverName = remember { matrixClient.userIdServerName() } val syncUpdateFlow = room.syncUpdateFlow.collectAsState() val roomInfo by room.roomInfoFlow.collectAsState() @@ -150,18 +149,24 @@ class SecurityAndPrivacyPresenter( saveAction.value = AsyncAction.Uninitialized } SecurityAndPrivacyEvents.Exit -> { - confirmExitAction = if (savedSettings == editedSettings || confirmExitAction.isConfirming()) { + saveAction.value = if (savedSettings == editedSettings || saveAction.value == AsyncAction.ConfirmingCancellation) { AsyncAction.Success(Unit) } else { - AsyncAction.ConfirmingNoParams + AsyncAction.ConfirmingCancellation } } SecurityAndPrivacyEvents.DismissExitConfirmation -> { - confirmExitAction = AsyncAction.Uninitialized + saveAction.value = AsyncAction.Uninitialized } } } + LaunchedEffect(saveAction.value.isSuccess()) { + if (saveAction.value.isSuccess()) { + navigator.onDone() + } + } + val state = SecurityAndPrivacyState( savedSettings = savedSettings, editedSettings = editedSettings, @@ -171,7 +176,6 @@ class SecurityAndPrivacyPresenter( saveAction = saveAction.value, permissions = permissions, isSpace = roomInfo.isSpace, - confirmExitAction = confirmExitAction, eventSink = ::handleEvent, ) diff --git a/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyState.kt b/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyState.kt index 0671bbf163..61e8ffd17c 100644 --- a/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyState.kt +++ b/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyState.kt @@ -22,7 +22,6 @@ data class SecurityAndPrivacyState( val showEnableEncryptionConfirmation: Boolean, val isKnockEnabled: Boolean, val saveAction: AsyncAction, - val confirmExitAction: AsyncAction, val isSpace: Boolean, private val permissions: SecurityAndPrivacyPermissions, val eventSink: (SecurityAndPrivacyEvents) -> Unit diff --git a/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyStateProvider.kt b/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyStateProvider.kt index 11e5665c1c..db696b18e8 100644 --- a/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyStateProvider.kt +++ b/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyStateProvider.kt @@ -27,7 +27,7 @@ open class SecurityAndPrivacyStateProvider : PreviewParameterProvider = AsyncAction.Uninitialized, - confirmExitAction: AsyncAction = AsyncAction.Uninitialized, permissions: SecurityAndPrivacyPermissions = SecurityAndPrivacyPermissions( canChangeRoomAccess = true, canChangeHistoryVisibility = true, @@ -125,7 +124,6 @@ fun aSecurityAndPrivacyState( homeserverName = homeserverName, showEnableEncryptionConfirmation = showEncryptionConfirmation, saveAction = saveAction, - confirmExitAction = confirmExitAction, isKnockEnabled = isKnockEnabled, permissions = permissions, isSpace = isSpace, diff --git a/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyView.kt b/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyView.kt index 019eac665c..d526f381be 100644 --- a/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyView.kt +++ b/features/securityandprivacy/impl/src/main/kotlin/io/element/android/features/securityandprivacy/impl/root/SecurityAndPrivacyView.kt @@ -32,6 +32,7 @@ import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.features.securityandprivacy.impl.R +import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.coverage.ExcludeFromCoverage import io.element.android.libraries.designsystem.components.async.AsyncActionView @@ -56,7 +57,6 @@ import kotlinx.collections.immutable.ImmutableSet @Composable fun SecurityAndPrivacyView( state: SecurityAndPrivacyState, - onBackClick: () -> Unit, modifier: Modifier = Modifier, ) { BackHandler { @@ -130,6 +130,16 @@ fun SecurityAndPrivacyView( async = state.saveAction, onSuccess = { }, onErrorDismiss = { state.eventSink(SecurityAndPrivacyEvents.DismissSaveError) }, + confirmationDialog = { confirming -> + when (confirming) { + is AsyncAction.ConfirmingCancellation -> + SaveChangesDialog( + onSaveClick = { state.eventSink(SecurityAndPrivacyEvents.Save) }, + onDiscardClick = { state.eventSink(SecurityAndPrivacyEvents.Exit) }, + onDismiss = { state.eventSink(SecurityAndPrivacyEvents.DismissExitConfirmation) } + ) + } + }, errorMessage = { stringResource(CommonStrings.error_unknown) }, progressDialog = { AsyncActionViewDefaults.ProgressDialog( @@ -138,18 +148,6 @@ fun SecurityAndPrivacyView( }, onRetry = { state.eventSink(SecurityAndPrivacyEvents.Save) }, ) - AsyncActionView( - async = state.confirmExitAction, - onSuccess = { onBackClick() }, - onErrorDismiss = { }, - confirmationDialog = { - SaveChangesDialog( - onSaveClick = { state.eventSink(SecurityAndPrivacyEvents.Save) }, - onDiscardClick = { state.eventSink(SecurityAndPrivacyEvents.Exit) }, - onDismiss = { state.eventSink(SecurityAndPrivacyEvents.DismissExitConfirmation) } - ) - }, - ) } @OptIn(ExperimentalMaterial3Api::class) @@ -426,6 +424,5 @@ internal fun SecurityAndPrivacyViewDarkPreview(@PreviewParameter(SecurityAndPriv private fun ContentToPreview(state: SecurityAndPrivacyState) { SecurityAndPrivacyView( state = state, - onBackClick = {}, ) } diff --git a/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/FakeSecurityAndPrivacyNavigator.kt b/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/FakeSecurityAndPrivacyNavigator.kt index 9ca3cc5288..f90040d3fb 100644 --- a/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/FakeSecurityAndPrivacyNavigator.kt +++ b/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/FakeSecurityAndPrivacyNavigator.kt @@ -11,9 +11,14 @@ package io.element.android.features.securityandprivacy.impl import io.element.android.tests.testutils.lambda.lambdaError class FakeSecurityAndPrivacyNavigator( + private val onDoneLambda: () -> Unit = { lambdaError() }, private val openEditRoomAddressLambda: () -> Unit = { lambdaError() }, private val closeEditRoomAddressLambda: () -> Unit = { lambdaError() }, ) : SecurityAndPrivacyNavigator { + override fun onDone() { + onDoneLambda() + } + override fun openEditRoomAddress() { openEditRoomAddressLambda() } diff --git a/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/SecurityAndPrivacyPresenterTest.kt b/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/SecurityAndPrivacyPresenterTest.kt index bdae5274f0..203447c911 100644 --- a/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/SecurityAndPrivacyPresenterTest.kt +++ b/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/SecurityAndPrivacyPresenterTest.kt @@ -203,7 +203,7 @@ class SecurityAndPrivacyPresenterTest { @Test fun `present - edit room address`() = runTest { val openEditRoomAddressLambda = lambdaRecorder { } - val navigator = FakeSecurityAndPrivacyNavigator(openEditRoomAddressLambda) + val navigator = FakeSecurityAndPrivacyNavigator(openEditRoomAddressLambda = openEditRoomAddressLambda) val presenter = createSecurityAndPrivacyPresenter(navigator = navigator) presenter.test { skipItems(1) @@ -231,7 +231,14 @@ class SecurityAndPrivacyPresenterTest { updateRoomVisibilityResult = updateRoomVisibilityLambda, updateRoomHistoryVisibilityResult = updateRoomHistoryVisibilityLambda, ) - val presenter = createSecurityAndPrivacyPresenter(room = room) + val onDoneLambda = lambdaRecorder { } + val navigator = FakeSecurityAndPrivacyNavigator( + onDoneLambda = onDoneLambda, + ) + val presenter = createSecurityAndPrivacyPresenter( + room = room, + navigator = navigator, + ) presenter.test { skipItems(2) with(awaitItem()) { @@ -276,6 +283,7 @@ class SecurityAndPrivacyPresenterTest { assert(updateJoinRuleLambda).isCalledOnce() assert(updateRoomVisibilityLambda).isCalledOnce() assert(updateRoomHistoryVisibilityLambda).isCalledOnce() + onDoneLambda.assertions().isCalledOnce() } } diff --git a/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/SecurityAndPrivacyViewTest.kt b/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/SecurityAndPrivacyViewTest.kt index 78b840d823..d1096c19af 100644 --- a/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/SecurityAndPrivacyViewTest.kt +++ b/features/securityandprivacy/impl/src/test/kotlin/io/element/android/features/securityandprivacy/impl/SecurityAndPrivacyViewTest.kt @@ -24,7 +24,6 @@ import io.element.android.features.securityandprivacy.impl.root.aSecurityAndPriv import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.ui.strings.CommonStrings -import io.element.android.tests.testutils.EnsureNeverCalled import io.element.android.tests.testutils.EventsRecorder import io.element.android.tests.testutils.clickOn import io.element.android.tests.testutils.pressBack @@ -50,27 +49,27 @@ class SecurityAndPrivacyViewTest { } @Test - fun `confirm cancellation emits the expected event`() { + fun `discard cancellation emits the expected event`() { val recorder = EventsRecorder() val state = aSecurityAndPrivacyState( - confirmExitAction = AsyncAction.ConfirmingCancellation, + saveAction = AsyncAction.ConfirmingCancellation, eventSink = recorder, ) rule.setSecurityAndPrivacyView(state) - rule.clickOn(CommonStrings.action_ok) + rule.clickOn(CommonStrings.action_discard) recorder.assertSingle(SecurityAndPrivacyEvents.Exit) } @Test - fun `dismiss cancellation confirmation emits the expected event`() { + fun `save cancellation confirmation emits the expected event`() { val recorder = EventsRecorder() val state = aSecurityAndPrivacyState( - confirmExitAction = AsyncAction.ConfirmingCancellation, + saveAction = AsyncAction.ConfirmingCancellation, eventSink = recorder, ) rule.setSecurityAndPrivacyView(state) - rule.clickOn(CommonStrings.action_cancel) - recorder.assertSingle(SecurityAndPrivacyEvents.DismissExitConfirmation) + rule.clickOn(CommonStrings.action_save, inDialog = true) + recorder.assertSingle(SecurityAndPrivacyEvents.Save) } @Test @@ -185,12 +184,10 @@ private fun AndroidComposeTestRule.setSecur state: SecurityAndPrivacyState = aSecurityAndPrivacyState( eventSink = EventsRecorder(expectEvents = false), ), - onBackClick: () -> Unit = EnsureNeverCalled(), ) { setContent { SecurityAndPrivacyView( state = state, - onBackClick = onBackClick, ) } } diff --git a/features/securityandprivacy/test/src/main/kotlin/io/element/android/features/securityandprivacy/test/FakeSecurityAndPrivacyEntryPoint.kt b/features/securityandprivacy/test/src/main/kotlin/io/element/android/features/securityandprivacy/test/FakeSecurityAndPrivacyEntryPoint.kt index f316b2fe96..a66fe55bff 100644 --- a/features/securityandprivacy/test/src/main/kotlin/io/element/android/features/securityandprivacy/test/FakeSecurityAndPrivacyEntryPoint.kt +++ b/features/securityandprivacy/test/src/main/kotlin/io/element/android/features/securityandprivacy/test/FakeSecurityAndPrivacyEntryPoint.kt @@ -13,7 +13,11 @@ import io.element.android.features.securityandprivacy.api.SecurityAndPrivacyEntr import io.element.android.tests.testutils.lambda.lambdaError class FakeSecurityAndPrivacyEntryPoint : SecurityAndPrivacyEntryPoint { - override fun createNode(parentNode: Node, buildContext: BuildContext): Node { + override fun createNode( + parentNode: Node, + buildContext: BuildContext, + callback: SecurityAndPrivacyEntryPoint.Callback, + ): Node { lambdaError() } } diff --git a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/SemanticsNodeInteractionsProviderExtensions.kt b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/SemanticsNodeInteractionsProviderExtensions.kt index f81b03b10b..982320aed7 100644 --- a/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/SemanticsNodeInteractionsProviderExtensions.kt +++ b/tests/testutils/src/main/kotlin/io/element/android/tests/testutils/SemanticsNodeInteractionsProviderExtensions.kt @@ -10,11 +10,14 @@ package io.element.android.tests.testutils import androidx.activity.ComponentActivity import androidx.annotation.StringRes +import androidx.compose.ui.test.SemanticsMatcher import androidx.compose.ui.test.SemanticsNodeInteractionsProvider +import androidx.compose.ui.test.hasAnyAncestor import androidx.compose.ui.test.hasClickAction import androidx.compose.ui.test.hasContentDescription import androidx.compose.ui.test.hasTestTag import androidx.compose.ui.test.hasText +import androidx.compose.ui.test.isDialog import androidx.compose.ui.test.junit4.AndroidComposeTestRule import androidx.compose.ui.test.onFirst import androidx.compose.ui.test.onNodeWithText @@ -22,9 +25,16 @@ import androidx.compose.ui.test.performClick import io.element.android.libraries.ui.strings.CommonStrings import org.junit.rules.TestRule -fun AndroidComposeTestRule.clickOn(@StringRes res: Int) { +val trueMatcher = SemanticsMatcher("true matcher") { true } + +fun AndroidComposeTestRule.clickOn( + @StringRes res: Int, + inDialog: Boolean = false, +) { val text = activity.getString(res) - onNode(hasText(text) and hasClickAction()) + onNode( + hasText(text) and hasClickAction() and if (inDialog) hasAnyAncestor(isDialog()) else trueMatcher + ) .performClick() }