diff --git a/features/preferences/impl/build.gradle.kts b/features/preferences/impl/build.gradle.kts index e647ebb919..80ac4b3ba3 100644 --- a/features/preferences/impl/build.gradle.kts +++ b/features/preferences/impl/build.gradle.kts @@ -64,6 +64,7 @@ dependencies { implementation(projects.libraries.testtags) implementation(projects.libraries.uiStrings) implementation(projects.libraries.matrixui) + implementation(projects.libraries.mediaviewer.api) implementation(projects.libraries.mediapickers.api) implementation(projects.libraries.mediaupload.api) implementation(projects.libraries.permissions.api) @@ -108,6 +109,7 @@ dependencies { testImplementation(projects.libraries.push.test) testImplementation(projects.libraries.pushstore.test) testImplementation(projects.libraries.roomselect.test) + testImplementation(projects.libraries.mediaviewer.test) testImplementation(projects.libraries.troubleshoot.test) testImplementation(projects.features.deactivation.test) testImplementation(projects.features.enterprise.test) diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt index 15718ca0f0..c85eed5b9d 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt @@ -40,10 +40,12 @@ import io.element.android.libraries.architecture.BaseFlowNode import io.element.android.libraries.architecture.appyx.canPop import io.element.android.libraries.architecture.callback import io.element.android.libraries.architecture.createNode +import io.element.android.libraries.core.mimetype.MimeTypes import io.element.android.libraries.di.SessionScope import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.user.MatrixUser +import io.element.android.libraries.mediaviewer.api.FileViewerEntryPoint import io.element.android.libraries.troubleshoot.api.NotificationTroubleShootEntryPoint import io.element.android.libraries.troubleshoot.api.PushHistoryEntryPoint import kotlinx.parcelize.Parcelize @@ -56,6 +58,7 @@ class PreferencesFlowNode( private val lockScreenEntryPoint: LockScreenEntryPoint, private val notificationTroubleShootEntryPoint: NotificationTroubleShootEntryPoint, private val pushHistoryEntryPoint: PushHistoryEntryPoint, + private val fileViewerEntryPoint: FileViewerEntryPoint, private val logoutEntryPoint: LogoutEntryPoint, private val openSourceLicensesEntryPoint: OpenSourceLicensesEntryPoint, private val accountDeactivationEntryPoint: AccountDeactivationEntryPoint, @@ -95,6 +98,9 @@ class PreferencesFlowNode( @Parcelize data object PushHistory : NavTarget + @Parcelize + data class PushRules(val filename: String, val content: String) : NavTarget + @Parcelize data object LockScreenSettings : NavTarget @@ -187,6 +193,10 @@ class PreferencesFlowNode( } NavTarget.DeveloperSettings -> { val developerSettingsCallback = object : DeveloperSettingsNode.Callback { + override fun navigateToPushRules(filename: String, content: String) { + backstack.push(NavTarget.PushRules(filename = filename, content = content)) + } + override fun navigateToPushHistory() { backstack.push(NavTarget.PushHistory) } @@ -270,6 +280,26 @@ class PreferencesFlowNode( }, ) } + is NavTarget.PushRules -> { + fileViewerEntryPoint.createNode( + parentNode = this, + buildContext = buildContext, + params = FileViewerEntryPoint.Params( + filename = navTarget.filename, + mimeType = MimeTypes.Json, + content = navTarget.content, + ), + callback = object : FileViewerEntryPoint.Callback { + override fun onDone() { + if (backstack.canPop()) { + backstack.pop() + } else { + navigateUp() + } + } + }, + ) + } is NavTarget.EditDefaultNotificationSetting -> { val callback = object : EditDefaultNotificationSettingNode.Callback { override fun navigateToRoomNotificationSettings(roomId: RoomId) { diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsEvent.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsEvent.kt index e0ad208fc1..34ccba2abe 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsEvent.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsEvent.kt @@ -17,4 +17,6 @@ sealed interface DeveloperSettingsEvent { data object VacuumStores : DeveloperSettingsEvent data class MarkAllRoomsAsRead(val needsConfirmation: Boolean) : DeveloperSettingsEvent data object DismissMarkAllRoomsAsReadConfirmation : DeveloperSettingsEvent + data object OpenPushRules : DeveloperSettingsEvent + data object DismissPushRulesError : DeveloperSettingsEvent } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsNavigator.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsNavigator.kt new file mode 100644 index 0000000000..8201c7a14d --- /dev/null +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsNavigator.kt @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.preferences.impl.developer + +/** + * Navigation performed by the developer settings screen, when data has to be loaded first. + */ +fun interface DeveloperSettingsNavigator { + fun openPushRules(filename: String, content: String) +} diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsNode.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsNode.kt index a8a8c63eed..7a8c3222d1 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsNode.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsNode.kt @@ -28,15 +28,22 @@ import io.element.android.libraries.di.SessionScope class DeveloperSettingsNode( @Assisted buildContext: BuildContext, @Assisted plugins: List, - private val presenter: DeveloperSettingsPresenter, + presenterFactory: DeveloperSettingsPresenter.Factory, private val extraDeveloperOptionsRenderer: ExtraDeveloperOptionsRenderer, -) : Node(buildContext, plugins = plugins) { +) : Node(buildContext, plugins = plugins), + DeveloperSettingsNavigator { interface Callback : Plugin { + fun navigateToPushRules(filename: String, content: String) fun navigateToPushHistory() fun onDone() } private val callback: Callback = callback() + private val presenter = presenterFactory.create(navigator = this) + + override fun openPushRules(filename: String, content: String) { + callback.navigateToPushRules(filename = filename, content = content) + } @Composable override fun View(modifier: Modifier) { diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenter.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenter.kt index c925433608..9b523d1c34 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenter.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenter.kt @@ -17,7 +17,9 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.graphics.toArgb -import dev.zacsweers.metro.Inject +import dev.zacsweers.metro.Assisted +import dev.zacsweers.metro.AssistedFactory +import dev.zacsweers.metro.AssistedInject import io.element.android.features.enterprise.api.EnterpriseService import io.element.android.features.preferences.impl.developer.appsettings.AppDeveloperSettingsState import io.element.android.features.preferences.impl.tasks.ClearCacheUseCase @@ -34,13 +36,15 @@ import io.element.android.libraries.core.meta.BuildMeta import io.element.android.libraries.matrix.api.analytics.GetDatabaseSizesUseCase import io.element.android.libraries.matrix.api.core.DeviceId import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService import kotlinx.collections.immutable.ImmutableMap import kotlinx.collections.immutable.toImmutableMap import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch -@Inject +@AssistedInject class DeveloperSettingsPresenter( + @Assisted private val navigator: DeveloperSettingsNavigator, private val appDeveloperSettingsPresenter: Presenter, private val sessionId: SessionId, private val deviceId: DeviceId, @@ -52,7 +56,13 @@ class DeveloperSettingsPresenter( private val fileSizeFormatter: FileSizeFormatter, private val markAllRoomsAsRead: MarkAllRoomsAsRead, private val buildMeta: BuildMeta, + private val notificationSettingsService: NotificationSettingsService, ) : Presenter { + @AssistedFactory + fun interface Factory { + fun create(navigator: DeveloperSettingsNavigator): DeveloperSettingsPresenter + } + @Composable override fun present(): DeveloperSettingsState { val cacheSize = remember { @@ -67,6 +77,9 @@ class DeveloperSettingsPresenter( val markAllRoomsAsReadAction = remember { mutableStateOf>(AsyncAction.Uninitialized) } + val pushRulesAction = remember { + mutableStateOf>(AsyncAction.Uninitialized) + } var showColorPicker by remember { mutableStateOf(false) } @@ -109,6 +122,10 @@ class DeveloperSettingsPresenter( DeveloperSettingsEvent.DismissMarkAllRoomsAsReadConfirmation -> { markAllRoomsAsReadAction.value = AsyncAction.Uninitialized } + DeveloperSettingsEvent.OpenPushRules -> coroutineScope.openPushRules(pushRulesAction) + DeveloperSettingsEvent.DismissPushRulesError -> { + pushRulesAction.value = AsyncAction.Uninitialized + } } } @@ -119,6 +136,7 @@ class DeveloperSettingsPresenter( databaseSizes = databaseSizes.value, clearCacheAction = clearCacheAction.value, markAllRoomsAsReadAction = markAllRoomsAsReadAction.value, + pushRulesAction = pushRulesAction.value, isEnterpriseBuild = buildMeta.isEnterpriseBuild, showColorPicker = showColorPicker, deviceId = deviceId, @@ -164,4 +182,25 @@ class DeveloperSettingsPresenter( markAllRoomsAsRead().getOrThrow() }.runCatchingUpdatingState(state = markAllRoomsAsReadAction) } + + private fun CoroutineScope.openPushRules(pushRulesAction: MutableState>) = launch { + pushRulesAction.value = AsyncAction.Loading + notificationSettingsService.getRawPushRules() + .onSuccess { content -> + pushRulesAction.value = AsyncAction.Uninitialized + navigator.openPushRules( + filename = pushRulesFilename(), + content = content.orEmpty(), + ) + } + .onFailure { + pushRulesAction.value = AsyncAction.Failure(it) + } + } + + /** + * The user id contains a colon, which is not a valid character for a file name on all the file systems, + * so replace it by an underscore. + */ + private fun pushRulesFilename() = "push_rules${sessionId.value.replace(':', '_')}.json" } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsState.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsState.kt index 3a859f14bb..a4345c6452 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsState.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsState.kt @@ -20,10 +20,13 @@ data class DeveloperSettingsState( val databaseSizes: AsyncData>, val clearCacheAction: AsyncAction, val markAllRoomsAsReadAction: AsyncAction, + val pushRulesAction: AsyncAction, val isEnterpriseBuild: Boolean, val showColorPicker: Boolean, val deviceId: DeviceId, val eventSink: (DeveloperSettingsEvent) -> Unit ) { - val showLoader = clearCacheAction is AsyncAction.Loading || markAllRoomsAsReadAction is AsyncAction.Loading + val showLoader = clearCacheAction is AsyncAction.Loading || + markAllRoomsAsReadAction is AsyncAction.Loading || + pushRulesAction is AsyncAction.Loading } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsStatePreviewParam.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsStatePreviewParam.kt index cbe95d6b20..0a42251b40 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsStatePreviewParam.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsStatePreviewParam.kt @@ -32,6 +32,9 @@ open class DeveloperSettingsStatePreviewParam : PreviewParameterProvider = AsyncAction.Uninitialized, markAllRoomsAsReadAction: AsyncAction = AsyncAction.Uninitialized, + pushRulesAction: AsyncAction = AsyncAction.Uninitialized, isEnterpriseBuild: Boolean = false, showColorPicker: Boolean = false, deviceId: DeviceId = DeviceId("ILAKNDNASDLK"), @@ -49,6 +53,7 @@ fun aDeveloperSettingsState( databaseSizes = AsyncData.Success(persistentMapOf("state_store" to "1.2MB")), clearCacheAction = clearCacheAction, markAllRoomsAsReadAction = markAllRoomsAsReadAction, + pushRulesAction = pushRulesAction, isEnterpriseBuild = isEnterpriseBuild, showColorPicker = showColorPicker, deviceId = deviceId, diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsView.kt index e143f42b0b..8eff49c471 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsView.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsView.kt @@ -23,8 +23,10 @@ import io.element.android.compound.theme.ElementTheme import io.element.android.features.preferences.impl.R import io.element.android.features.preferences.impl.developer.appsettings.AppDeveloperSettingsView import io.element.android.libraries.androidutils.system.copyToClipboard +import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.designsystem.components.ProgressDialog import io.element.android.libraries.designsystem.components.dialogs.ConfirmationDialog +import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog import io.element.android.libraries.designsystem.components.list.ListItemContent import io.element.android.libraries.designsystem.components.preferences.PreferenceCategory import io.element.android.libraries.designsystem.components.preferences.PreferencePage @@ -60,6 +62,12 @@ fun DeveloperSettingsView( onDismiss = { state.eventSink(DeveloperSettingsEvent.DismissMarkAllRoomsAsReadConfirmation) }, ) } + (state.pushRulesAction as? AsyncAction.Failure)?.let { failure -> + ErrorDialog( + content = failure.error.message ?: stringResource(CommonStrings.error_unknown), + onSubmit = { state.eventSink(DeveloperSettingsEvent.DismissPushRulesError) }, + ) + } BackHandler( enabled = !state.showLoader, onBack = onBackClick, @@ -79,7 +87,10 @@ fun DeveloperSettingsView( onOpenShowkase = onOpenShowkase, ) SessionCategory(deviceId = state.deviceId) - NotificationCategory(onPushHistoryClick) + NotificationCategory( + onPushRulesClick = { state.eventSink(DeveloperSettingsEvent.OpenPushRules) }, + onPushHistoryClick = onPushHistoryClick, + ) MarkAllRoomsAsReadCategory(state) if (state.isEnterpriseBuild) { @@ -217,8 +228,17 @@ private fun MarkAllRoomsAsReadCategory(state: DeveloperSettingsState) { } @Composable -private fun NotificationCategory(onPushHistoryClick: () -> Unit) { +private fun NotificationCategory( + onPushRulesClick: () -> Unit, + onPushHistoryClick: () -> Unit, +) { PreferenceCategory(title = stringResource(id = R.string.screen_notification_settings_title)) { + ListItem( + content = { + Text("Push rules") + }, + onClick = onPushRulesClick, + ) ListItem( content = { Text(stringResource(R.string.troubleshoot_notifications_entry_point_push_history_title)) diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/DefaultPreferencesEntryPointTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/DefaultPreferencesEntryPointTest.kt index 963d7846b4..afc3801c88 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/DefaultPreferencesEntryPointTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/DefaultPreferencesEntryPointTest.kt @@ -19,6 +19,7 @@ import io.element.android.features.logout.test.FakeLogoutEntryPoint import io.element.android.features.preferences.api.PreferencesEntryPoint import io.element.android.libraries.matrix.api.core.EventId import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.mediaviewer.test.FakeFileViewerEntryPoint import io.element.android.libraries.troubleshoot.test.FakeNotificationTroubleShootEntryPoint import io.element.android.libraries.troubleshoot.test.FakePushHistoryEntryPoint import io.element.android.tests.testutils.lambda.lambdaError @@ -43,6 +44,7 @@ class DefaultPreferencesEntryPointTest { lockScreenEntryPoint = FakeLockScreenEntryPoint(), notificationTroubleShootEntryPoint = FakeNotificationTroubleShootEntryPoint(), pushHistoryEntryPoint = FakePushHistoryEntryPoint(), + fileViewerEntryPoint = FakeFileViewerEntryPoint(), logoutEntryPoint = FakeLogoutEntryPoint(), openSourceLicensesEntryPoint = FakeOpenSourceLicensesEntryPoint(), accountDeactivationEntryPoint = FakeAccountDeactivationEntryPoint(), diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenterTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenterTest.kt index 753d89da95..66f96e5eb3 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenterTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsPresenterTest.kt @@ -28,10 +28,13 @@ import io.element.android.libraries.matrix.api.analytics.GetDatabaseSizesUseCase import io.element.android.libraries.matrix.api.analytics.SdkStoreSizes import io.element.android.libraries.matrix.api.core.DeviceId import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService import io.element.android.libraries.matrix.test.A_DEVICE_ID import io.element.android.libraries.matrix.test.A_SESSION_ID import io.element.android.libraries.matrix.test.core.aBuildMeta +import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService import io.element.android.tests.testutils.WarmUpRule +import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.lambda.lambdaRecorder import io.element.android.tests.testutils.lambda.value import io.element.android.tests.testutils.test @@ -41,6 +44,9 @@ import kotlinx.coroutines.test.runTest import org.junit.Rule import org.junit.Test +private const val A_PUSH_RULES_CONTENT = "{\"global\":{}}" +private val AN_EXCEPTION = Exception("A failure") + class DeveloperSettingsPresenterTest { @get:Rule val warmUpRule = WarmUpRule() @@ -170,7 +176,53 @@ class DeveloperSettingsPresenterTest { } } + @Test + fun `present - OpenPushRules event navigates to the push rules content`() = runTest { + val openPushRulesLambda = lambdaRecorder { _, _ -> } + val presenter = createDeveloperSettingsPresenter( + navigator = DeveloperSettingsNavigator(openPushRulesLambda), + notificationSettingsService = FakeNotificationSettingsService( + getRawPushRulesResult = { Result.success(A_PUSH_RULES_CONTENT) }, + ), + ) + presenter.test { + val state = awaitItem() + assertThat(state.pushRulesAction).isEqualTo(AsyncAction.Uninitialized) + state.eventSink(DeveloperSettingsEvent.OpenPushRules) + skipItems(1) + awaitItem().also { + assertThat(it.pushRulesAction).isEqualTo(AsyncAction.Uninitialized) + } + openPushRulesLambda.assertions().isCalledOnce().with( + value("push_rules@alice_server.org.json"), + value(A_PUSH_RULES_CONTENT), + ) + } + } + + @Test + fun `present - OpenPushRules event failure can be dismissed`() = runTest { + val presenter = createDeveloperSettingsPresenter( + notificationSettingsService = FakeNotificationSettingsService( + getRawPushRulesResult = { Result.failure(AN_EXCEPTION) }, + ), + ) + presenter.test { + val state = awaitItem() + state.eventSink(DeveloperSettingsEvent.OpenPushRules) + skipItems(1) + awaitItem().also { + assertThat(it.pushRulesAction).isEqualTo(AsyncAction.Failure(AN_EXCEPTION)) + it.eventSink(DeveloperSettingsEvent.DismissPushRulesError) + } + awaitItem().also { + assertThat(it.pushRulesAction).isEqualTo(AsyncAction.Uninitialized) + } + } + } + private fun createDeveloperSettingsPresenter( + navigator: DeveloperSettingsNavigator = DeveloperSettingsNavigator { _, _ -> lambdaError() }, sessionId: SessionId = A_SESSION_ID, deviceId: DeviceId = A_DEVICE_ID, cacheSizeUseCase: FakeComputeCacheSizeUseCase = FakeComputeCacheSizeUseCase(), @@ -180,8 +232,10 @@ class DeveloperSettingsPresenterTest { databaseSizesUseCase: GetDatabaseSizesUseCase = GetDatabaseSizesUseCase { Result.success(SdkStoreSizes(null, null, null, null)) }, markAllRoomsAsRead: FakeMarkAllRoomsAsRead = FakeMarkAllRoomsAsRead(), buildMeta: BuildMeta = aBuildMeta(), + notificationSettingsService: NotificationSettingsService = FakeNotificationSettingsService(), ): DeveloperSettingsPresenter { return DeveloperSettingsPresenter( + navigator = navigator, appDeveloperSettingsPresenter = { anAppDeveloperSettingsState() }, sessionId = sessionId, deviceId = deviceId, @@ -193,6 +247,7 @@ class DeveloperSettingsPresenterTest { fileSizeFormatter = FakeFileSizeFormatter(), markAllRoomsAsRead = markAllRoomsAsRead, buildMeta = buildMeta, + notificationSettingsService = notificationSettingsService, ) } } diff --git a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsViewTest.kt b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsViewTest.kt index f1151bd3e1..fcc69cda91 100644 --- a/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsViewTest.kt +++ b/features/preferences/impl/src/test/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsViewTest.kt @@ -57,6 +57,19 @@ class DeveloperSettingsViewTest : RobolectricTest() { } } + @Config(qualifiers = "h2400dp") + @Test + fun `clicking on push rules emits the expected event`() = runAndroidComposeUiTest { + val eventsRecorder = EventsRecorder() + setDeveloperSettingsView( + state = aDeveloperSettingsState( + eventSink = eventsRecorder + ), + ) + onNodeWithText("Push rules").performScrollTo().performClick() + eventsRecorder.assertSingle(DeveloperSettingsEvent.OpenPushRules) + } + @Config(qualifiers = "h2000dp") @Test fun `clicking on open showkase invokes the expected callback`() = runAndroidComposeUiTest {