Add tests, mocks and lint

This commit is contained in:
David Langley 2023-09-13 12:44:22 +01:00
parent 7d95feadc1
commit ccd684ea40
24 changed files with 523 additions and 96 deletions

View file

@ -41,6 +41,7 @@ dependencies {
implementation(projects.libraries.featureflag.ui) implementation(projects.libraries.featureflag.ui)
implementation(projects.libraries.network) implementation(projects.libraries.network)
implementation(projects.libraries.pushstore.api) implementation(projects.libraries.pushstore.api)
implementation(projects.libraries.pushstore.test)
implementation(projects.libraries.testtags) implementation(projects.libraries.testtags)
implementation(projects.libraries.uiStrings) implementation(projects.libraries.uiStrings)
implementation(projects.features.rageshake.api) implementation(projects.features.rageshake.api)

View file

@ -41,7 +41,6 @@ import io.element.android.libraries.architecture.BackstackNode
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
import io.element.android.libraries.architecture.createNode import io.element.android.libraries.architecture.createNode
import io.element.android.libraries.di.SessionScope import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.matrix.api.core.UserId
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
@ContributesNode(SessionScope::class) @ContributesNode(SessionScope::class)

View file

@ -16,16 +16,12 @@
package io.element.android.features.preferences.impl.notifications package io.element.android.features.preferences.impl.notifications
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
sealed interface NotificationSettingsEvents { sealed interface NotificationSettingsEvents {
data object RefreshSystemNotificationsEnabled : NotificationSettingsEvents data object RefreshSystemNotificationsEnabled : NotificationSettingsEvents
data class SetNotificationsEnabled(val enabled: Boolean) : NotificationSettingsEvents data class SetNotificationsEnabled(val enabled: Boolean) : NotificationSettingsEvents
data class SetAtRoomNotificationsEnabled(val enabled: Boolean) : NotificationSettingsEvents data class SetAtRoomNotificationsEnabled(val enabled: Boolean) : NotificationSettingsEvents
data class SetCallNotificationsEnabled(val enabled: Boolean) : NotificationSettingsEvents data class SetCallNotificationsEnabled(val enabled: Boolean) : NotificationSettingsEvents
data class SetDefaultGroupNotificationMode(val mode: RoomNotificationMode) : NotificationSettingsEvents
data class SetDefaultOneToOneNotificationMode(val mode: RoomNotificationMode) : NotificationSettingsEvents
data object FixConfigurationMismatch : NotificationSettingsEvents data object FixConfigurationMismatch : NotificationSettingsEvents
data object ClearConfigurationMismatchError : NotificationSettingsEvents data object ClearConfigurationMismatchError : NotificationSettingsEvents
} }

View file

@ -26,7 +26,6 @@ import dagger.assisted.Assisted
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import io.element.android.anvilannotations.ContributesNode import io.element.android.anvilannotations.ContributesNode
import io.element.android.libraries.di.SessionScope import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.matrix.api.core.UserId
@ContributesNode(SessionScope::class) @ContributesNode(SessionScope::class)
class NotificationSettingsNode @AssistedInject constructor( class NotificationSettingsNode @AssistedInject constructor(

View file

@ -56,8 +56,8 @@ class NotificationSettingsPresenter @Inject constructor(
.getNotificationEnabledForDevice() .getNotificationEnabledForDevice()
.collectAsState(initial = false) .collectAsState(initial = false)
val matrixSettings: MutableState<NotificationSettingsState.MatrixNotificationSettings> = remember { val matrixSettings: MutableState<NotificationSettingsState.MatrixSettings> = remember {
mutableStateOf(NotificationSettingsState.MatrixNotificationSettings.Uninitialized) mutableStateOf(NotificationSettingsState.MatrixSettings.Uninitialized)
} }
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
@ -69,18 +69,20 @@ class NotificationSettingsPresenter @Inject constructor(
when (event) { when (event) {
is NotificationSettingsEvents.SetAtRoomNotificationsEnabled -> localCoroutineScope.setAtRoomNotificationsEnabled(event.enabled) is NotificationSettingsEvents.SetAtRoomNotificationsEnabled -> localCoroutineScope.setAtRoomNotificationsEnabled(event.enabled)
is NotificationSettingsEvents.SetCallNotificationsEnabled -> localCoroutineScope.setCallNotificationsEnabled(event.enabled) is NotificationSettingsEvents.SetCallNotificationsEnabled -> localCoroutineScope.setCallNotificationsEnabled(event.enabled)
is NotificationSettingsEvents.SetDefaultGroupNotificationMode -> localCoroutineScope.setDefaultGroupNotificationMode(event.mode)
is NotificationSettingsEvents.SetDefaultOneToOneNotificationMode -> localCoroutineScope.setDefaultOneToOneNotificationMode(event.mode)
is NotificationSettingsEvents.SetNotificationsEnabled -> localCoroutineScope.setNotificationsEnabled(userPushStore, event.enabled) is NotificationSettingsEvents.SetNotificationsEnabled -> localCoroutineScope.setNotificationsEnabled(userPushStore, event.enabled)
NotificationSettingsEvents.ClearConfigurationMismatchError -> matrixSettings.value = NotificationSettingsState.MatrixNotificationSettings.InvalidNotificationSettingsState(fixFailed = false) NotificationSettingsEvents.ClearConfigurationMismatchError -> {
matrixSettings.value = NotificationSettingsState.MatrixSettings.Invalid(fixFailed = false)
}
NotificationSettingsEvents.FixConfigurationMismatch -> localCoroutineScope.fixConfigurationMismatch(matrixSettings) NotificationSettingsEvents.FixConfigurationMismatch -> localCoroutineScope.fixConfigurationMismatch(matrixSettings)
NotificationSettingsEvents.RefreshSystemNotificationsEnabled -> systemNotificationsEnabled.value = systemNotificationsEnabledProvider.notificationsEnabled() NotificationSettingsEvents.RefreshSystemNotificationsEnabled -> {
systemNotificationsEnabled.value = systemNotificationsEnabledProvider.notificationsEnabled()
}
} }
} }
return NotificationSettingsState( return NotificationSettingsState(
matrixNotificationSettings = matrixSettings.value, matrixSettings = matrixSettings.value,
appNotificationSettings = NotificationSettingsState.AppNotificationSettings( appSettings = NotificationSettingsState.AppSettings(
systemNotificationsEnabled = systemNotificationsEnabled.value, systemNotificationsEnabled = systemNotificationsEnabled.value,
appNotificationsEnabled = appNotificationsEnabled.value appNotificationsEnabled = appNotificationsEnabled.value
), ),
@ -89,7 +91,7 @@ class NotificationSettingsPresenter @Inject constructor(
} }
@OptIn(FlowPreview::class) @OptIn(FlowPreview::class)
private fun CoroutineScope.observeNotificationSettings(target: MutableState<NotificationSettingsState.MatrixNotificationSettings>) { private fun CoroutineScope.observeNotificationSettings(target: MutableState<NotificationSettingsState.MatrixSettings>) {
notificationSettingsService.notificationSettingsChangeFlow notificationSettingsService.notificationSettingsChangeFlow
.debounce(0.5.seconds) .debounce(0.5.seconds)
.onEach { .onEach {
@ -98,7 +100,7 @@ class NotificationSettingsPresenter @Inject constructor(
.launchIn(this) .launchIn(this)
} }
private fun CoroutineScope.fetchSettings(target: MutableState<NotificationSettingsState.MatrixNotificationSettings>) = launch { private fun CoroutineScope.fetchSettings(target: MutableState<NotificationSettingsState.MatrixSettings>) = launch {
val groupDefaultMode = notificationSettingsService.getDefaultRoomNotificationMode(isEncrypted = false, isOneToOne = false).getOrThrow() val groupDefaultMode = notificationSettingsService.getDefaultRoomNotificationMode(isEncrypted = false, isOneToOne = false).getOrThrow()
val encryptedGroupDefaultMode = notificationSettingsService.getDefaultRoomNotificationMode(isEncrypted = true, isOneToOne = false).getOrThrow() val encryptedGroupDefaultMode = notificationSettingsService.getDefaultRoomNotificationMode(isEncrypted = true, isOneToOne = false).getOrThrow()
@ -106,14 +108,14 @@ class NotificationSettingsPresenter @Inject constructor(
val encryptedOneToOneDefaultMode = notificationSettingsService.getDefaultRoomNotificationMode(isEncrypted = true, isOneToOne = true).getOrThrow() val encryptedOneToOneDefaultMode = notificationSettingsService.getDefaultRoomNotificationMode(isEncrypted = true, isOneToOne = true).getOrThrow()
if(groupDefaultMode != encryptedGroupDefaultMode || oneToOneDefaultMode != encryptedOneToOneDefaultMode) { if(groupDefaultMode != encryptedGroupDefaultMode || oneToOneDefaultMode != encryptedOneToOneDefaultMode) {
target.value = NotificationSettingsState.MatrixNotificationSettings.InvalidNotificationSettingsState(fixFailed = false) target.value = NotificationSettingsState.MatrixSettings.Invalid(fixFailed = false)
return@launch return@launch
} }
val callNotificationsEnabled = notificationSettingsService.isCallEnabled().getOrThrow() val callNotificationsEnabled = notificationSettingsService.isCallEnabled().getOrThrow()
val atRoomNotificationsEnabled = notificationSettingsService.isRoomMentionEnabled().getOrThrow() val atRoomNotificationsEnabled = notificationSettingsService.isRoomMentionEnabled().getOrThrow()
target.value = NotificationSettingsState.MatrixNotificationSettings.ValidNotificationSettingsState( target.value = NotificationSettingsState.MatrixSettings.Valid(
atRoomNotificationsEnabled = atRoomNotificationsEnabled, atRoomNotificationsEnabled = atRoomNotificationsEnabled,
callNotificationsEnabled = callNotificationsEnabled, callNotificationsEnabled = callNotificationsEnabled,
defaultGroupNotificationMode = encryptedGroupDefaultMode, defaultGroupNotificationMode = encryptedGroupDefaultMode,
@ -121,7 +123,7 @@ class NotificationSettingsPresenter @Inject constructor(
) )
} }
private fun CoroutineScope.fixConfigurationMismatch(target: MutableState<NotificationSettingsState.MatrixNotificationSettings>) = launch { private fun CoroutineScope.fixConfigurationMismatch(target: MutableState<NotificationSettingsState.MatrixSettings>) = launch {
runCatching { runCatching {
val groupDefaultMode = notificationSettingsService.getDefaultRoomNotificationMode(isEncrypted = false, isOneToOne = false).getOrThrow() val groupDefaultMode = notificationSettingsService.getDefaultRoomNotificationMode(isEncrypted = false, isOneToOne = false).getOrThrow()
val encryptedGroupDefaultMode = notificationSettingsService.getDefaultRoomNotificationMode(isEncrypted = true, isOneToOne = false).getOrThrow() val encryptedGroupDefaultMode = notificationSettingsService.getDefaultRoomNotificationMode(isEncrypted = true, isOneToOne = false).getOrThrow()
@ -147,7 +149,7 @@ class NotificationSettingsPresenter @Inject constructor(
}.fold( }.fold(
onSuccess = {}, onSuccess = {},
onFailure = { onFailure = {
target.value = NotificationSettingsState.MatrixNotificationSettings.InvalidNotificationSettingsState(fixFailed = true) target.value = NotificationSettingsState.MatrixSettings.Invalid(fixFailed = true)
} }
) )
} }
@ -160,27 +162,7 @@ class NotificationSettingsPresenter @Inject constructor(
notificationSettingsService.setCallEnabled(enabled) notificationSettingsService.setCallEnabled(enabled)
} }
private fun CoroutineScope.setDefaultGroupNotificationMode(mode: RoomNotificationMode) = launch {
notificationSettingsService.setDefaultRoomNotificationMode(false, mode, false)
notificationSettingsService.setDefaultRoomNotificationMode(true, mode, false)
}
private fun CoroutineScope.setDefaultOneToOneNotificationMode(mode: RoomNotificationMode) = launch {
notificationSettingsService.setDefaultRoomNotificationMode(false, mode, true)
notificationSettingsService.setDefaultRoomNotificationMode(true, mode, true)
}
private fun CoroutineScope.setNotificationsEnabled(userPushStore: UserPushStore, enabled: Boolean) = launch { private fun CoroutineScope.setNotificationsEnabled(userPushStore: UserPushStore, enabled: Boolean) = launch {
userPushStore.setNotificationEnabledForDevice(enabled) userPushStore.setNotificationEnabledForDevice(enabled)
} }
private fun CoroutineScope.getDefaultRoomNotificationMode(isOneToOne: Boolean, defaultRoomNotificationMode: MutableState<RoomNotificationMode?>) = launch {
val encryptedMode = notificationSettingsService.getDefaultRoomNotificationMode(true, isOneToOne).getOrThrow()
val unencryptedMode = notificationSettingsService.getDefaultRoomNotificationMode(false, isOneToOne).getOrThrow()
if (encryptedMode == unencryptedMode) {
defaultRoomNotificationMode.value
} else {
defaultRoomNotificationMode.value = null
}
}
} }

View file

@ -21,25 +21,25 @@ import io.element.android.libraries.matrix.api.room.RoomNotificationMode
@Immutable @Immutable
data class NotificationSettingsState( data class NotificationSettingsState(
val matrixNotificationSettings: MatrixNotificationSettings, val matrixSettings: MatrixSettings,
val appNotificationSettings: AppNotificationSettings, val appSettings: AppSettings,
val eventSink: (NotificationSettingsEvents) -> Unit, val eventSink: (NotificationSettingsEvents) -> Unit,
) { ) {
sealed interface MatrixNotificationSettings { sealed interface MatrixSettings {
data object Uninitialized : MatrixNotificationSettings data object Uninitialized : MatrixSettings
data class ValidNotificationSettingsState( data class Valid(
val atRoomNotificationsEnabled: Boolean, val atRoomNotificationsEnabled: Boolean,
val callNotificationsEnabled: Boolean, val callNotificationsEnabled: Boolean,
val defaultGroupNotificationMode: RoomNotificationMode?, val defaultGroupNotificationMode: RoomNotificationMode?,
val defaultOneToOneNotificationMode: RoomNotificationMode?, val defaultOneToOneNotificationMode: RoomNotificationMode?,
) : MatrixNotificationSettings ) : MatrixSettings
data class InvalidNotificationSettingsState( data class Invalid(
val fixFailed: Boolean val fixFailed: Boolean
) : MatrixNotificationSettings ) : MatrixSettings
} }
data class AppNotificationSettings( data class AppSettings(
val systemNotificationsEnabled: Boolean, val systemNotificationsEnabled: Boolean,
val appNotificationsEnabled: Boolean, val appNotificationsEnabled: Boolean,
) )

View file

@ -27,13 +27,13 @@ open class NotificationSettingsStateProvider : PreviewParameterProvider<Notifica
} }
fun aNotificationSettingsState() = NotificationSettingsState( fun aNotificationSettingsState() = NotificationSettingsState(
matrixNotificationSettings = NotificationSettingsState.MatrixNotificationSettings.ValidNotificationSettingsState( matrixSettings = NotificationSettingsState.MatrixSettings.Valid(
atRoomNotificationsEnabled = true, atRoomNotificationsEnabled = true,
callNotificationsEnabled = true, callNotificationsEnabled = true,
defaultGroupNotificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, defaultGroupNotificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY,
defaultOneToOneNotificationMode = RoomNotificationMode.ALL_MESSAGES, defaultOneToOneNotificationMode = RoomNotificationMode.ALL_MESSAGES,
), ),
appNotificationSettings = NotificationSettingsState.AppNotificationSettings( appSettings = NotificationSettingsState.AppSettings(
systemNotificationsEnabled = false, systemNotificationsEnabled = false,
appNotificationsEnabled = true, appNotificationsEnabled = true,
), ),

View file

@ -74,23 +74,21 @@ fun NotificationSettingsView(
title = stringResource(id = CommonStrings.screen_notification_settings_title) title = stringResource(id = CommonStrings.screen_notification_settings_title)
) { ) {
when (state.matrixNotificationSettings) { when (state.matrixSettings) {
is NotificationSettingsState.MatrixNotificationSettings.InvalidNotificationSettingsState -> InvalidNotificationSettingsView( is NotificationSettingsState.MatrixSettings.Invalid -> InvalidNotificationSettingsView(
showError = state.matrixNotificationSettings.fixFailed, showError = state.matrixSettings.fixFailed,
onContinueClicked = { state.eventSink(NotificationSettingsEvents.FixConfigurationMismatch) }, onContinueClicked = { state.eventSink(NotificationSettingsEvents.FixConfigurationMismatch) },
onDismissError = { state.eventSink(NotificationSettingsEvents.ClearConfigurationMismatchError) }, onDismissError = { state.eventSink(NotificationSettingsEvents.ClearConfigurationMismatchError) },
modifier = modifier,
) )
NotificationSettingsState.MatrixNotificationSettings.Uninitialized -> return@PreferenceView NotificationSettingsState.MatrixSettings.Uninitialized -> return@PreferenceView
is NotificationSettingsState.MatrixNotificationSettings.ValidNotificationSettingsState -> NotificationSettingsContentView( is NotificationSettingsState.MatrixSettings.Valid -> NotificationSettingsContentView(
matrixSettings = state.matrixNotificationSettings, matrixSettings = state.matrixSettings,
systemSettings = state.appNotificationSettings, systemSettings = state.appSettings,
onNotificationsEnabledChanged = { state.eventSink(NotificationSettingsEvents.SetNotificationsEnabled(it))}, onNotificationsEnabledChanged = { state.eventSink(NotificationSettingsEvents.SetNotificationsEnabled(it))},
onGroupChatsClicked = { onOpenEditDefault(false) }, onGroupChatsClicked = { onOpenEditDefault(false) },
onDirectChatsClicked = { onOpenEditDefault(true) }, onDirectChatsClicked = { onOpenEditDefault(true) },
onMentionNotificationsChanged = { state.eventSink(NotificationSettingsEvents.SetAtRoomNotificationsEnabled(it)) }, onMentionNotificationsChanged = { state.eventSink(NotificationSettingsEvents.SetAtRoomNotificationsEnabled(it)) },
onCallsNotificationsChanged = { state.eventSink(NotificationSettingsEvents.SetCallNotificationsEnabled(it)) }, onCallsNotificationsChanged = { state.eventSink(NotificationSettingsEvents.SetCallNotificationsEnabled(it)) },
modifier = modifier,
) )
} }
} }
@ -98,8 +96,8 @@ fun NotificationSettingsView(
@Composable @Composable
private fun NotificationSettingsContentView( private fun NotificationSettingsContentView(
matrixSettings: NotificationSettingsState.MatrixNotificationSettings.ValidNotificationSettingsState, matrixSettings: NotificationSettingsState.MatrixSettings.Valid,
systemSettings: NotificationSettingsState.AppNotificationSettings, systemSettings: NotificationSettingsState.AppSettings,
onNotificationsEnabledChanged: (Boolean) -> Unit, onNotificationsEnabledChanged: (Boolean) -> Unit,
onGroupChatsClicked: () -> Unit, onGroupChatsClicked: () -> Unit,
onDirectChatsClicked: () -> Unit, onDirectChatsClicked: () -> Unit,
@ -252,16 +250,16 @@ private fun ContentToPreview(state: NotificationSettingsState) {
@Preview @Preview
@Composable @Composable
internal fun InvalidNotificationSettingsViewightPreview(@PreviewParameter(NotificationSettingsStateProvider::class) state: NotificationSettingsState) = internal fun InvalidNotificationSettingsViewightPreview() =
ElementPreviewLight { InvalidNotificationSettingsContentToPreview(state) } ElementPreviewLight { InvalidNotificationSettingsContentToPreview() }
@Preview @Preview
@Composable @Composable
internal fun InvalidNotificationSettingsViewDarkPreview(@PreviewParameter(NotificationSettingsStateProvider::class) state: NotificationSettingsState) = internal fun InvalidNotificationSettingsViewDarkPreview() =
ElementPreviewDark { InvalidNotificationSettingsContentToPreview(state) } ElementPreviewDark { InvalidNotificationSettingsContentToPreview() }
@Composable @Composable
private fun InvalidNotificationSettingsContentToPreview(state: NotificationSettingsState) { private fun InvalidNotificationSettingsContentToPreview() {
InvalidNotificationSettingsView( InvalidNotificationSettingsView(
showError = false, showError = false,
onContinueClicked = {}, onContinueClicked = {},

View file

@ -26,7 +26,6 @@ import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.room.RoomNotificationMode
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope

View file

@ -55,7 +55,7 @@ fun EditDefaultNotificationSettingView(
PreferenceCategory(title = stringResource(id = categoryTitle)) { PreferenceCategory(title = stringResource(id = categoryTitle)) {
if (state.mode != null) { if (state.mode != null) {
Column(modifier = modifier.selectableGroup()) { Column(modifier = Modifier.selectableGroup()) {
validModes.forEach { item -> validModes.forEach { item ->
DefaultNotificationSettingOption( DefaultNotificationSettingOption(
mode = item, mode = item,

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.preferences.impl.notifications
import app.cash.molecule.RecompositionMode
import app.cash.molecule.moleculeFlow
import app.cash.turbine.test
import com.google.common.truth.Truth
import io.element.android.features.preferences.impl.notifications.edit.EditDefaultNotificationSettingPresenter
import io.element.android.features.preferences.impl.notifications.edit.EditDefaultNotificationSettingStateEvents
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService
import io.element.android.tests.testutils.consumeItemsUntilPredicate
import kotlinx.coroutines.test.runTest
import org.junit.Test
class EditDefaultNotificationSettingsPresenterTests {
@Test
fun `present - ensures initial state is correct`() = runTest {
val notificationSettingsService = FakeNotificationSettingsService()
val presenter = EditDefaultNotificationSettingPresenter(notificationSettingsService = notificationSettingsService, isOneToOne = false)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
Truth.assertThat(initialState.mode).isNull()
Truth.assertThat(initialState.isOneToOne).isFalse()
val loadedState = consumeItemsUntilPredicate {
it.mode == RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY
}.last()
Truth.assertThat(loadedState.mode).isEqualTo(RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY)
}
}
@Test
fun `present - edit default notification setting`() = runTest {
val notificationSettingsService = FakeNotificationSettingsService()
val presenter = EditDefaultNotificationSettingPresenter(notificationSettingsService = notificationSettingsService, isOneToOne = false)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
awaitItem().eventSink(EditDefaultNotificationSettingStateEvents.SetNotificationMode(RoomNotificationMode.ALL_MESSAGES))
val loadedState = consumeItemsUntilPredicate {
it.mode == RoomNotificationMode.ALL_MESSAGES
}.last()
Truth.assertThat(loadedState.mode).isEqualTo(RoomNotificationMode.ALL_MESSAGES)
}
}
}

View file

@ -0,0 +1,23 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.preferences.impl.notifications
class FakeSystemNotificationsEnabledProvider: SystemNotificationsEnabledProvider {
override fun notificationsEnabled(): Boolean {
return true
}
}

View file

@ -0,0 +1,201 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.features.preferences.impl.notifications
import app.cash.molecule.RecompositionMode
import app.cash.molecule.moleculeFlow
import app.cash.turbine.test
import com.element.android.libraries.pushstore.test.userpushstore.FakeUserPushStoreFactory
import com.google.common.truth.Truth
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService
import io.element.android.tests.testutils.consumeItemsUntilPredicate
import kotlinx.coroutines.test.runTest
import org.junit.Test
import kotlin.time.Duration.Companion.milliseconds
class NotificationSettingsPresenterTests {
@Test
fun `present - ensures initial state is correct`() = runTest {
val presenter = aNotificationPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
Truth.assertThat(initialState.appSettings.appNotificationsEnabled).isFalse()
Truth.assertThat(initialState.appSettings.systemNotificationsEnabled).isTrue()
Truth.assertThat(initialState.matrixSettings).isEqualTo(NotificationSettingsState.MatrixSettings.Uninitialized)
val loadedState = consumeItemsUntilPredicate {
it.matrixSettings is NotificationSettingsState.MatrixSettings.Valid
}.last()
Truth.assertThat(loadedState.appSettings.appNotificationsEnabled).isTrue()
Truth.assertThat(loadedState.appSettings.systemNotificationsEnabled).isTrue()
val valid = loadedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
Truth.assertThat(valid?.atRoomNotificationsEnabled).isFalse()
Truth.assertThat(valid?.callNotificationsEnabled).isFalse()
Truth.assertThat(valid?.defaultGroupNotificationMode).isEqualTo(RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY)
Truth.assertThat(valid?.defaultOneToOneNotificationMode).isEqualTo(RoomNotificationMode.ALL_MESSAGES)
cancelAndIgnoreRemainingEvents()
}
}
@Test
fun `present - default group notification mode changed`() = runTest {
val notificationSettingsService = FakeNotificationSettingsService()
val presenter = aNotificationPresenter(notificationSettingsService)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
notificationSettingsService.setDefaultRoomNotificationMode(isEncrypted = true, isOneToOne = false, mode = RoomNotificationMode.ALL_MESSAGES)
notificationSettingsService.setDefaultRoomNotificationMode(isEncrypted = false, isOneToOne = false, mode = RoomNotificationMode.ALL_MESSAGES)
val updatedState = consumeItemsUntilPredicate {
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)
?.defaultGroupNotificationMode == RoomNotificationMode.ALL_MESSAGES
}.last()
val valid = updatedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
Truth.assertThat(valid?.defaultGroupNotificationMode).isEqualTo(RoomNotificationMode.ALL_MESSAGES)
}
}
@Test
fun `present - notification settings mismatched`() = runTest {
val notificationSettingsService = FakeNotificationSettingsService()
val presenter = aNotificationPresenter(notificationSettingsService)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
notificationSettingsService.setDefaultRoomNotificationMode(
isEncrypted = true,
isOneToOne = false,
mode = RoomNotificationMode.ALL_MESSAGES
)
notificationSettingsService.setDefaultRoomNotificationMode(
isEncrypted = false,
isOneToOne = false,
mode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY
)
val updatedState = consumeItemsUntilPredicate {
it.matrixSettings is NotificationSettingsState.MatrixSettings.Invalid
}.last()
Truth.assertThat(updatedState.matrixSettings).isEqualTo(NotificationSettingsState.MatrixSettings.Invalid(fixFailed = false))
}
}
@Test
fun `present - fix notification settings mismatched`() = runTest {
// Start with a mismatched configuration
val notificationSettingsService = FakeNotificationSettingsService(
initialEncryptedGroupDefaultMode = RoomNotificationMode.ALL_MESSAGES,
initialGroupDefaultMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY,
initialEncryptedOneToOneDefaultMode = RoomNotificationMode.ALL_MESSAGES,
initialOneToOneDefaultMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY
)
val presenter = aNotificationPresenter(notificationSettingsService)
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
initialState.eventSink(NotificationSettingsEvents.FixConfigurationMismatch)
val fixedState = consumeItemsUntilPredicate(timeout = 2000.milliseconds) {
it.matrixSettings is NotificationSettingsState.MatrixSettings.Valid
}.last()
val fixedMatrixState = fixedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
Truth.assertThat(fixedMatrixState?.defaultGroupNotificationMode).isEqualTo(RoomNotificationMode.ALL_MESSAGES)
}
}
@Test
fun `present - set notifications enabled`() = runTest {
val presenter = aNotificationPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val loadedState = consumeItemsUntilPredicate {
it.matrixSettings is NotificationSettingsState.MatrixSettings.Valid
}.last()
Truth.assertThat(loadedState.appSettings.appNotificationsEnabled).isTrue()
loadedState.eventSink(NotificationSettingsEvents.SetNotificationsEnabled(false))
val updatedState = consumeItemsUntilPredicate {
!it.appSettings.appNotificationsEnabled
}.last()
Truth.assertThat(updatedState.appSettings.appNotificationsEnabled).isFalse()
cancelAndIgnoreRemainingEvents()
}
}
@Test
fun `present - set call notifications enabled`() = runTest {
val presenter = aNotificationPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val loadedState = consumeItemsUntilPredicate {
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)?.callNotificationsEnabled == false
}.last()
val validMatrixState = loadedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
Truth.assertThat(validMatrixState?.callNotificationsEnabled).isFalse()
loadedState.eventSink(NotificationSettingsEvents.SetCallNotificationsEnabled(true))
val updatedState = consumeItemsUntilPredicate {
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)?.callNotificationsEnabled == true
}.last()
val updatedMatrixState = updatedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
Truth.assertThat(updatedMatrixState?.callNotificationsEnabled).isTrue()
cancelAndIgnoreRemainingEvents()
}
}
@Test
fun `present - set atRoom notifications enabled`() = runTest {
val presenter = aNotificationPresenter()
moleculeFlow(RecompositionMode.Immediate) {
presenter.present()
}.test {
val loadedState = consumeItemsUntilPredicate {
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)?.atRoomNotificationsEnabled == false
}.last()
val validMatrixState = loadedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
Truth.assertThat(validMatrixState?.atRoomNotificationsEnabled).isFalse()
loadedState.eventSink(NotificationSettingsEvents.SetAtRoomNotificationsEnabled(true))
val updatedState = consumeItemsUntilPredicate {
(it.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid)?.atRoomNotificationsEnabled == true
}.last()
val updatedMatrixState = updatedState.matrixSettings as? NotificationSettingsState.MatrixSettings.Valid
Truth.assertThat(updatedMatrixState?.atRoomNotificationsEnabled).isTrue()
cancelAndIgnoreRemainingEvents()
}
}
private fun aNotificationPresenter(
notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService()
) : NotificationSettingsPresenter {
val matrixClient = FakeMatrixClient(notificationSettingsService = notificationSettingsService)
return NotificationSettingsPresenter(
notificationSettingsService = notificationSettingsService,
userPushStoreFactory = FakeUserPushStoreFactory(),
matrixClient = matrixClient,
systemNotificationsEnabledProvider = FakeSystemNotificationsEnabledProvider(),
)
}
}

View file

@ -24,6 +24,7 @@ import io.element.android.features.logout.impl.DefaultLogoutPreferencePresenter
import io.element.android.libraries.architecture.Async import io.element.android.libraries.architecture.Async
import io.element.android.libraries.core.meta.BuildType import io.element.android.libraries.core.meta.BuildType
import io.element.android.libraries.designsystem.utils.SnackbarDispatcher import io.element.android.libraries.designsystem.utils.SnackbarDispatcher
import io.element.android.libraries.featureflag.test.FakeFeatureFlagService
import io.element.android.libraries.matrix.api.user.MatrixUser import io.element.android.libraries.matrix.api.user.MatrixUser
import io.element.android.libraries.matrix.test.AN_AVATAR_URL import io.element.android.libraries.matrix.test.AN_AVATAR_URL
import io.element.android.libraries.matrix.test.A_USER_NAME import io.element.android.libraries.matrix.test.A_USER_NAME
@ -53,6 +54,7 @@ class PreferencesRootPresenterTest {
BuildType.DEBUG, BuildType.DEBUG,
FakeVersionFormatter(), FakeVersionFormatter(),
SnackbarDispatcher(), SnackbarDispatcher(),
FakeFeatureFlagService()
) )
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
presenter.present() presenter.present()

View file

@ -35,7 +35,6 @@ import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds

View file

@ -385,7 +385,7 @@ class RoomDetailsPresenterTests {
@Test @Test
fun `present - mute room notifications`() = runTest { fun `present - mute room notifications`() = runTest {
val leaveRoomPresenter = LeaveRoomPresenterFake() val leaveRoomPresenter = LeaveRoomPresenterFake()
val notificationSettingsService = FakeNotificationSettingsService(initialMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY) val notificationSettingsService = FakeNotificationSettingsService(initialRoomMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY)
val room = aMatrixRoom(notificationSettingsService = notificationSettingsService) val room = aMatrixRoom(notificationSettingsService = notificationSettingsService)
val presenter = aRoomDetailsPresenter(room, leaveRoomPresenter, testCoroutineDispatchers(), notificationSettingsService) val presenter = aRoomDetailsPresenter(room, leaveRoomPresenter, testCoroutineDispatchers(), notificationSettingsService)
moleculeFlow(RecompositionMode.Immediate) { moleculeFlow(RecompositionMode.Immediate) {
@ -404,8 +404,8 @@ class RoomDetailsPresenterTests {
fun `present - unmute room notifications`() = runTest { fun `present - unmute room notifications`() = runTest {
val leaveRoomPresenter = LeaveRoomPresenterFake() val leaveRoomPresenter = LeaveRoomPresenterFake()
val notificationSettingsService = FakeNotificationSettingsService( val notificationSettingsService = FakeNotificationSettingsService(
initialMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY, initialRoomMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY,
initialDefaultMode = RoomNotificationMode.ALL_MESSAGES initialEncryptedGroupDefaultMode = RoomNotificationMode.ALL_MESSAGES
) )
val room = aMatrixRoom(notificationSettingsService = notificationSettingsService) val room = aMatrixRoom(notificationSettingsService = notificationSettingsService)
val presenter = aRoomDetailsPresenter(room, leaveRoomPresenter, testCoroutineDispatchers(), notificationSettingsService) val presenter = aRoomDetailsPresenter(room, leaveRoomPresenter, testCoroutineDispatchers(), notificationSettingsService)

View file

@ -24,7 +24,6 @@ import io.element.android.features.roomdetails.aMatrixRoom
import io.element.android.features.roomdetails.impl.notificationsettings.RoomNotificationSettingsEvents import io.element.android.features.roomdetails.impl.notificationsettings.RoomNotificationSettingsEvents
import io.element.android.features.roomdetails.impl.notificationsettings.RoomNotificationSettingsPresenter import io.element.android.features.roomdetails.impl.notificationsettings.RoomNotificationSettingsPresenter
import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.room.RoomNotificationMode
import io.element.android.libraries.matrix.test.A_ROOM_NOTIFICATION_MODE
import io.element.android.tests.testutils.consumeItemsUntilPredicate import io.element.android.tests.testutils.consumeItemsUntilPredicate
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
@ -67,9 +66,9 @@ class RoomNotificationSettingsPresenterTests {
initialState.eventSink(RoomNotificationSettingsEvents.RoomNotificationModeChanged(RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY)) initialState.eventSink(RoomNotificationSettingsEvents.RoomNotificationModeChanged(RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY))
initialState.eventSink(RoomNotificationSettingsEvents.SetNotificationMode(true)) initialState.eventSink(RoomNotificationSettingsEvents.SetNotificationMode(true))
val defaultState = consumeItemsUntilPredicate { val defaultState = consumeItemsUntilPredicate {
it.roomNotificationSettings?.mode == A_ROOM_NOTIFICATION_MODE it.roomNotificationSettings?.mode == RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY
}.last() }.last()
Truth.assertThat(defaultState.roomNotificationSettings?.mode).isEqualTo(A_ROOM_NOTIFICATION_MODE) Truth.assertThat(defaultState.roomNotificationSettings?.mode).isEqualTo(RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY)
} }
} }

View file

@ -21,7 +21,6 @@ import io.element.android.libraries.matrix.api.room.MatrixRoomNotificationSettin
import io.element.android.libraries.matrix.api.room.RoomNotificationMode import io.element.android.libraries.matrix.api.room.RoomNotificationMode
import io.element.android.libraries.matrix.api.room.RoomNotificationSettings import io.element.android.libraries.matrix.api.room.RoomNotificationSettings
import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.withContext
interface NotificationSettingsService { interface NotificationSettingsService {
/** /**

View file

@ -57,7 +57,11 @@ class RustNotificationSettingsService(
notificationSettings.getDefaultRoomNotificationMode(isEncrypted, isOneToOne).let(RoomNotificationSettingsMapper::mapMode) notificationSettings.getDefaultRoomNotificationMode(isEncrypted, isOneToOne).let(RoomNotificationSettingsMapper::mapMode)
} }
override suspend fun setDefaultRoomNotificationMode(isEncrypted: Boolean, mode: RoomNotificationMode, isOneToOne: Boolean): Result<Unit> = withContext(dispatchers.io) { override suspend fun setDefaultRoomNotificationMode(
isEncrypted: Boolean,
mode: RoomNotificationMode,
isOneToOne: Boolean
): Result<Unit> = withContext(dispatchers.io) {
runCatching { runCatching {
notificationSettings.setDefaultRoomNotificationMode(isEncrypted, isOneToOne, mode.let(RoomNotificationSettingsMapper::mapMode)) notificationSettings.setDefaultRoomNotificationMode(isEncrypted, isOneToOne, mode.let(RoomNotificationSettingsMapper::mapMode))
} }

View file

@ -25,32 +25,75 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.flow.SharedFlow
class FakeNotificationSettingsService( class FakeNotificationSettingsService(
initialMode: RoomNotificationMode = A_ROOM_NOTIFICATION_MODE, initialRoomMode: RoomNotificationMode = A_ROOM_NOTIFICATION_MODE,
initialDefaultMode: RoomNotificationMode = A_ROOM_NOTIFICATION_MODE initialGroupDefaultMode: RoomNotificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY,
initialEncryptedGroupDefaultMode: RoomNotificationMode = RoomNotificationMode.MENTIONS_AND_KEYWORDS_ONLY,
initialOneToOneDefaultMode: RoomNotificationMode = RoomNotificationMode.ALL_MESSAGES,
initialEncryptedOneToOneDefaultMode: RoomNotificationMode = RoomNotificationMode.ALL_MESSAGES,
) : NotificationSettingsService { ) : NotificationSettingsService {
private var _roomNotificationSettingsStateFlow = MutableStateFlow(Unit) private var _notificationSettingsStateFlow = MutableStateFlow(Unit)
private var defaultRoomNotificationMode: RoomNotificationMode = initialDefaultMode private var defaultGroupRoomNotificationMode: RoomNotificationMode = initialGroupDefaultMode
private var roomNotificationMode: RoomNotificationMode = initialMode private var defaultEncryptedGroupRoomNotificationMode: RoomNotificationMode = initialEncryptedGroupDefaultMode
private var defaultOneToOneRoomNotificationMode: RoomNotificationMode = initialOneToOneDefaultMode
private var defaultEncryptedOneToOneRoomNotificationMode: RoomNotificationMode = initialEncryptedOneToOneDefaultMode
private var roomNotificationMode: RoomNotificationMode = initialRoomMode
private var callNotificationsEnabled = false
private var atRoomNotificationsEnabled = false
override val notificationSettingsChangeFlow: SharedFlow<Unit> override val notificationSettingsChangeFlow: SharedFlow<Unit>
get() = _roomNotificationSettingsStateFlow get() = _notificationSettingsStateFlow
override suspend fun getRoomNotificationSettings(roomId: RoomId, isEncrypted: Boolean, membersCount: Long): Result<RoomNotificationSettings> { override suspend fun getRoomNotificationSettings(roomId: RoomId, isEncrypted: Boolean, isOneToOne: Boolean): Result<RoomNotificationSettings> {
return Result.success(RoomNotificationSettings(mode = roomNotificationMode, isDefault = roomNotificationMode == defaultRoomNotificationMode)) return Result.success(
RoomNotificationSettings(
mode = roomNotificationMode,
isDefault = roomNotificationMode == defaultEncryptedGroupRoomNotificationMode
)
)
} }
override suspend fun getDefaultRoomNotificationMode(isEncrypted: Boolean, membersCount: Long): Result<RoomNotificationMode> { override suspend fun getDefaultRoomNotificationMode(isEncrypted: Boolean, isOneToOne: Boolean): Result<RoomNotificationMode> {
return Result.success(defaultRoomNotificationMode) return if (isOneToOne) {
if (isEncrypted) {
Result.success(defaultEncryptedOneToOneRoomNotificationMode)
} else {
Result.success(defaultOneToOneRoomNotificationMode)
}
} else {
if (isEncrypted) {
Result.success(defaultEncryptedGroupRoomNotificationMode)
} else {
Result.success(defaultGroupRoomNotificationMode)
}
}
}
override suspend fun setDefaultRoomNotificationMode(isEncrypted: Boolean, mode: RoomNotificationMode, isOneToOne: Boolean): Result<Unit> {
if (isOneToOne) {
if (isEncrypted) {
defaultEncryptedOneToOneRoomNotificationMode = mode
} else {
defaultOneToOneRoomNotificationMode = mode
}
} else {
if (isEncrypted) {
defaultEncryptedGroupRoomNotificationMode = mode
} else {
defaultGroupRoomNotificationMode = mode
}
}
_notificationSettingsStateFlow.emit(Unit)
return Result.success(Unit)
} }
override suspend fun setRoomNotificationMode(roomId: RoomId, mode: RoomNotificationMode): Result<Unit> { override suspend fun setRoomNotificationMode(roomId: RoomId, mode: RoomNotificationMode): Result<Unit> {
roomNotificationMode = mode roomNotificationMode = mode
_roomNotificationSettingsStateFlow.emit(Unit) _notificationSettingsStateFlow.emit(Unit)
return Result.success(Unit) return Result.success(Unit)
} }
override suspend fun restoreDefaultRoomNotificationMode(roomId: RoomId): Result<Unit> { override suspend fun restoreDefaultRoomNotificationMode(roomId: RoomId): Result<Unit> {
roomNotificationMode = defaultRoomNotificationMode roomNotificationMode = defaultEncryptedGroupRoomNotificationMode
_roomNotificationSettingsStateFlow.emit(Unit) _notificationSettingsStateFlow.emit(Unit)
return Result.success(Unit) return Result.success(Unit)
} }
@ -58,23 +101,25 @@ class FakeNotificationSettingsService(
return setRoomNotificationMode(roomId, RoomNotificationMode.MUTE) return setRoomNotificationMode(roomId, RoomNotificationMode.MUTE)
} }
override suspend fun unmuteRoom(roomId: RoomId, isEncrypted: Boolean, membersCount: Long): Result<Unit> { override suspend fun unmuteRoom(roomId: RoomId, isEncrypted: Boolean, isOneToOne: Boolean): Result<Unit> {
return restoreDefaultRoomNotificationMode(roomId) return restoreDefaultRoomNotificationMode(roomId)
} }
override suspend fun isRoomMentionEnabled(): Result<Boolean> { override suspend fun isRoomMentionEnabled(): Result<Boolean> {
return Result.success(false) return Result.success(atRoomNotificationsEnabled)
} }
override suspend fun setRoomMentionEnabled(enabled: Boolean): Result<Unit> { override suspend fun setRoomMentionEnabled(enabled: Boolean): Result<Unit> {
atRoomNotificationsEnabled = enabled
return Result.success(Unit) return Result.success(Unit)
} }
override suspend fun isCallEnabled(): Result<Boolean> { override suspend fun isCallEnabled(): Result<Boolean> {
return Result.success(false) return Result.success(callNotificationsEnabled)
} }
override suspend fun setCallEnabled(enabled: Boolean): Result<Unit> { override suspend fun setCallEnabled(enabled: Boolean): Result<Unit> {
callNotificationsEnabled = enabled
return Result.success(Unit) return Result.success(Unit)
} }
} }

View file

@ -72,7 +72,6 @@ class FakeMatrixRoom(
private var userAvatarUrlResult = Result.success<String?>(null) private var userAvatarUrlResult = Result.success<String?>(null)
private var updateMembersResult: Result<Unit> = Result.success(Unit) private var updateMembersResult: Result<Unit> = Result.success(Unit)
private var joinRoomResult = Result.success(Unit) private var joinRoomResult = Result.success(Unit)
private var updateRoomNotificationSettingsResult: Result<Unit> = Result.success(Unit)
private var inviteUserResult = Result.success(Unit) private var inviteUserResult = Result.success(Unit)
private var canInviteResult = Result.success(true) private var canInviteResult = Result.success(true)
private var canRedactResult = Result.success(canRedact) private var canRedactResult = Result.success(canRedact)
@ -149,7 +148,7 @@ class FakeMatrixRoom(
} }
override suspend fun updateRoomNotificationSettings(): Result<Unit> = simulateLongTask { override suspend fun updateRoomNotificationSettings(): Result<Unit> = simulateLongTask {
val notificationSettings = notificationSettingsService.getRoomNotificationSettings(roomId, isEncrypted, activeMemberCount).getOrThrow() val notificationSettings = notificationSettingsService.getRoomNotificationSettings(roomId, isEncrypted, isOneToOne).getOrThrow()
roomNotificationSettingsStateFlow.value = MatrixRoomNotificationSettingsState.Ready(notificationSettings) roomNotificationSettingsStateFlow.value = MatrixRoomNotificationSettingsState.Ready(notificationSettings)
return Result.success(Unit) return Result.success(Unit)
} }

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
plugins {
id("io.element.android-library")
}
android {
namespace = "io.element.android.libraries.pushstore.test"
}
dependencies {
api(projects.libraries.matrix.api)
api(libs.coroutines.core)
implementation(libs.coroutines.test)
implementation(projects.tests.testutils)
implementation(projects.libraries.pushstore.api)
}

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.element.android.libraries.pushstore.test.userpushstore
import io.element.android.libraries.pushstore.api.UserPushStore
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
class FakeUserPushStore: UserPushStore {
private var pushProviderName: String? = null
private var currentRegisteredPushKey: String? = null
private val notificationEnabledForDevice = MutableStateFlow(true)
override suspend fun getPushProviderName(): String? {
return pushProviderName
}
override suspend fun setPushProviderName(value: String) {
pushProviderName = value
}
override suspend fun getCurrentRegisteredPushKey(): String? {
return currentRegisteredPushKey
}
override suspend fun setCurrentRegisteredPushKey(value: String) {
currentRegisteredPushKey = value
}
override fun getNotificationEnabledForDevice(): Flow<Boolean> {
return notificationEnabledForDevice
}
override suspend fun setNotificationEnabledForDevice(enabled: Boolean) {
notificationEnabledForDevice.value = enabled
}
override fun useCompleteNotificationFormat(): Boolean {
return true
}
override suspend fun reset() {
}
}

View file

@ -0,0 +1,28 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.element.android.libraries.pushstore.test.userpushstore
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.pushstore.api.UserPushStore
import io.element.android.libraries.pushstore.api.UserPushStoreFactory
class FakeUserPushStoreFactory: UserPushStoreFactory {
override fun create(userId: SessionId): UserPushStore {
return FakeUserPushStore()
}
}