diff --git a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt index 891301532c..8d2edd0843 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt @@ -197,7 +197,9 @@ class LoggedInFlowNode @AssistedInject constructor( ) : NavTarget @Parcelize - data object Settings : NavTarget + data class Settings( + val initialElement: PreferencesEntryPoint.InitialTarget = PreferencesEntryPoint.InitialTarget.Root + ) : NavTarget @Parcelize data object CreateRoom : NavTarget @@ -227,7 +229,7 @@ class LoggedInFlowNode @AssistedInject constructor( } override fun onSettingsClicked() { - backstack.push(NavTarget.Settings) + backstack.push(NavTarget.Settings()) } override fun onCreateRoomClicked() { @@ -260,11 +262,15 @@ class LoggedInFlowNode @AssistedInject constructor( override fun onForwardedToSingleRoom(roomId: RoomId) { coroutineScope.launch { attachRoom(roomId) } } + + override fun onOpenGlobalNotificationSettings() { + backstack.push(NavTarget.Settings(PreferencesEntryPoint.InitialTarget.NotificationSettings)) + } } val inputs = RoomFlowNode.Inputs(roomId = navTarget.roomId, initialElement = navTarget.initialElement) createNode(buildContext, plugins = listOf(inputs, callback)) } - NavTarget.Settings -> { + is NavTarget.Settings -> { val callback = object : PreferencesEntryPoint.Callback { override fun onOpenBugReport() { plugins().forEach { it.onOpenBugReport() } @@ -278,7 +284,9 @@ class LoggedInFlowNode @AssistedInject constructor( backstack.push(NavTarget.Room(roomId, initialElement = RoomLoadedFlowNode.NavTarget.RoomNotificationSettings)) } } - preferencesEntryPoint.nodeBuilder(this, buildContext) + val inputs = PreferencesEntryPoint.Params(navTarget.initialElement) + return preferencesEntryPoint.nodeBuilder(this, buildContext) + .params(inputs) .callback(callback) .build() } diff --git a/appnav/src/main/kotlin/io/element/android/appnav/room/RoomLoadedFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/room/RoomLoadedFlowNode.kt index fa583645b2..613ed650c8 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/room/RoomLoadedFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/room/RoomLoadedFlowNode.kt @@ -75,6 +75,7 @@ class RoomLoadedFlowNode @AssistedInject constructor( interface Callback : Plugin { fun onForwardedToSingleRoom(roomId: RoomId) + fun onOpenGlobalNotificationSettings() } data class Inputs( @@ -128,6 +129,18 @@ class RoomLoadedFlowNode @AssistedInject constructor( } } + private fun createRoomDetailsNode(buildContext: BuildContext, initialTarget: RoomDetailsEntryPoint.InitialTarget): Node { + val callback = object : RoomDetailsEntryPoint.Callback { + override fun onOpenGlobalNotificationSettings() { + callbacks.forEach { it.onOpenGlobalNotificationSettings() } + } + } + return roomDetailsEntryPoint.nodeBuilder(this, buildContext) + .params(RoomDetailsEntryPoint.Params(initialTarget)) + .callback(callback) + .build() + } + override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { return when (navTarget) { NavTarget.Messages -> { @@ -147,16 +160,13 @@ class RoomLoadedFlowNode @AssistedInject constructor( messagesEntryPoint.createNode(this, buildContext, callback) } NavTarget.RoomDetails -> { - val inputs = RoomDetailsEntryPoint.Inputs(RoomDetailsEntryPoint.InitialTarget.RoomDetails) - roomDetailsEntryPoint.createNode(this, buildContext, inputs, emptyList()) + createRoomDetailsNode(buildContext, RoomDetailsEntryPoint.InitialTarget.RoomDetails) } is NavTarget.RoomMemberDetails -> { - val inputs = RoomDetailsEntryPoint.Inputs(RoomDetailsEntryPoint.InitialTarget.RoomMemberDetails(navTarget.userId)) - roomDetailsEntryPoint.createNode(this, buildContext, inputs, emptyList()) + createRoomDetailsNode(buildContext, RoomDetailsEntryPoint.InitialTarget.RoomMemberDetails(navTarget.userId)) } NavTarget.RoomNotificationSettings -> { - val inputs = RoomDetailsEntryPoint.Inputs(RoomDetailsEntryPoint.InitialTarget.RoomNotificationSettings) - roomDetailsEntryPoint.createNode(this, buildContext, inputs, emptyList()) + createRoomDetailsNode(buildContext, RoomDetailsEntryPoint.InitialTarget.RoomNotificationSettings) } } } diff --git a/appnav/src/test/kotlin/io/element/android/appnav/RoomFlowNodeTest.kt b/appnav/src/test/kotlin/io/element/android/appnav/RoomFlowNodeTest.kt index a25e4d8134..fd5de85b1d 100644 --- a/appnav/src/test/kotlin/io/element/android/appnav/RoomFlowNodeTest.kt +++ b/appnav/src/test/kotlin/io/element/android/appnav/RoomFlowNodeTest.kt @@ -71,14 +71,22 @@ class RoomFlowNodeTest { var nodeId: String? = null - override fun createNode( - parentNode: Node, - buildContext: BuildContext, - inputs: RoomDetailsEntryPoint.Inputs, - plugins: List - ): Node { - return node(buildContext) {}.also { - nodeId = it.id + override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): RoomDetailsEntryPoint.NodeBuilder { + return object : RoomDetailsEntryPoint.NodeBuilder { + + override fun params(params: RoomDetailsEntryPoint.Params): RoomDetailsEntryPoint.NodeBuilder { + return this + } + + override fun callback(callback: RoomDetailsEntryPoint.Callback): RoomDetailsEntryPoint.NodeBuilder { + return this + } + + override fun build(): Node { + return node(buildContext) {}.also { + nodeId = it.id + } + } } } } diff --git a/features/preferences/api/build.gradle.kts b/features/preferences/api/build.gradle.kts index c20fe9aabb..0278385ab3 100644 --- a/features/preferences/api/build.gradle.kts +++ b/features/preferences/api/build.gradle.kts @@ -15,6 +15,7 @@ */ plugins { id("io.element.android-library") + id("kotlin-parcelize") } android { diff --git a/features/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/PreferencesEntryPoint.kt b/features/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/PreferencesEntryPoint.kt index 50a605efe4..a0d2b8e057 100644 --- a/features/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/PreferencesEntryPoint.kt +++ b/features/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/PreferencesEntryPoint.kt @@ -16,17 +16,30 @@ package io.element.android.features.preferences.api +import android.os.Parcelable 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 +import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.matrix.api.core.RoomId +import kotlinx.parcelize.Parcelize interface PreferencesEntryPoint : FeatureEntryPoint { + sealed interface InitialTarget : Parcelable { + @Parcelize + data object Root : InitialTarget + @Parcelize + data object NotificationSettings : InitialTarget + } + + data class Params(val initialElement: InitialTarget) : NodeInputs fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder interface NodeBuilder { + + fun params(params: Params): NodeBuilder fun callback(callback: Callback): NodeBuilder fun build(): Node } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/DefaultPreferencesEntryPoint.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/DefaultPreferencesEntryPoint.kt index aa286394dc..e551d9d8dc 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/DefaultPreferencesEntryPoint.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/DefaultPreferencesEntryPoint.kt @@ -31,6 +31,11 @@ class DefaultPreferencesEntryPoint @Inject constructor() : PreferencesEntryPoint return object : PreferencesEntryPoint.NodeBuilder { val plugins = ArrayList() + override fun params(params: PreferencesEntryPoint.Params): PreferencesEntryPoint.NodeBuilder { + plugins += params + return this + } + override fun callback(callback: PreferencesEntryPoint.Callback): PreferencesEntryPoint.NodeBuilder { plugins += callback return this @@ -42,3 +47,8 @@ class DefaultPreferencesEntryPoint @Inject constructor() : PreferencesEntryPoint } } } + +internal fun PreferencesEntryPoint.InitialTarget.toNavTarget() = when (this) { + is PreferencesEntryPoint.InitialTarget.Root -> PreferencesFlowNode.NavTarget.Root + is PreferencesEntryPoint.InitialTarget.NotificationSettings -> PreferencesFlowNode.NavTarget.NotificationSettings +} 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 8d77757527..0fcf04d1df 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 @@ -53,7 +53,7 @@ class PreferencesFlowNode @AssistedInject constructor( @Assisted plugins: List, ) : BackstackNode( backstack = BackStack( - initialElement = NavTarget.Root, + initialElement = plugins.filterIsInstance().first().initialElement.toNavTarget(), savedStateMap = buildContext.savedStateMap, ), buildContext = buildContext, diff --git a/features/roomdetails/api/src/main/kotlin/io/element/android/features/roomdetails/api/RoomDetailsEntryPoint.kt b/features/roomdetails/api/src/main/kotlin/io/element/android/features/roomdetails/api/RoomDetailsEntryPoint.kt index ed1e6f5c5a..0aaac324da 100644 --- a/features/roomdetails/api/src/main/kotlin/io/element/android/features/roomdetails/api/RoomDetailsEntryPoint.kt +++ b/features/roomdetails/api/src/main/kotlin/io/element/android/features/roomdetails/api/RoomDetailsEntryPoint.kt @@ -38,7 +38,17 @@ interface RoomDetailsEntryPoint : FeatureEntryPoint { data object RoomNotificationSettings : InitialTarget } - data class Inputs(val initialElement: InitialTarget) : NodeInputs + data class Params(val initialElement: InitialTarget) : NodeInputs - fun createNode(parentNode: Node, buildContext: BuildContext, inputs: Inputs, plugins: List): Node + interface Callback : Plugin { + fun onOpenGlobalNotificationSettings() + } + + interface NodeBuilder { + fun params(params: Params): NodeBuilder + fun callback(callback: Callback): NodeBuilder + fun build(): Node + } + + fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder } diff --git a/features/roomdetails/impl/build.gradle.kts b/features/roomdetails/impl/build.gradle.kts index 3bf38d4fa7..a2fdfa18c1 100644 --- a/features/roomdetails/impl/build.gradle.kts +++ b/features/roomdetails/impl/build.gradle.kts @@ -44,6 +44,7 @@ dependencies { implementation(projects.libraries.mediaupload.api) implementation(projects.libraries.featureflag.api) implementation(projects.libraries.permissions.api) + implementation(projects.libraries.preferences.api) api(projects.features.roomdetails.api) api(projects.libraries.usersearch.api) api(projects.services.apperror.api) diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/DefaultRoomDetailsEntryPoint.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/DefaultRoomDetailsEntryPoint.kt index 8cd6cb54d6..108ef088f0 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/DefaultRoomDetailsEntryPoint.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/DefaultRoomDetailsEntryPoint.kt @@ -29,13 +29,25 @@ import javax.inject.Inject @ContributesBinding(AppScope::class) class DefaultRoomDetailsEntryPoint @Inject constructor() : RoomDetailsEntryPoint { - override fun createNode( - parentNode: Node, - buildContext: BuildContext, - inputs: RoomDetailsEntryPoint.Inputs, - plugins: List - ): Node { - return parentNode.createNode(buildContext, plugins + inputs) + + override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): RoomDetailsEntryPoint.NodeBuilder { + return object : RoomDetailsEntryPoint.NodeBuilder { + val plugins = ArrayList() + + override fun params(params: RoomDetailsEntryPoint.Params): RoomDetailsEntryPoint.NodeBuilder { + plugins += params + return this + } + + override fun callback(callback: RoomDetailsEntryPoint.Callback): RoomDetailsEntryPoint.NodeBuilder { + plugins += callback + return this + } + + override fun build(): Node { + return parentNode.createNode(buildContext, plugins) + } + } } } 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 6945ebb0ca..dba31ab223 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 @@ -23,6 +23,7 @@ import com.bumble.appyx.core.composable.Children import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.core.plugin.plugins import com.bumble.appyx.navmodel.backstack.BackStack import com.bumble.appyx.navmodel.backstack.operation.push import dagger.assisted.Assisted @@ -47,7 +48,7 @@ class RoomDetailsFlowNode @AssistedInject constructor( @Assisted plugins: List, ) : BackstackNode( backstack = BackStack( - initialElement = plugins.filterIsInstance().first().initialElement.toNavTarget(), + initialElement = plugins.filterIsInstance().first().initialElement.toNavTarget(), savedStateMap = buildContext.savedStateMap, ), buildContext = buildContext, @@ -125,8 +126,13 @@ class RoomDetailsFlowNode @AssistedInject constructor( } is NavTarget.RoomNotificationSettings -> { - val plugins = listOf(RoomNotificationSettingsNode.RoomNotificationSettingInput(navTarget.showUserDefinedSettingStyle)) - createNode(buildContext, plugins) + val input = RoomNotificationSettingsNode.RoomNotificationSettingInput(navTarget.showUserDefinedSettingStyle) + val callback = object : RoomNotificationSettingsNode.Callback { + override fun openGlobalNotificationSettings() { + plugins().forEach { it.onOpenGlobalNotificationSettings() } + } + } + createNode(buildContext, listOf(input, callback)) } is NavTarget.RoomMemberDetails -> { diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsNode.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsNode.kt index 5972314ea4..4f3265ea1f 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsNode.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsNode.kt @@ -22,6 +22,7 @@ import com.bumble.appyx.core.lifecycle.subscribe import com.bumble.appyx.core.modality.BuildContext import com.bumble.appyx.core.node.Node import com.bumble.appyx.core.plugin.Plugin +import com.bumble.appyx.core.plugin.plugins import dagger.assisted.Assisted import dagger.assisted.AssistedInject import im.vector.app.features.analytics.plan.MobileScreen @@ -42,8 +43,15 @@ class RoomNotificationSettingsNode @AssistedInject constructor( data class RoomNotificationSettingInput( val showUserDefinedSettingStyle: Boolean ) : NodeInputs - + interface Callback : Plugin { + fun openGlobalNotificationSettings() + } private val inputs = inputs() + private val callbacks = plugins() + + private fun openGlobalNotificationSettings() { + callbacks.forEach { it.openGlobalNotificationSettings() } + } private val presenter = presenterFactory.create(inputs.showUserDefinedSettingStyle) init { @@ -60,6 +68,7 @@ class RoomNotificationSettingsNode @AssistedInject constructor( RoomNotificationSettingsView( state = state, modifier = modifier, + onShowGlobalNotifications = this::openGlobalNotificationSettings, onBackPressed = this::navigateUp, ) } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsStateProvider.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsStateProvider.kt index a7faa52210..0024abbb35 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsStateProvider.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsStateProvider.kt @@ -37,5 +37,17 @@ internal class RoomNotificationSettingsStateProvider : PreviewParameterProvider< restoreDefaultAction = Async.Uninitialized, eventSink = { }, ), + RoomNotificationSettingsState( + roomName = "Room 1", + Async.Success(RoomNotificationSettings( + mode = RoomNotificationMode.MUTE, + isDefault = false)), + pendingRoomNotificationMode = null, + pendingSetDefault = null, + defaultRoomNotificationMode = RoomNotificationMode.ALL_MESSAGES, + setNotificationSettingAction = Async.Uninitialized, + restoreDefaultAction = Async.Uninitialized, + eventSink = { }, + ), ) } diff --git a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsView.kt b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsView.kt index 43e736137e..898268359c 100644 --- a/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsView.kt +++ b/features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsView.kt @@ -21,10 +21,14 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.text.ClickableText import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.unit.dp import io.element.android.features.roomdetails.impl.R @@ -34,9 +38,9 @@ import io.element.android.libraries.designsystem.components.ProgressDialog import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.components.preferences.PreferenceCategory import io.element.android.libraries.designsystem.components.preferences.PreferenceSwitch -import io.element.android.libraries.designsystem.components.preferences.PreferenceText import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.PreviewsDayNight +import io.element.android.libraries.designsystem.text.buildAnnotatedStringWithStyledPart import io.element.android.libraries.designsystem.theme.aliasScreenTitle import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.theme.components.Text @@ -50,6 +54,7 @@ import io.element.android.libraries.ui.strings.CommonStrings fun RoomNotificationSettingsView( state: RoomNotificationSettingsState, modifier: Modifier = Modifier, + onShowGlobalNotifications: () -> Unit = {}, onBackPressed: () -> Unit = {}, ) { if(state.showUserDefinedSettingStyle) { @@ -88,40 +93,62 @@ private fun RoomSpecificNotificationSettingsView( .consumeWindowInsets(padding), verticalArrangement = Arrangement.spacedBy(16.dp), ) { - val subtitle = when (state.defaultRoomNotificationMode) { - RoomNotificationMode.ALL_MESSAGES -> stringResource(id = R.string.screen_room_notification_settings_mode_all_messages) - RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY -> stringResource(id = R.string.screen_room_notification_settings_mode_mentions_and_keywords) - RoomNotificationMode.MUTE -> stringResource(id = CommonStrings.common_mute) - null -> "" - } - val roomNotificationSettings = state.roomNotificationSettings.dataOrNull() - - PreferenceCategory(title = stringResource(id = R.string.screen_room_notification_settings_custom_settings_title)) { - PreferenceSwitch( - isChecked = state.displayIsDefault.orTrue(), - onCheckedChange = { - state.eventSink(RoomNotificationSettingsEvents.SetNotificationMode(it)) - }, - title = "Match default setting", - subtitle = subtitle, - enabled = roomNotificationSettings != null - ) - - PreferenceText( - title = stringResource(id = R.string.screen_room_notification_settings_allow_custom), - subtitle = stringResource(id = R.string.screen_room_notification_settings_allow_custom_footnote), - enabled = !state.displayIsDefault.orTrue(), - ) - - if (roomNotificationSettings != null && state.displayNotificationMode != null) { + PreferenceSwitch( + isChecked = !state.displayIsDefault.orTrue(), + onCheckedChange = { + state.eventSink(RoomNotificationSettingsEvents.SetNotificationMode(!it)) + }, + title = stringResource(id = R.string.screen_room_notification_settings_allow_custom), + subtitle = stringResource(id = R.string.screen_room_notification_settings_allow_custom_footnote), + enabled = roomNotificationSettings != null + ) + if (state.displayIsDefault.orTrue()) { + PreferenceCategory(title = stringResource(id = R.string.screen_room_notification_settings_default_setting_title)) { + val text = buildAnnotatedStringWithStyledPart( + R.string.screen_room_notification_settings_default_setting_footnote, + R.string.screen_room_notification_settings_default_setting_footnote_content_link, + color = Color.Unspecified, + underline = false, + bold = true, + ) + ClickableText( + text = text, + onClick = { + onShowGlobalNotifications() + }, + modifier = Modifier + .padding(start = 16.dp, bottom = 16.dp, end = 16.dp), + style = ElementTheme.typography.fontBodyMdRegular + .copy( + color = MaterialTheme.colorScheme.secondary, + textAlign = TextAlign.Center, + ) + ) + if(state.defaultRoomNotificationMode != null){ + val defaultModeTitle = when (state.defaultRoomNotificationMode) { + RoomNotificationMode.ALL_MESSAGES -> stringResource(id = R.string.screen_room_notification_settings_mode_all_messages) + RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY -> { + stringResource(id = R.string.screen_room_notification_settings_mode_mentions_and_keywords) + } + RoomNotificationMode.MUTE -> stringResource(id = CommonStrings.common_mute) + } + RoomNotificationSettingsOption( + roomNotificationSettingsItem = RoomNotificationSettingsItem(state.defaultRoomNotificationMode, defaultModeTitle), + isSelected = true, + onOptionSelected = { }, + enabled = true + ) + } + } + } else { + PreferenceCategory(title = stringResource(id = R.string.screen_room_notification_settings_custom_settings_title)) { RoomNotificationSettingsOptions( selected = state.displayNotificationMode, enabled = !state.displayIsDefault.orTrue(), onOptionSelected = { state.eventSink(RoomNotificationSettingsEvents.RoomNotificationModeChanged(it.mode)) - }, - ) + },) } } diff --git a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notificationsettings/RustNotificationSettingsService.kt b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notificationsettings/RustNotificationSettingsService.kt index df5c4d577f..42b2662a6d 100644 --- a/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notificationsettings/RustNotificationSettingsService.kt +++ b/libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notificationsettings/RustNotificationSettingsService.kt @@ -28,6 +28,8 @@ import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.withContext import org.matrix.rustcomponents.sdk.NotificationSettings import org.matrix.rustcomponents.sdk.NotificationSettingsDelegate +import org.matrix.rustcomponents.sdk.NotificationSettingsException +import timber.log.Timber class RustNotificationSettingsService( private val notificationSettings: NotificationSettings, @@ -63,7 +65,13 @@ class RustNotificationSettingsService( isOneToOne: Boolean ): Result = withContext(dispatchers.io) { runCatching { - notificationSettings.setDefaultRoomNotificationMode(isEncrypted, isOneToOne, mode.let(RoomNotificationSettingsMapper::mapMode)) + try { + notificationSettings.setDefaultRoomNotificationMode(isEncrypted, isOneToOne, mode.let(RoomNotificationSettingsMapper::mapMode)) + } catch (exception: NotificationSettingsException.RuleNotFound) { + // `setDefaultRoomNotificationMode` updates multiple rules including unstable rules (e.g. the polls push rules defined in the MSC3930) + // since production home servers may not have these rules yet, we drop the RuleNotFound error + Timber.w("Unable to find the rule: ${exception.ruleId}") + } } } diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_null_RoomNotificationSettings-D-4_4_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_null_RoomNotificationSettings-D-4_4_null_0,NEXUS_5,1.0,en].png index 88554d0d72..7a08009659 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_null_RoomNotificationSettings-D-4_4_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_null_RoomNotificationSettings-D-4_4_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f34dde086bbd14cc5cfeb0003d6bfd0d3868ecbc497956dc17794e69f6773279 -size 40070 +oid sha256:3f2fc33febab98860da9b6591c4ae33dc9ba4fa28365520e4fcb08f8bfaf6ff8 +size 33828 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_null_RoomNotificationSettings-D-4_4_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_null_RoomNotificationSettings-D-4_4_null_1,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..383adaff52 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_null_RoomNotificationSettings-D-4_4_null_1,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9d99786d84445bc42f7e7f7e414f973a04ba6684780f69eb1cfe60a09ff3ec6e +size 38017 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_null_RoomNotificationSettings-N-4_5_null_0,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_null_RoomNotificationSettings-N-4_5_null_0,NEXUS_5,1.0,en].png index 9adff83203..d59805dfbd 100644 --- a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_null_RoomNotificationSettings-N-4_5_null_0,NEXUS_5,1.0,en].png +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_null_RoomNotificationSettings-N-4_5_null_0,NEXUS_5,1.0,en].png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ef0545d55a8a78af5d8286fc590998c973cee986a3f6aff91850cf277d47a5e5 -size 36415 +oid sha256:0cf8d93229fd5d8034dc7e2f68f9868fc42515c538098c89d4dddca814827bc3 +size 31448 diff --git a/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_null_RoomNotificationSettings-N-4_5_null_1,NEXUS_5,1.0,en].png b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_null_RoomNotificationSettings-N-4_5_null_1,NEXUS_5,1.0,en].png new file mode 100644 index 0000000000..9b7a1f3917 --- /dev/null +++ b/tests/uitests/src/test/snapshots/images/ui_S_t[f.roomdetails.impl.notificationsettings_null_RoomNotificationSettings-N-4_5_null_1,NEXUS_5,1.0,en].png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:13c5007d3a97734dca40a88f2312e59d09a8906deb71d16c0611df7dd25a6391 +size 35124