Browse Source

Merge pull request #1621 from vector-im/dla/feature/room_notification_settings_ui_update

Room notification settings UI update
pull/1610/head
David Langley 11 months ago committed by GitHub
parent
commit
0e6f7623ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt
  2. 22
      appnav/src/main/kotlin/io/element/android/appnav/room/RoomLoadedFlowNode.kt
  3. 24
      appnav/src/test/kotlin/io/element/android/appnav/RoomFlowNodeTest.kt
  4. 1
      features/preferences/api/build.gradle.kts
  5. 13
      features/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/PreferencesEntryPoint.kt
  6. 10
      features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/DefaultPreferencesEntryPoint.kt
  7. 2
      features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt
  8. 14
      features/roomdetails/api/src/main/kotlin/io/element/android/features/roomdetails/api/RoomDetailsEntryPoint.kt
  9. 1
      features/roomdetails/impl/build.gradle.kts
  10. 26
      features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/DefaultRoomDetailsEntryPoint.kt
  11. 12
      features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/RoomDetailsFlowNode.kt
  12. 11
      features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsNode.kt
  13. 12
      features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsStateProvider.kt
  14. 85
      features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsView.kt
  15. 10
      libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notificationsettings/RustNotificationSettingsService.kt
  16. BIN
      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
  17. BIN
      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
  18. BIN
      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
  19. BIN
      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

16
appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt

@ -197,7 +197,9 @@ class LoggedInFlowNode @AssistedInject constructor( @@ -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( @@ -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( @@ -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<RoomFlowNode>(buildContext, plugins = listOf(inputs, callback))
}
NavTarget.Settings -> {
is NavTarget.Settings -> {
val callback = object : PreferencesEntryPoint.Callback {
override fun onOpenBugReport() {
plugins<Callback>().forEach { it.onOpenBugReport() }
@ -278,7 +284,9 @@ class LoggedInFlowNode @AssistedInject constructor( @@ -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()
}

22
appnav/src/main/kotlin/io/element/android/appnav/room/RoomLoadedFlowNode.kt

@ -75,6 +75,7 @@ class RoomLoadedFlowNode @AssistedInject constructor( @@ -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( @@ -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( @@ -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)
}
}
}

24
appnav/src/test/kotlin/io/element/android/appnav/RoomFlowNodeTest.kt

@ -71,14 +71,22 @@ class RoomFlowNodeTest { @@ -71,14 +71,22 @@ class RoomFlowNodeTest {
var nodeId: String? = null
override fun createNode(
parentNode: Node,
buildContext: BuildContext,
inputs: RoomDetailsEntryPoint.Inputs,
plugins: List<Plugin>
): 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
}
}
}
}
}

1
features/preferences/api/build.gradle.kts

@ -15,6 +15,7 @@ @@ -15,6 +15,7 @@
*/
plugins {
id("io.element.android-library")
id("kotlin-parcelize")
}
android {

13
features/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/PreferencesEntryPoint.kt

@ -16,17 +16,30 @@ @@ -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
}

10
features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/DefaultPreferencesEntryPoint.kt

@ -31,6 +31,11 @@ class DefaultPreferencesEntryPoint @Inject constructor() : PreferencesEntryPoint @@ -31,6 +31,11 @@ class DefaultPreferencesEntryPoint @Inject constructor() : PreferencesEntryPoint
return object : PreferencesEntryPoint.NodeBuilder {
val plugins = ArrayList<Plugin>()
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 @@ -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
}

2
features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/PreferencesFlowNode.kt

@ -53,7 +53,7 @@ class PreferencesFlowNode @AssistedInject constructor( @@ -53,7 +53,7 @@ class PreferencesFlowNode @AssistedInject constructor(
@Assisted plugins: List<Plugin>,
) : BackstackNode<PreferencesFlowNode.NavTarget>(
backstack = BackStack(
initialElement = NavTarget.Root,
initialElement = plugins.filterIsInstance<PreferencesEntryPoint.Params>().first().initialElement.toNavTarget(),
savedStateMap = buildContext.savedStateMap,
),
buildContext = buildContext,

14
features/roomdetails/api/src/main/kotlin/io/element/android/features/roomdetails/api/RoomDetailsEntryPoint.kt

@ -38,7 +38,17 @@ interface RoomDetailsEntryPoint : FeatureEntryPoint { @@ -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<Plugin>): 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
}

1
features/roomdetails/impl/build.gradle.kts

@ -44,6 +44,7 @@ dependencies { @@ -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)

26
features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/DefaultRoomDetailsEntryPoint.kt

@ -29,13 +29,25 @@ import javax.inject.Inject @@ -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<Plugin>
): Node {
return parentNode.createNode<RoomDetailsFlowNode>(buildContext, plugins + inputs)
override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): RoomDetailsEntryPoint.NodeBuilder {
return object : RoomDetailsEntryPoint.NodeBuilder {
val plugins = ArrayList<Plugin>()
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<RoomDetailsFlowNode>(buildContext, plugins)
}
}
}
}

