Move setting to change push provider to the Notifications setting screen. #2912
Also improve previews of NotificationSettingsView.
This commit is contained in:
parent
d0b2233a7b
commit
300ca40af4
14 changed files with 271 additions and 265 deletions
|
|
@ -24,7 +24,4 @@ sealed interface AdvancedSettingsEvents {
|
|||
data object ChangeTheme : AdvancedSettingsEvents
|
||||
data object CancelChangeTheme : AdvancedSettingsEvents
|
||||
data class SetTheme(val theme: Theme) : AdvancedSettingsEvents
|
||||
data object ChangePushProvider : AdvancedSettingsEvents
|
||||
data object CancelChangePushProvider : AdvancedSettingsEvents
|
||||
data class SetPushProvider(val index: Int) : AdvancedSettingsEvents
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,10 +17,8 @@
|
|||
package io.element.android.features.preferences.impl.advanced
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
|
|
@ -29,22 +27,13 @@ import io.element.android.compound.theme.Theme
|
|||
import io.element.android.compound.theme.mapToTheme
|
||||
import io.element.android.features.preferences.api.store.AppPreferencesStore
|
||||
import io.element.android.features.preferences.api.store.SessionPreferencesStore
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.push.api.PushService
|
||||
import io.element.android.libraries.pushproviders.api.Distributor
|
||||
import io.element.android.libraries.pushproviders.api.PushProvider
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
class AdvancedSettingsPresenter @Inject constructor(
|
||||
private val appPreferencesStore: AppPreferencesStore,
|
||||
private val sessionPreferencesStore: SessionPreferencesStore,
|
||||
private val matrixClient: MatrixClient,
|
||||
private val pushService: PushService,
|
||||
) : Presenter<AdvancedSettingsState> {
|
||||
@Composable
|
||||
override fun present(): AdvancedSettingsState {
|
||||
|
|
@ -61,61 +50,6 @@ class AdvancedSettingsPresenter @Inject constructor(
|
|||
.collectAsState(initial = Theme.System)
|
||||
var showChangeThemeDialog by remember { mutableStateOf(false) }
|
||||
|
||||
// List of PushProvider -> Distributor
|
||||
val distributors = remember {
|
||||
pushService.getAvailablePushProviders()
|
||||
.flatMap { pushProvider ->
|
||||
pushProvider.getDistributors().map { distributor ->
|
||||
pushProvider to distributor
|
||||
}
|
||||
}
|
||||
}
|
||||
// List of Distributor names
|
||||
val distributorNames = remember {
|
||||
distributors.map { it.second.name }
|
||||
}
|
||||
|
||||
var currentDistributorName by remember { mutableStateOf<AsyncAction<String>>(AsyncAction.Uninitialized) }
|
||||
var refreshPushProvider by remember { mutableIntStateOf(0) }
|
||||
|
||||
LaunchedEffect(refreshPushProvider) {
|
||||
val p = pushService.getCurrentPushProvider()
|
||||
val name = p?.getCurrentDistributor(matrixClient)?.name
|
||||
currentDistributorName = if (name != null) {
|
||||
AsyncAction.Success(name)
|
||||
} else {
|
||||
AsyncAction.Failure(Exception("Failed to get current push provider"))
|
||||
}
|
||||
}
|
||||
|
||||
var showChangePushProviderDialog by remember { mutableStateOf(false) }
|
||||
|
||||
fun CoroutineScope.changePushProvider(
|
||||
data: Pair<PushProvider, Distributor>?
|
||||
) = launch {
|
||||
showChangePushProviderDialog = false
|
||||
data ?: return@launch
|
||||
// No op if the value is the same.
|
||||
if (data.second.name == currentDistributorName.dataOrNull()) return@launch
|
||||
currentDistributorName = AsyncAction.Loading
|
||||
data.let { (pushProvider, distributor) ->
|
||||
pushService.registerWith(
|
||||
matrixClient = matrixClient,
|
||||
pushProvider = pushProvider,
|
||||
distributor = distributor
|
||||
)
|
||||
.fold(
|
||||
{
|
||||
currentDistributorName = AsyncAction.Success(distributor.name)
|
||||
refreshPushProvider++
|
||||
},
|
||||
{
|
||||
currentDistributorName = AsyncAction.Failure(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun handleEvents(event: AdvancedSettingsEvents) {
|
||||
when (event) {
|
||||
is AdvancedSettingsEvents.SetDeveloperModeEnabled -> localCoroutineScope.launch {
|
||||
|
|
@ -130,9 +64,6 @@ class AdvancedSettingsPresenter @Inject constructor(
|
|||
appPreferencesStore.setTheme(event.theme.name)
|
||||
showChangeThemeDialog = false
|
||||
}
|
||||
AdvancedSettingsEvents.ChangePushProvider -> showChangePushProviderDialog = true
|
||||
AdvancedSettingsEvents.CancelChangePushProvider -> showChangePushProviderDialog = false
|
||||
is AdvancedSettingsEvents.SetPushProvider -> localCoroutineScope.changePushProvider(distributors.getOrNull(event.index))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -141,9 +72,6 @@ class AdvancedSettingsPresenter @Inject constructor(
|
|||
isSharePresenceEnabled = isSharePresenceEnabled,
|
||||
theme = theme,
|
||||
showChangeThemeDialog = showChangeThemeDialog,
|
||||
currentPushDistributor = currentDistributorName,
|
||||
availablePushDistributors = distributorNames.toImmutableList(),
|
||||
showChangePushProviderDialog = showChangePushProviderDialog,
|
||||
eventSink = { handleEvents(it) }
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,16 +17,11 @@
|
|||
package io.element.android.features.preferences.impl.advanced
|
||||
|
||||
import io.element.android.compound.theme.Theme
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
data class AdvancedSettingsState(
|
||||
val isDeveloperModeEnabled: Boolean,
|
||||
val isSharePresenceEnabled: Boolean,
|
||||
val theme: Theme,
|
||||
val showChangeThemeDialog: Boolean,
|
||||
val currentPushDistributor: AsyncAction<String>,
|
||||
val availablePushDistributors: ImmutableList<String>,
|
||||
val showChangePushProviderDialog: Boolean,
|
||||
val eventSink: (AdvancedSettingsEvents) -> Unit
|
||||
)
|
||||
|
|
|
|||
|
|
@ -18,8 +18,6 @@ package io.element.android.features.preferences.impl.advanced
|
|||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.compound.theme.Theme
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
open class AdvancedSettingsStateProvider : PreviewParameterProvider<AdvancedSettingsState> {
|
||||
override val values: Sequence<AdvancedSettingsState>
|
||||
|
|
@ -28,9 +26,6 @@ open class AdvancedSettingsStateProvider : PreviewParameterProvider<AdvancedSett
|
|||
aAdvancedSettingsState(isDeveloperModeEnabled = true),
|
||||
aAdvancedSettingsState(showChangeThemeDialog = true),
|
||||
aAdvancedSettingsState(isSendPublicReadReceiptsEnabled = true),
|
||||
aAdvancedSettingsState(showChangePushProviderDialog = true),
|
||||
aAdvancedSettingsState(currentPushDistributor = AsyncAction.Loading),
|
||||
aAdvancedSettingsState(currentPushDistributor = AsyncAction.Failure(Exception("Failed to change distributor"))),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -38,17 +33,11 @@ fun aAdvancedSettingsState(
|
|||
isDeveloperModeEnabled: Boolean = false,
|
||||
isSendPublicReadReceiptsEnabled: Boolean = false,
|
||||
showChangeThemeDialog: Boolean = false,
|
||||
currentPushDistributor: AsyncAction<String> = AsyncAction.Success("Firebase"),
|
||||
availablePushDistributors: List<String> = listOf("Firebase", "ntfy"),
|
||||
showChangePushProviderDialog: Boolean = false,
|
||||
eventSink: (AdvancedSettingsEvents) -> Unit = {},
|
||||
) = AdvancedSettingsState(
|
||||
isDeveloperModeEnabled = isDeveloperModeEnabled,
|
||||
isSharePresenceEnabled = isSendPublicReadReceiptsEnabled,
|
||||
theme = Theme.System,
|
||||
showChangeThemeDialog = showChangeThemeDialog,
|
||||
currentPushDistributor = currentPushDistributor,
|
||||
availablePushDistributors = availablePushDistributors.toImmutableList(),
|
||||
showChangePushProviderDialog = showChangePushProviderDialog,
|
||||
eventSink = eventSink
|
||||
)
|
||||
|
|
|
|||
|
|
@ -16,24 +16,19 @@
|
|||
|
||||
package io.element.android.features.preferences.impl.advanced
|
||||
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.progressSemantics
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.Theme
|
||||
import io.element.android.compound.theme.themes
|
||||
import io.element.android.features.preferences.impl.R
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.designsystem.components.dialogs.ListOption
|
||||
import io.element.android.libraries.designsystem.components.dialogs.SingleSelectionDialog
|
||||
import io.element.android.libraries.designsystem.components.list.ListItemContent
|
||||
import io.element.android.libraries.designsystem.components.preferences.PreferencePage
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
|
||||
import io.element.android.libraries.designsystem.theme.components.ListItem
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
|
@ -86,34 +81,6 @@ fun AdvancedSettingsView(
|
|||
),
|
||||
onClick = { state.eventSink(AdvancedSettingsEvents.SetSharePresenceEnabled(!state.isSharePresenceEnabled)) }
|
||||
)
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(text = stringResource(id = R.string.screen_advanced_settings_push_provider_android))
|
||||
},
|
||||
trailingContent = when (state.currentPushDistributor) {
|
||||
AsyncAction.Uninitialized,
|
||||
AsyncAction.Confirming,
|
||||
AsyncAction.Loading -> ListItemContent.Custom {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier
|
||||
.progressSemantics()
|
||||
.size(20.dp),
|
||||
strokeWidth = 2.dp
|
||||
)
|
||||
}
|
||||
is AsyncAction.Failure -> ListItemContent.Text(
|
||||
stringResource(id = CommonStrings.common_error)
|
||||
)
|
||||
is AsyncAction.Success -> ListItemContent.Text(
|
||||
state.currentPushDistributor.dataOrNull() ?: ""
|
||||
)
|
||||
},
|
||||
onClick = {
|
||||
if (state.currentPushDistributor.isReady()) {
|
||||
state.eventSink(AdvancedSettingsEvents.ChangePushProvider)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (state.showChangeThemeDialog) {
|
||||
|
|
@ -130,22 +97,6 @@ fun AdvancedSettingsView(
|
|||
onDismissRequest = { state.eventSink(AdvancedSettingsEvents.CancelChangeTheme) },
|
||||
)
|
||||
}
|
||||
|
||||
if (state.showChangePushProviderDialog) {
|
||||
SingleSelectionDialog(
|
||||
title = stringResource(id = R.string.screen_advanced_settings_choose_distributor_dialog_title_android),
|
||||
options = state.availablePushDistributors.map {
|
||||
ListOption(title = it)
|
||||
}.toImmutableList(),
|
||||
initialSelection = state.availablePushDistributors.indexOf(state.currentPushDistributor.dataOrNull()),
|
||||
onOptionSelected = { index ->
|
||||
state.eventSink(
|
||||
AdvancedSettingsEvents.SetPushProvider(index)
|
||||
)
|
||||
},
|
||||
onDismissRequest = { state.eventSink(AdvancedSettingsEvents.CancelChangePushProvider) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -25,4 +25,7 @@ sealed interface NotificationSettingsEvents {
|
|||
data object FixConfigurationMismatch : NotificationSettingsEvents
|
||||
data object ClearConfigurationMismatchError : NotificationSettingsEvents
|
||||
data object ClearNotificationChangeError : NotificationSettingsEvents
|
||||
data object ChangePushProvider : NotificationSettingsEvents
|
||||
data object CancelChangePushProvider : NotificationSettingsEvents
|
||||
data class SetPushProvider(val index: Int) : NotificationSettingsEvents
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,17 +20,24 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.push.api.PushService
|
||||
import io.element.android.libraries.pushproviders.api.Distributor
|
||||
import io.element.android.libraries.pushproviders.api.PushProvider
|
||||
import io.element.android.libraries.pushstore.api.UserPushStore
|
||||
import io.element.android.libraries.pushstore.api.UserPushStoreFactory
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
|
|
@ -44,7 +51,8 @@ class NotificationSettingsPresenter @Inject constructor(
|
|||
private val notificationSettingsService: NotificationSettingsService,
|
||||
private val userPushStoreFactory: UserPushStoreFactory,
|
||||
private val matrixClient: MatrixClient,
|
||||
private val systemNotificationsEnabledProvider: SystemNotificationsEnabledProvider
|
||||
private val pushService: PushService,
|
||||
private val systemNotificationsEnabledProvider: SystemNotificationsEnabledProvider,
|
||||
) : Presenter<NotificationSettingsState> {
|
||||
@Composable
|
||||
override fun present(): NotificationSettingsState {
|
||||
|
|
@ -68,6 +76,61 @@ class NotificationSettingsPresenter @Inject constructor(
|
|||
observeNotificationSettings(matrixSettings)
|
||||
}
|
||||
|
||||
// List of PushProvider -> Distributor
|
||||
val distributors = remember {
|
||||
pushService.getAvailablePushProviders()
|
||||
.flatMap { pushProvider ->
|
||||
pushProvider.getDistributors().map { distributor ->
|
||||
pushProvider to distributor
|
||||
}
|
||||
}
|
||||
}
|
||||
// List of Distributor names
|
||||
val distributorNames = remember {
|
||||
distributors.map { it.second.name }
|
||||
}
|
||||
|
||||
var currentDistributorName by remember { mutableStateOf<AsyncAction<String>>(AsyncAction.Uninitialized) }
|
||||
var refreshPushProvider by remember { mutableIntStateOf(0) }
|
||||
|
||||
LaunchedEffect(refreshPushProvider) {
|
||||
val p = pushService.getCurrentPushProvider()
|
||||
val name = p?.getCurrentDistributor(matrixClient)?.name
|
||||
currentDistributorName = if (name != null) {
|
||||
AsyncAction.Success(name)
|
||||
} else {
|
||||
AsyncAction.Failure(Exception("Failed to get current push provider"))
|
||||
}
|
||||
}
|
||||
|
||||
var showChangePushProviderDialog by remember { mutableStateOf(false) }
|
||||
|
||||
fun CoroutineScope.changePushProvider(
|
||||
data: Pair<PushProvider, Distributor>?
|
||||
) = launch {
|
||||
showChangePushProviderDialog = false
|
||||
data ?: return@launch
|
||||
// No op if the value is the same.
|
||||
if (data.second.name == currentDistributorName.dataOrNull()) return@launch
|
||||
currentDistributorName = AsyncAction.Loading
|
||||
data.let { (pushProvider, distributor) ->
|
||||
pushService.registerWith(
|
||||
matrixClient = matrixClient,
|
||||
pushProvider = pushProvider,
|
||||
distributor = distributor
|
||||
)
|
||||
.fold(
|
||||
{
|
||||
currentDistributorName = AsyncAction.Success(distributor.name)
|
||||
refreshPushProvider++
|
||||
},
|
||||
{
|
||||
currentDistributorName = AsyncAction.Failure(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun handleEvents(event: NotificationSettingsEvents) {
|
||||
when (event) {
|
||||
is NotificationSettingsEvents.SetAtRoomNotificationsEnabled -> {
|
||||
|
|
@ -88,6 +151,9 @@ class NotificationSettingsPresenter @Inject constructor(
|
|||
systemNotificationsEnabled.value = systemNotificationsEnabledProvider.notificationsEnabled()
|
||||
}
|
||||
NotificationSettingsEvents.ClearNotificationChangeError -> changeNotificationSettingAction.value = AsyncAction.Uninitialized
|
||||
NotificationSettingsEvents.ChangePushProvider -> showChangePushProviderDialog = true
|
||||
NotificationSettingsEvents.CancelChangePushProvider -> showChangePushProviderDialog = false
|
||||
is NotificationSettingsEvents.SetPushProvider -> localCoroutineScope.changePushProvider(distributors.getOrNull(event.index))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -98,6 +164,9 @@ class NotificationSettingsPresenter @Inject constructor(
|
|||
appNotificationsEnabled = appNotificationsEnabled.value
|
||||
),
|
||||
changeNotificationSettingAction = changeNotificationSettingAction.value,
|
||||
currentPushDistributor = currentDistributorName,
|
||||
availablePushDistributors = distributorNames.toImmutableList(),
|
||||
showChangePushProviderDialog = showChangePushProviderDialog,
|
||||
eventSink = ::handleEvents
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,12 +19,16 @@ package io.element.android.features.preferences.impl.notifications
|
|||
import androidx.compose.runtime.Immutable
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import kotlinx.collections.immutable.ImmutableList
|
||||
|
||||
@Immutable
|
||||
data class NotificationSettingsState(
|
||||
val matrixSettings: MatrixSettings,
|
||||
val appSettings: AppSettings,
|
||||
val changeNotificationSettingAction: AsyncAction<Unit>,
|
||||
val currentPushDistributor: AsyncAction<String>,
|
||||
val availablePushDistributors: ImmutableList<String>,
|
||||
val showChangePushProviderDialog: Boolean,
|
||||
val eventSink: (NotificationSettingsEvents) -> Unit,
|
||||
) {
|
||||
sealed interface MatrixSettings {
|
||||
|
|
|
|||
|
|
@ -19,13 +19,19 @@ package io.element.android.features.preferences.impl.notifications
|
|||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
open class NotificationSettingsStateProvider : PreviewParameterProvider<NotificationSettingsState> {
|
||||
override val values: Sequence<NotificationSettingsState>
|
||||
get() = sequenceOf(
|
||||
aValidNotificationSettingsState(),
|
||||
aValidNotificationSettingsState(systemNotificationsEnabled = false),
|
||||
aValidNotificationSettingsState(changeNotificationSettingAction = AsyncAction.Loading),
|
||||
aValidNotificationSettingsState(changeNotificationSettingAction = AsyncAction.Failure(Throwable("error"))),
|
||||
aValidNotificationSettingsState(showChangePushProviderDialog = true),
|
||||
aValidNotificationSettingsState(currentPushDistributor = AsyncAction.Loading),
|
||||
aValidNotificationSettingsState(currentPushDistributor = AsyncAction.Failure(Exception("Failed to change distributor"))),
|
||||
aInvalidNotificationSettingsState(),
|
||||
aInvalidNotificationSettingsState(fixFailed = true),
|
||||
)
|
||||
|
|
@ -36,7 +42,11 @@ fun aValidNotificationSettingsState(
|
|||
atRoomNotificationsEnabled: Boolean = true,
|
||||
callNotificationsEnabled: Boolean = true,
|
||||
inviteForMeNotificationsEnabled: Boolean = true,
|
||||
systemNotificationsEnabled: Boolean = true,
|
||||
appNotificationEnabled: Boolean = true,
|
||||
currentPushDistributor: AsyncAction<String> = AsyncAction.Success("Firebase"),
|
||||
availablePushDistributors: List<String> = listOf("Firebase", "ntfy"),
|
||||
showChangePushProviderDialog: Boolean = false,
|
||||
eventSink: (NotificationSettingsEvents) -> Unit = {},
|
||||
) = NotificationSettingsState(
|
||||
matrixSettings = NotificationSettingsState.MatrixSettings.Valid(
|
||||
|
|
@ -47,10 +57,13 @@ fun aValidNotificationSettingsState(
|
|||
defaultOneToOneNotificationMode = RoomNotificationMode.ALL_MESSAGES,
|
||||
),
|
||||
appSettings = NotificationSettingsState.AppSettings(
|
||||
systemNotificationsEnabled = false,
|
||||
systemNotificationsEnabled = systemNotificationsEnabled,
|
||||
appNotificationsEnabled = appNotificationEnabled,
|
||||
),
|
||||
changeNotificationSettingAction = changeNotificationSettingAction,
|
||||
currentPushDistributor = currentPushDistributor,
|
||||
availablePushDistributors = availablePushDistributors.toImmutableList(),
|
||||
showChangePushProviderDialog = showChangePushProviderDialog,
|
||||
eventSink = eventSink,
|
||||
)
|
||||
|
||||
|
|
@ -66,5 +79,8 @@ fun aInvalidNotificationSettingsState(
|
|||
appNotificationsEnabled = true,
|
||||
),
|
||||
changeNotificationSettingAction = AsyncAction.Uninitialized,
|
||||
currentPushDistributor = AsyncAction.Uninitialized,
|
||||
availablePushDistributors = persistentListOf(),
|
||||
showChangePushProviderDialog = false,
|
||||
eventSink = eventSink,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -16,27 +16,38 @@
|
|||
|
||||
package io.element.android.features.preferences.impl.notifications
|
||||
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.progressSemantics
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||
import io.element.android.features.preferences.impl.R
|
||||
import io.element.android.libraries.androidutils.system.startNotificationSettingsIntent
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.designsystem.atomic.molecules.DialogLikeBannerMolecule
|
||||
import io.element.android.libraries.designsystem.components.async.AsyncActionView
|
||||
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
|
||||
import io.element.android.libraries.designsystem.components.dialogs.ListOption
|
||||
import io.element.android.libraries.designsystem.components.dialogs.SingleSelectionDialog
|
||||
import io.element.android.libraries.designsystem.components.list.ListItemContent
|
||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceCategory
|
||||
import io.element.android.libraries.designsystem.components.preferences.PreferencePage
|
||||
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.theme.components.CircularProgressIndicator
|
||||
import io.element.android.libraries.designsystem.theme.components.ListItem
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.utils.OnLifecycleEvent
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import kotlinx.collections.immutable.toImmutableList
|
||||
|
||||
/**
|
||||
* A view that allows a user edit their global notification settings.
|
||||
|
|
@ -69,7 +80,7 @@ fun NotificationSettingsView(
|
|||
NotificationSettingsState.MatrixSettings.Uninitialized -> return@PreferencePage
|
||||
is NotificationSettingsState.MatrixSettings.Valid -> NotificationSettingsContentView(
|
||||
matrixSettings = state.matrixSettings,
|
||||
systemSettings = state.appSettings,
|
||||
state = state,
|
||||
onNotificationsEnabledChanged = { state.eventSink(NotificationSettingsEvents.SetNotificationsEnabled(it)) },
|
||||
onGroupChatsClicked = { onOpenEditDefault(false) },
|
||||
onDirectChatsClicked = { onOpenEditDefault(true) },
|
||||
|
|
@ -92,7 +103,7 @@ fun NotificationSettingsView(
|
|||
@Composable
|
||||
private fun NotificationSettingsContentView(
|
||||
matrixSettings: NotificationSettingsState.MatrixSettings.Valid,
|
||||
systemSettings: NotificationSettingsState.AppSettings,
|
||||
state: NotificationSettingsState,
|
||||
onNotificationsEnabledChanged: (Boolean) -> Unit,
|
||||
onGroupChatsClicked: () -> Unit,
|
||||
onDirectChatsClicked: () -> Unit,
|
||||
|
|
@ -103,6 +114,7 @@ private fun NotificationSettingsContentView(
|
|||
onTroubleshootNotificationsClicked: () -> Unit,
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val systemSettings: NotificationSettingsState.AppSettings = state.appSettings
|
||||
if (systemSettings.appNotificationsEnabled && !systemSettings.systemNotificationsEnabled) {
|
||||
PreferenceText(
|
||||
icon = CompoundIcons.NotificationsOffSolid(),
|
||||
|
|
@ -169,6 +181,51 @@ private fun NotificationSettingsContentView(
|
|||
onClick = onTroubleshootNotificationsClicked
|
||||
)
|
||||
}
|
||||
PreferenceCategory(title = stringResource(id = CommonStrings.common_advanced_settings)) {
|
||||
ListItem(
|
||||
headlineContent = {
|
||||
Text(text = stringResource(id = R.string.screen_advanced_settings_push_provider_android))
|
||||
},
|
||||
trailingContent = when (state.currentPushDistributor) {
|
||||
AsyncAction.Uninitialized,
|
||||
AsyncAction.Confirming,
|
||||
AsyncAction.Loading -> ListItemContent.Custom {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier
|
||||
.progressSemantics()
|
||||
.size(20.dp),
|
||||
strokeWidth = 2.dp
|
||||
)
|
||||
}
|
||||
is AsyncAction.Failure -> ListItemContent.Text(
|
||||
stringResource(id = CommonStrings.common_error)
|
||||
)
|
||||
is AsyncAction.Success -> ListItemContent.Text(
|
||||
state.currentPushDistributor.dataOrNull() ?: ""
|
||||
)
|
||||
},
|
||||
onClick = {
|
||||
if (state.currentPushDistributor.isReady()) {
|
||||
state.eventSink(NotificationSettingsEvents.ChangePushProvider)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
if (state.showChangePushProviderDialog) {
|
||||
SingleSelectionDialog(
|
||||
title = stringResource(id = R.string.screen_advanced_settings_choose_distributor_dialog_title_android),
|
||||
options = state.availablePushDistributors.map {
|
||||
ListOption(title = it)
|
||||
}.toImmutableList(),
|
||||
initialSelection = state.availablePushDistributors.indexOf(state.currentPushDistributor.dataOrNull()),
|
||||
onOptionSelected = { index ->
|
||||
state.eventSink(
|
||||
NotificationSettingsEvents.SetPushProvider(index)
|
||||
)
|
||||
},
|
||||
onDismissRequest = { state.eventSink(NotificationSettingsEvents.CancelChangePushProvider) },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,16 +21,8 @@ import app.cash.molecule.moleculeFlow
|
|||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.compound.theme.Theme
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||
import io.element.android.libraries.preferences.test.InMemoryAppPreferencesStore
|
||||
import io.element.android.libraries.preferences.test.InMemorySessionPreferencesStore
|
||||
import io.element.android.libraries.push.api.PushService
|
||||
import io.element.android.libraries.push.test.FakePushService
|
||||
import io.element.android.libraries.pushproviders.api.Distributor
|
||||
import io.element.android.libraries.pushproviders.api.PushProvider
|
||||
import io.element.android.libraries.pushproviders.test.FakePushProvider
|
||||
import io.element.android.tests.testutils.WarmUpRule
|
||||
import io.element.android.tests.testutils.awaitLastSequentialItem
|
||||
import kotlinx.coroutines.test.runTest
|
||||
|
|
@ -108,93 +100,11 @@ class AdvancedSettingsPresenterTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - change push provider`() = runTest {
|
||||
val presenter = createAdvancedSettingsPresenter(
|
||||
pushService = createFakePushService(),
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitLastSequentialItem()
|
||||
assertThat(initialState.currentPushDistributor).isEqualTo(AsyncAction.Success("aDistributorName0"))
|
||||
assertThat(initialState.availablePushDistributors).containsExactly("aDistributorName0", "aDistributorName1")
|
||||
initialState.eventSink.invoke(AdvancedSettingsEvents.ChangePushProvider)
|
||||
val withDialog = awaitItem()
|
||||
assertThat(withDialog.showChangePushProviderDialog).isTrue()
|
||||
// Cancel
|
||||
withDialog.eventSink(AdvancedSettingsEvents.CancelChangePushProvider)
|
||||
val withoutDialog = awaitItem()
|
||||
assertThat(withoutDialog.showChangePushProviderDialog).isFalse()
|
||||
withDialog.eventSink.invoke(AdvancedSettingsEvents.ChangePushProvider)
|
||||
assertThat(awaitItem().showChangePushProviderDialog).isTrue()
|
||||
withDialog.eventSink(AdvancedSettingsEvents.SetPushProvider(1))
|
||||
val withNewProvider = awaitItem()
|
||||
assertThat(withNewProvider.showChangePushProviderDialog).isFalse()
|
||||
assertThat(withNewProvider.currentPushDistributor).isEqualTo(AsyncAction.Loading)
|
||||
val lastItem = awaitItem()
|
||||
assertThat(lastItem.currentPushDistributor).isEqualTo(AsyncAction.Success("aDistributorName1"))
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - change push provider error`() = runTest {
|
||||
val presenter = createAdvancedSettingsPresenter(
|
||||
pushService = createFakePushService(
|
||||
registerWithLambda = { _, _, _ ->
|
||||
Result.failure(Exception("An error"))
|
||||
},
|
||||
),
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitLastSequentialItem()
|
||||
initialState.eventSink.invoke(AdvancedSettingsEvents.ChangePushProvider)
|
||||
val withDialog = awaitItem()
|
||||
assertThat(withDialog.showChangePushProviderDialog).isTrue()
|
||||
withDialog.eventSink(AdvancedSettingsEvents.SetPushProvider(1))
|
||||
val withNewProvider = awaitItem()
|
||||
assertThat(withNewProvider.showChangePushProviderDialog).isFalse()
|
||||
assertThat(withNewProvider.currentPushDistributor).isEqualTo(AsyncAction.Loading)
|
||||
val lastItem = awaitItem()
|
||||
assertThat(lastItem.currentPushDistributor).isInstanceOf(AsyncAction.Failure::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createFakePushService(
|
||||
registerWithLambda: suspend (MatrixClient, PushProvider, Distributor) -> Result<Unit> = { _, _, _ ->
|
||||
Result.success(Unit)
|
||||
}
|
||||
): PushService {
|
||||
val pushProvider1 = FakePushProvider(
|
||||
index = 0,
|
||||
name = "aFakePushProvider0",
|
||||
isAvailable = true,
|
||||
distributors = listOf(Distributor("aDistributorValue0", "aDistributorName0")),
|
||||
)
|
||||
val pushProvider2 = FakePushProvider(
|
||||
index = 1,
|
||||
name = "aFakePushProvider1",
|
||||
isAvailable = true,
|
||||
distributors = listOf(Distributor("aDistributorValue1", "aDistributorName1")),
|
||||
)
|
||||
return FakePushService(
|
||||
availablePushProviders = listOf(pushProvider1, pushProvider2),
|
||||
registerWithLambda = registerWithLambda,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createAdvancedSettingsPresenter(
|
||||
appPreferencesStore: InMemoryAppPreferencesStore = InMemoryAppPreferencesStore(),
|
||||
sessionPreferencesStore: InMemorySessionPreferencesStore = InMemorySessionPreferencesStore(),
|
||||
matrixClient: MatrixClient = FakeMatrixClient(),
|
||||
pushService: PushService = FakePushService(),
|
||||
) = AdvancedSettingsPresenter(
|
||||
appPreferencesStore = appPreferencesStore,
|
||||
sessionPreferencesStore = sessionPreferencesStore,
|
||||
matrixClient = matrixClient,
|
||||
pushService = pushService,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,8 +19,6 @@ package io.element.android.features.preferences.impl.advanced
|
|||
import androidx.activity.ComponentActivity
|
||||
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
|
||||
import androidx.compose.ui.test.junit4.createAndroidComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.element.android.compound.theme.Theme
|
||||
import io.element.android.features.preferences.impl.R
|
||||
|
|
@ -34,7 +32,6 @@ import org.junit.Rule
|
|||
import org.junit.Test
|
||||
import org.junit.rules.TestRule
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class AdvancedSettingsViewTest {
|
||||
|
|
@ -103,33 +100,6 @@ class AdvancedSettingsViewTest {
|
|||
rule.clickOn(R.string.screen_advanced_settings_share_presence)
|
||||
eventsRecorder.assertSingle(AdvancedSettingsEvents.SetSharePresenceEnabled(true))
|
||||
}
|
||||
|
||||
@Config(qualifiers = "h1024dp")
|
||||
@Test
|
||||
fun `clicking on Push notification provider emits the expected event`() {
|
||||
val eventsRecorder = EventsRecorder<AdvancedSettingsEvents>()
|
||||
rule.setAdvancedSettingsView(
|
||||
state = aAdvancedSettingsState(
|
||||
eventSink = eventsRecorder
|
||||
),
|
||||
)
|
||||
rule.clickOn(R.string.screen_advanced_settings_push_provider_android)
|
||||
eventsRecorder.assertSingle(AdvancedSettingsEvents.ChangePushProvider)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on a push provider emits the expected event`() {
|
||||
val eventsRecorder = EventsRecorder<AdvancedSettingsEvents>()
|
||||
rule.setAdvancedSettingsView(
|
||||
state = aAdvancedSettingsState(
|
||||
eventSink = eventsRecorder,
|
||||
showChangePushProviderDialog = true,
|
||||
availablePushDistributors = listOf("P1", "P2")
|
||||
),
|
||||
)
|
||||
rule.onNodeWithText("P2").performClick()
|
||||
eventsRecorder.assertSingle(AdvancedSettingsEvents.SetPushProvider(1))
|
||||
}
|
||||
}
|
||||
|
||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setAdvancedSettingsView(
|
||||
|
|
|
|||
|
|
@ -20,11 +20,19 @@ import app.cash.molecule.RecompositionMode
|
|||
import app.cash.molecule.moleculeFlow
|
||||
import app.cash.turbine.test
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||
import io.element.android.libraries.matrix.test.A_THROWABLE
|
||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||
import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService
|
||||
import io.element.android.libraries.push.api.PushService
|
||||
import io.element.android.libraries.push.test.FakePushService
|
||||
import io.element.android.libraries.pushproviders.api.Distributor
|
||||
import io.element.android.libraries.pushproviders.api.PushProvider
|
||||
import io.element.android.libraries.pushproviders.test.FakePushProvider
|
||||
import io.element.android.libraries.pushstore.test.userpushstore.FakeUserPushStoreFactory
|
||||
import io.element.android.tests.testutils.awaitLastSequentialItem
|
||||
import io.element.android.tests.testutils.consumeItemsUntilPredicate
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
|
|
@ -230,14 +238,94 @@ class NotificationSettingsPresenterTests {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - change push provider`() = runTest {
|
||||
val presenter = createNotificationSettingsPresenter(
|
||||
pushService = createFakePushService(),
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitLastSequentialItem()
|
||||
assertThat(initialState.currentPushDistributor).isEqualTo(AsyncAction.Success("aDistributorName0"))
|
||||
assertThat(initialState.availablePushDistributors).containsExactly("aDistributorName0", "aDistributorName1")
|
||||
initialState.eventSink.invoke(NotificationSettingsEvents.ChangePushProvider)
|
||||
val withDialog = awaitItem()
|
||||
assertThat(withDialog.showChangePushProviderDialog).isTrue()
|
||||
// Cancel
|
||||
withDialog.eventSink(NotificationSettingsEvents.CancelChangePushProvider)
|
||||
val withoutDialog = awaitItem()
|
||||
assertThat(withoutDialog.showChangePushProviderDialog).isFalse()
|
||||
withDialog.eventSink.invoke(NotificationSettingsEvents.ChangePushProvider)
|
||||
assertThat(awaitItem().showChangePushProviderDialog).isTrue()
|
||||
withDialog.eventSink(NotificationSettingsEvents.SetPushProvider(1))
|
||||
val withNewProvider = awaitItem()
|
||||
assertThat(withNewProvider.showChangePushProviderDialog).isFalse()
|
||||
assertThat(withNewProvider.currentPushDistributor).isEqualTo(AsyncAction.Loading)
|
||||
val lastItem = awaitItem()
|
||||
assertThat(lastItem.currentPushDistributor).isEqualTo(AsyncAction.Success("aDistributorName1"))
|
||||
cancelAndIgnoreRemainingEvents()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `present - change push provider error`() = runTest {
|
||||
val presenter = createNotificationSettingsPresenter(
|
||||
pushService = createFakePushService(
|
||||
registerWithLambda = { _, _, _ ->
|
||||
Result.failure(Exception("An error"))
|
||||
},
|
||||
),
|
||||
)
|
||||
moleculeFlow(RecompositionMode.Immediate) {
|
||||
presenter.present()
|
||||
}.test {
|
||||
val initialState = awaitLastSequentialItem()
|
||||
initialState.eventSink.invoke(NotificationSettingsEvents.ChangePushProvider)
|
||||
val withDialog = awaitItem()
|
||||
assertThat(withDialog.showChangePushProviderDialog).isTrue()
|
||||
withDialog.eventSink(NotificationSettingsEvents.SetPushProvider(1))
|
||||
val withNewProvider = awaitItem()
|
||||
assertThat(withNewProvider.showChangePushProviderDialog).isFalse()
|
||||
assertThat(withNewProvider.currentPushDistributor).isEqualTo(AsyncAction.Loading)
|
||||
val lastItem = awaitItem()
|
||||
assertThat(lastItem.currentPushDistributor).isInstanceOf(AsyncAction.Failure::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createFakePushService(
|
||||
registerWithLambda: suspend (MatrixClient, PushProvider, Distributor) -> Result<Unit> = { _, _, _ ->
|
||||
Result.success(Unit)
|
||||
}
|
||||
): PushService {
|
||||
val pushProvider1 = FakePushProvider(
|
||||
index = 0,
|
||||
name = "aFakePushProvider0",
|
||||
isAvailable = true,
|
||||
distributors = listOf(Distributor("aDistributorValue0", "aDistributorName0")),
|
||||
)
|
||||
val pushProvider2 = FakePushProvider(
|
||||
index = 1,
|
||||
name = "aFakePushProvider1",
|
||||
isAvailable = true,
|
||||
distributors = listOf(Distributor("aDistributorValue1", "aDistributorName1")),
|
||||
)
|
||||
return FakePushService(
|
||||
availablePushProviders = listOf(pushProvider1, pushProvider2),
|
||||
registerWithLambda = registerWithLambda,
|
||||
)
|
||||
}
|
||||
|
||||
private fun createNotificationSettingsPresenter(
|
||||
notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService()
|
||||
notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(),
|
||||
pushService: PushService = FakePushService(),
|
||||
): NotificationSettingsPresenter {
|
||||
val matrixClient = FakeMatrixClient(notificationSettingsService = notificationSettingsService)
|
||||
return NotificationSettingsPresenter(
|
||||
notificationSettingsService = notificationSettingsService,
|
||||
userPushStoreFactory = FakeUserPushStoreFactory(),
|
||||
matrixClient = matrixClient,
|
||||
pushService = pushService,
|
||||
systemNotificationsEnabledProvider = FakeSystemNotificationsEnabledProvider(),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ package io.element.android.features.preferences.impl.notifications
|
|||
import androidx.activity.ComponentActivity
|
||||
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
|
||||
import androidx.compose.ui.test.junit4.createAndroidComposeRule
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.performClick
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import io.element.android.features.preferences.impl.R
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
|
|
@ -248,6 +250,33 @@ class NotificationSettingsViewTest {
|
|||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Config(qualifiers = "h1024dp")
|
||||
@Test
|
||||
fun `clicking on Push notification provider emits the expected event`() {
|
||||
val eventsRecorder = EventsRecorder<NotificationSettingsEvents>()
|
||||
rule.setNotificationSettingsView(
|
||||
state = aValidNotificationSettingsState(
|
||||
eventSink = eventsRecorder
|
||||
),
|
||||
)
|
||||
rule.clickOn(R.string.screen_advanced_settings_push_provider_android)
|
||||
eventsRecorder.assertSingle(NotificationSettingsEvents.ChangePushProvider)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking on a push provider emits the expected event`() {
|
||||
val eventsRecorder = EventsRecorder<NotificationSettingsEvents>()
|
||||
rule.setNotificationSettingsView(
|
||||
state = aValidNotificationSettingsState(
|
||||
eventSink = eventsRecorder,
|
||||
showChangePushProviderDialog = true,
|
||||
availablePushDistributors = listOf("P1", "P2")
|
||||
),
|
||||
)
|
||||
rule.onNodeWithText("P2").performClick()
|
||||
eventsRecorder.assertSingle(NotificationSettingsEvents.SetPushProvider(1))
|
||||
}
|
||||
}
|
||||
|
||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setNotificationSettingsView(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue