Add notification setting to enable/disable being notified for room invite (#1944)

This commit is contained in:
Benoit Marty 2023-12-04 13:07:21 +01:00 committed by Benoit Marty
parent 0573dda874
commit 66ac1e271f
10 changed files with 75 additions and 6 deletions

View file

@ -17,11 +17,11 @@
package io.element.android.features.preferences.impl.notifications
sealed interface NotificationSettingsEvents {
data object RefreshSystemNotificationsEnabled : NotificationSettingsEvents
data class SetNotificationsEnabled(val enabled: Boolean) : NotificationSettingsEvents
data class SetAtRoomNotificationsEnabled(val enabled: Boolean) : NotificationSettingsEvents
data class SetCallNotificationsEnabled(val enabled: Boolean) : NotificationSettingsEvents
data class SetInviteForMeNotificationsEnabled(val enabled: Boolean) : NotificationSettingsEvents
data object FixConfigurationMismatch : NotificationSettingsEvents
data object ClearConfigurationMismatchError : NotificationSettingsEvents
data object ClearNotificationChangeError : NotificationSettingsEvents

View file

@ -76,6 +76,9 @@ class NotificationSettingsPresenter @Inject constructor(
is NotificationSettingsEvents.SetCallNotificationsEnabled -> {
localCoroutineScope.setCallNotificationsEnabled(event.enabled, changeNotificationSettingAction)
}
is NotificationSettingsEvents.SetInviteForMeNotificationsEnabled -> {
localCoroutineScope.setInviteForMeNotificationsEnabled(event.enabled, changeNotificationSettingAction)
}
is NotificationSettingsEvents.SetNotificationsEnabled -> localCoroutineScope.setNotificationsEnabled(userPushStore, event.enabled)
NotificationSettingsEvents.ClearConfigurationMismatchError -> {
matrixSettings.value = NotificationSettingsState.MatrixSettings.Invalid(fixFailed = false)
@ -123,10 +126,12 @@ class NotificationSettingsPresenter @Inject constructor(
val callNotificationsEnabled = notificationSettingsService.isCallEnabled().getOrThrow()
val atRoomNotificationsEnabled = notificationSettingsService.isRoomMentionEnabled().getOrThrow()
val inviteForMeNotificationsEnabled = notificationSettingsService.isInviteForMeEnabled().getOrThrow()
target.value = NotificationSettingsState.MatrixSettings.Valid(
atRoomNotificationsEnabled = atRoomNotificationsEnabled,
callNotificationsEnabled = callNotificationsEnabled,
inviteForMeNotificationsEnabled = inviteForMeNotificationsEnabled,
defaultGroupNotificationMode = encryptedGroupDefaultMode,
defaultOneToOneNotificationMode = encryptedOneToOneDefaultMode,
)
@ -175,6 +180,12 @@ class NotificationSettingsPresenter @Inject constructor(
}.runCatchingUpdatingState(action)
}
private fun CoroutineScope.setInviteForMeNotificationsEnabled(enabled: Boolean, action: MutableState<Async<Unit>>) = launch {
suspend {
notificationSettingsService.setInviteForMeEnabled(enabled).getOrThrow()
}.runCatchingUpdatingState(action)
}
private fun CoroutineScope.setNotificationsEnabled(userPushStore: UserPushStore, enabled: Boolean) = launch {
userPushStore.setNotificationEnabledForDevice(enabled)
}

View file

@ -32,6 +32,7 @@ data class NotificationSettingsState(
data class Valid(
val atRoomNotificationsEnabled: Boolean,
val callNotificationsEnabled: Boolean,
val inviteForMeNotificationsEnabled: Boolean,
val defaultGroupNotificationMode: RoomNotificationMode?,
val defaultOneToOneNotificationMode: RoomNotificationMode?,
) : MatrixSettings

View file

@ -35,6 +35,7 @@ fun aNotificationSettingsState(
matrixSettings = NotificationSettingsState.MatrixSettings.Valid(
atRoomNotificationsEnabled = true,
callNotificationsEnabled = true,
inviteForMeNotificationsEnabled = true,
defaultGroupNotificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY,
defaultOneToOneNotificationMode = RoomNotificationMode.ALL_MESSAGES,
),

View file

@ -77,6 +77,7 @@ fun NotificationSettingsView(
onMentionNotificationsChanged = { state.eventSink(NotificationSettingsEvents.SetAtRoomNotificationsEnabled(it)) },
// TODO We are removing the call notification toggle until support for call notifications has been added
// onCallsNotificationsChanged = { state.eventSink(NotificationSettingsEvents.SetCallNotificationsEnabled(it)) },
onInviteForMeNotificationsChanged = { state.eventSink(NotificationSettingsEvents.SetInviteForMeNotificationsEnabled(it)) },
)
}
AsyncView(
@ -98,6 +99,7 @@ private fun NotificationSettingsContentView(
onMentionNotificationsChanged: (Boolean) -> Unit,
// TODO We are removing the call notification toggle until support for call notifications has been added
// onCallsNotificationsChanged: (Boolean) -> Unit,
onInviteForMeNotificationsChanged: (Boolean) -> Unit,
modifier: Modifier = Modifier,
) {
val context = LocalContext.current
@ -147,8 +149,8 @@ private fun NotificationSettingsContentView(
onCheckedChange = onMentionNotificationsChanged
)
}
// TODO We are removing the call notification toggle until support for call notifications has been added
// PreferenceCategory(title = stringResource(id = CommonStrings.screen_notification_settings_additional_settings_section_title)) {
PreferenceCategory(title = stringResource(id = R.string.screen_notification_settings_additional_settings_section_title)) {
// TODO We are removing the call notification toggle until support for call notifications has been added
// PreferenceSwitch(
// modifier = Modifier,
// title = stringResource(id = CommonStrings.screen_notification_settings_calls_label),
@ -156,7 +158,14 @@ private fun NotificationSettingsContentView(
// switchAlignment = Alignment.Top,
// onCheckedChange = onCallsNotificationsChanged
// )
// }
PreferenceSwitch(
modifier = Modifier,
title = stringResource(id = R.string.screen_notification_settings_invite_for_me_label),
isChecked = matrixSettings.inviteForMeNotificationsEnabled,
switchAlignment = Alignment.Top,
onCheckedChange = onInviteForMeNotificationsChanged
)
}
}
}

View file

@ -29,6 +29,7 @@ If you proceed, some of your settings may change."</string>
<string name="screen_notification_settings_enable_notifications">"Enable notifications on this device"</string>
<string name="screen_notification_settings_failed_fixing_configuration">"The configuration has not been corrected, please try again."</string>
<string name="screen_notification_settings_group_chats">"Group chats"</string>
<string name="screen_notification_settings_invite_for_me_label">"Invitations"</string>
<string name="screen_notification_settings_mentions_only_disclaimer">"Your homeserver does not support this option in encrypted rooms, you may not get notified in some rooms."</string>
<string name="screen_notification_settings_mentions_section_title">"Mentions"</string>
<string name="screen_notification_settings_mode_all">"All"</string>

View file

@ -50,6 +50,7 @@ class NotificationSettingsPresenterTests {
val valid = loadedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
assertThat(valid?.atRoomNotificationsEnabled).isFalse()
assertThat(valid?.callNotificationsEnabled).isFalse()
assertThat(valid?.inviteForMeNotificationsEnabled).isFalse()
assertThat(valid?.defaultGroupNotificationMode).isEqualTo(RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY)
assertThat(valid?.defaultOneToOneNotificationMode).isEqualTo(RoomNotificationMode.ALL_MESSAGES)
cancelAndIgnoreRemainingEvents()
@ -166,6 +167,28 @@ class NotificationSettingsPresenterTests {
}
}
@Test
fun `present - set invite for me notifications enabled`() = runTest {
val presenter = createNotificationSettingsPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val loadedState = consumeItemsUntilPredicate {
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)?.inviteForMeNotificationsEnabled == false
}.last()
val validMatrixState = loadedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
Truth.assertThat(validMatrixState?.inviteForMeNotificationsEnabled).isFalse()
loadedState.eventSink(NotificationSettingsEvents.SetInviteForMeNotificationsEnabled(true))
val updatedState = consumeItemsUntilPredicate {
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)?.inviteForMeNotificationsEnabled == true
}.last()
val updatedMatrixState = updatedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
Truth.assertThat(updatedMatrixState?.inviteForMeNotificationsEnabled).isTrue()
cancelAndIgnoreRemainingEvents()
}
}
@Test
fun `present - set atRoom notifications enabled`() = runTest {
val presenter = createNotificationSettingsPresenter()

View file

@ -38,5 +38,7 @@ interface NotificationSettingsService {
suspend fun setRoomMentionEnabled(enabled: Boolean): Result<Unit>
suspend fun isCallEnabled(): Result<Boolean>
suspend fun setCallEnabled(enabled: Boolean): Result<Unit>
suspend fun isInviteForMeEnabled(): Result<Boolean>
suspend fun setInviteForMeEnabled(enabled: Boolean): Result<Unit>
suspend fun getRoomsWithUserDefinedRules(): Result<List<String>>
}

View file

@ -124,6 +124,18 @@ class RustNotificationSettingsService(
}
}
override suspend fun isInviteForMeEnabled(): Result<Boolean> = withContext(dispatchers.io) {
runCatching {
notificationSettings.isInviteForMeEnabled()
}
}
override suspend fun setInviteForMeEnabled(enabled: Boolean): Result<Unit> = withContext(dispatchers.io) {
runCatching {
notificationSettings.setInviteForMeEnabled(enabled)
}
}
override suspend fun getRoomsWithUserDefinedRules(): Result<List<String>> =
runCatching {
notificationSettings.getRoomsWithUserDefinedRules(enabled = true)

View file

@ -41,6 +41,7 @@ class FakeNotificationSettingsService(
private var roomNotificationMode: RoomNotificationMode = initialRoomMode
private var roomNotificationModeIsDefault: Boolean = initialRoomModeIsDefault
private var callNotificationsEnabled = false
private var inviteNotificationsEnabled = false
private var atRoomNotificationsEnabled = false
private var setNotificationModeError: Throwable? = null
private var restoreDefaultNotificationModeError: Throwable? = null
@ -52,7 +53,7 @@ class FakeNotificationSettingsService(
override suspend fun getRoomNotificationSettings(roomId: RoomId, isEncrypted: Boolean, isOneToOne: Boolean): Result<RoomNotificationSettings> {
return Result.success(
RoomNotificationSettings(
mode = if(roomNotificationModeIsDefault) defaultEncryptedGroupRoomNotificationMode else roomNotificationMode,
mode = if (roomNotificationModeIsDefault) defaultEncryptedGroupRoomNotificationMode else roomNotificationMode,
isDefault = roomNotificationModeIsDefault
)
)
@ -149,6 +150,15 @@ class FakeNotificationSettingsService(
return Result.success(Unit)
}
override suspend fun isInviteForMeEnabled(): Result<Boolean> {
return Result.success(inviteNotificationsEnabled)
}
override suspend fun setInviteForMeEnabled(enabled: Boolean): Result<Unit> {
inviteNotificationsEnabled = enabled
return Result.success(Unit)
}
override suspend fun getRoomsWithUserDefinedRules(): Result<List<String>> {
return Result.success(if (roomNotificationModeIsDefault) listOf() else listOf(A_ROOM_ID.value))
}
@ -168,5 +178,4 @@ class FakeNotificationSettingsService(
fun givenSetDefaultNotificationModeError(throwable: Throwable?) {
setDefaultNotificationModeError = throwable
}
}