12
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 @@ -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( @@ -47,7 +48,7 @@ class RoomDetailsFlowNode @AssistedInject constructor(
@Assisted plugins: List<Plugin>,
) : BackstackNode<RoomDetailsFlowNode.NavTarget>(
backstack = BackStack(
initialElement = plugins.filterIsInstance<RoomDetailsEntryPoint.Inputs>().first().initialElement.toNavTarget(),
initialElement = plugins.filterIsInstance<RoomDetailsEntryPoint.Params>().first().initialElement.toNavTarget(),
savedStateMap = buildContext.savedStateMap,
),
buildContext = buildContext,
@ -125,8 +126,13 @@ class RoomDetailsFlowNode @AssistedInject constructor( @@ -125,8 +126,13 @@ class RoomDetailsFlowNode @AssistedInject constructor(
}
is NavTarget.RoomNotificationSettings -> {
val plugins = listOf(RoomNotificationSettingsNode.RoomNotificationSettingInput(navTarget.showUserDefinedSettingStyle))
createNode<RoomNotificationSettingsNode>(buildContext, plugins)
val input = RoomNotificationSettingsNode.RoomNotificationSettingInput(navTarget.showUserDefinedSettingStyle)
val callback = object : RoomNotificationSettingsNode.Callback {
override fun openGlobalNotificationSettings() {
plugins<RoomDetailsEntryPoint.Callback>().forEach { it.onOpenGlobalNotificationSettings() }
}
}
createNode<RoomNotificationSettingsNode>(buildContext, listOf(input, callback))
}
is NavTarget.RoomMemberDetails -> {

11
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 @@ -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( @@ -42,8 +43,15 @@ class RoomNotificationSettingsNode @AssistedInject constructor(
data class RoomNotificationSettingInput(
val showUserDefinedSettingStyle: Boolean
) : NodeInputs
interface Callback : Plugin {
fun openGlobalNotificationSettings()
}
private val inputs = inputs<RoomNotificationSettingInput>()
private val callbacks = plugins<Callback>()
private fun openGlobalNotificationSettings() {
callbacks.forEach { it.openGlobalNotificationSettings() }
}
private val presenter = presenterFactory.create(inputs.showUserDefinedSettingStyle)
init {
@ -60,6 +68,7 @@ class RoomNotificationSettingsNode @AssistedInject constructor( @@ -60,6 +68,7 @@ class RoomNotificationSettingsNode @AssistedInject constructor(
RoomNotificationSettingsView(
state = state,
modifier = modifier,
onShowGlobalNotifications = this::openGlobalNotificationSettings,
onBackPressed = this::navigateUp,
)
}

12
features/roomdetails/impl/src/main/kotlin/io/element/android/features/roomdetails/impl/notificationsettings/RoomNotificationSettingsStateProvider.kt

@ -37,5 +37,17 @@ internal class RoomNotificationSettingsStateProvider : PreviewParameterProvider< @@ -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 = { },
),
)
}

85
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 @@ -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 @@ -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 @@ -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( @@ -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))
},
)
},)
}
}

10
libraries/matrix/impl/src/main/kotlin/io/element/android/libraries/matrix/impl/notificationsettings/RustNotificationSettingsService.kt

@ -28,6 +28,8 @@ import kotlinx.coroutines.flow.asSharedFlow @@ -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( @@ -63,7 +65,13 @@ class RustNotificationSettingsService(
isOneToOne: Boolean
): Result<Unit> = 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}")
}
}
}

BIN
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 (Stored with Git LFS)

Binary file not shown.

BIN
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 (Stored with Git LFS)

Binary file not shown.

BIN
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 (Stored with Git LFS)

Binary file not shown.

BIN
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 (Stored with Git LFS)

Binary file not shown.
Loading…
Cancel
Save