Merge pull request #2928 from element-hq/feature/bma/movePushSetting
Move push provider setting
This commit is contained in:
commit
edc589b494
52 changed files with 376 additions and 317 deletions
1
changelog.d/2912.misc
Normal file
1
changelog.d/2912.misc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Move push provider setting to the "Notifications" screen and display it only when several push provider are available.
|
||||||
|
|
@ -24,7 +24,4 @@ sealed interface AdvancedSettingsEvents {
|
||||||
data object ChangeTheme : AdvancedSettingsEvents
|
data object ChangeTheme : AdvancedSettingsEvents
|
||||||
data object CancelChangeTheme : AdvancedSettingsEvents
|
data object CancelChangeTheme : AdvancedSettingsEvents
|
||||||
data class SetTheme(val theme: Theme) : 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
|
package io.element.android.features.preferences.impl.advanced
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
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.compound.theme.mapToTheme
|
||||||
import io.element.android.features.preferences.api.store.AppPreferencesStore
|
import io.element.android.features.preferences.api.store.AppPreferencesStore
|
||||||
import io.element.android.features.preferences.api.store.SessionPreferencesStore
|
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.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 kotlinx.coroutines.launch
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class AdvancedSettingsPresenter @Inject constructor(
|
class AdvancedSettingsPresenter @Inject constructor(
|
||||||
private val appPreferencesStore: AppPreferencesStore,
|
private val appPreferencesStore: AppPreferencesStore,
|
||||||
private val sessionPreferencesStore: SessionPreferencesStore,
|
private val sessionPreferencesStore: SessionPreferencesStore,
|
||||||
private val matrixClient: MatrixClient,
|
|
||||||
private val pushService: PushService,
|
|
||||||
) : Presenter<AdvancedSettingsState> {
|
) : Presenter<AdvancedSettingsState> {
|
||||||
@Composable
|
@Composable
|
||||||
override fun present(): AdvancedSettingsState {
|
override fun present(): AdvancedSettingsState {
|
||||||
|
|
@ -61,61 +50,6 @@ class AdvancedSettingsPresenter @Inject constructor(
|
||||||
.collectAsState(initial = Theme.System)
|
.collectAsState(initial = Theme.System)
|
||||||
var showChangeThemeDialog by remember { mutableStateOf(false) }
|
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) {
|
fun handleEvents(event: AdvancedSettingsEvents) {
|
||||||
when (event) {
|
when (event) {
|
||||||
is AdvancedSettingsEvents.SetDeveloperModeEnabled -> localCoroutineScope.launch {
|
is AdvancedSettingsEvents.SetDeveloperModeEnabled -> localCoroutineScope.launch {
|
||||||
|
|
@ -130,9 +64,6 @@ class AdvancedSettingsPresenter @Inject constructor(
|
||||||
appPreferencesStore.setTheme(event.theme.name)
|
appPreferencesStore.setTheme(event.theme.name)
|
||||||
showChangeThemeDialog = false
|
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,
|
isSharePresenceEnabled = isSharePresenceEnabled,
|
||||||
theme = theme,
|
theme = theme,
|
||||||
showChangeThemeDialog = showChangeThemeDialog,
|
showChangeThemeDialog = showChangeThemeDialog,
|
||||||
currentPushDistributor = currentDistributorName,
|
|
||||||
availablePushDistributors = distributorNames.toImmutableList(),
|
|
||||||
showChangePushProviderDialog = showChangePushProviderDialog,
|
|
||||||
eventSink = { handleEvents(it) }
|
eventSink = { handleEvents(it) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,16 +17,11 @@
|
||||||
package io.element.android.features.preferences.impl.advanced
|
package io.element.android.features.preferences.impl.advanced
|
||||||
|
|
||||||
import io.element.android.compound.theme.Theme
|
import io.element.android.compound.theme.Theme
|
||||||
import io.element.android.libraries.architecture.AsyncAction
|
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
|
||||||
|
|
||||||
data class AdvancedSettingsState(
|
data class AdvancedSettingsState(
|
||||||
val isDeveloperModeEnabled: Boolean,
|
val isDeveloperModeEnabled: Boolean,
|
||||||
val isSharePresenceEnabled: Boolean,
|
val isSharePresenceEnabled: Boolean,
|
||||||
val theme: Theme,
|
val theme: Theme,
|
||||||
val showChangeThemeDialog: Boolean,
|
val showChangeThemeDialog: Boolean,
|
||||||
val currentPushDistributor: AsyncAction<String>,
|
|
||||||
val availablePushDistributors: ImmutableList<String>,
|
|
||||||
val showChangePushProviderDialog: Boolean,
|
|
||||||
val eventSink: (AdvancedSettingsEvents) -> Unit
|
val eventSink: (AdvancedSettingsEvents) -> Unit
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,6 @@ package io.element.android.features.preferences.impl.advanced
|
||||||
|
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
import io.element.android.compound.theme.Theme
|
import io.element.android.compound.theme.Theme
|
||||||
import io.element.android.libraries.architecture.AsyncAction
|
|
||||||
import kotlinx.collections.immutable.toImmutableList
|
|
||||||
|
|
||||||
open class AdvancedSettingsStateProvider : PreviewParameterProvider<AdvancedSettingsState> {
|
open class AdvancedSettingsStateProvider : PreviewParameterProvider<AdvancedSettingsState> {
|
||||||
override val values: Sequence<AdvancedSettingsState>
|
override val values: Sequence<AdvancedSettingsState>
|
||||||
|
|
@ -28,9 +26,6 @@ open class AdvancedSettingsStateProvider : PreviewParameterProvider<AdvancedSett
|
||||||
aAdvancedSettingsState(isDeveloperModeEnabled = true),
|
aAdvancedSettingsState(isDeveloperModeEnabled = true),
|
||||||
aAdvancedSettingsState(showChangeThemeDialog = true),
|
aAdvancedSettingsState(showChangeThemeDialog = true),
|
||||||
aAdvancedSettingsState(isSendPublicReadReceiptsEnabled = 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,
|
isDeveloperModeEnabled: Boolean = false,
|
||||||
isSendPublicReadReceiptsEnabled: Boolean = false,
|
isSendPublicReadReceiptsEnabled: Boolean = false,
|
||||||
showChangeThemeDialog: Boolean = false,
|
showChangeThemeDialog: Boolean = false,
|
||||||
currentPushDistributor: AsyncAction<String> = AsyncAction.Success("Firebase"),
|
|
||||||
availablePushDistributors: List<String> = listOf("Firebase", "ntfy"),
|
|
||||||
showChangePushProviderDialog: Boolean = false,
|
|
||||||
eventSink: (AdvancedSettingsEvents) -> Unit = {},
|
eventSink: (AdvancedSettingsEvents) -> Unit = {},
|
||||||
) = AdvancedSettingsState(
|
) = AdvancedSettingsState(
|
||||||
isDeveloperModeEnabled = isDeveloperModeEnabled,
|
isDeveloperModeEnabled = isDeveloperModeEnabled,
|
||||||
isSharePresenceEnabled = isSendPublicReadReceiptsEnabled,
|
isSharePresenceEnabled = isSendPublicReadReceiptsEnabled,
|
||||||
theme = Theme.System,
|
theme = Theme.System,
|
||||||
showChangeThemeDialog = showChangeThemeDialog,
|
showChangeThemeDialog = showChangeThemeDialog,
|
||||||
currentPushDistributor = currentPushDistributor,
|
|
||||||
availablePushDistributors = availablePushDistributors.toImmutableList(),
|
|
||||||
showChangePushProviderDialog = showChangePushProviderDialog,
|
|
||||||
eventSink = eventSink
|
eventSink = eventSink
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -16,24 +16,19 @@
|
||||||
|
|
||||||
package io.element.android.features.preferences.impl.advanced
|
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.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
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.Theme
|
||||||
import io.element.android.compound.theme.themes
|
import io.element.android.compound.theme.themes
|
||||||
import io.element.android.features.preferences.impl.R
|
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.ListOption
|
||||||
import io.element.android.libraries.designsystem.components.dialogs.SingleSelectionDialog
|
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.list.ListItemContent
|
||||||
import io.element.android.libraries.designsystem.components.preferences.PreferencePage
|
import io.element.android.libraries.designsystem.components.preferences.PreferencePage
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
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.ListItem
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
|
@ -86,34 +81,6 @@ fun AdvancedSettingsView(
|
||||||
),
|
),
|
||||||
onClick = { state.eventSink(AdvancedSettingsEvents.SetSharePresenceEnabled(!state.isSharePresenceEnabled)) }
|
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) {
|
if (state.showChangeThemeDialog) {
|
||||||
|
|
@ -130,22 +97,6 @@ fun AdvancedSettingsView(
|
||||||
onDismissRequest = { state.eventSink(AdvancedSettingsEvents.CancelChangeTheme) },
|
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
|
@Composable
|
||||||
|
|
|
||||||
|
|
@ -25,4 +25,7 @@ sealed interface NotificationSettingsEvents {
|
||||||
data object FixConfigurationMismatch : NotificationSettingsEvents
|
data object FixConfigurationMismatch : NotificationSettingsEvents
|
||||||
data object ClearConfigurationMismatchError : NotificationSettingsEvents
|
data object ClearConfigurationMismatchError : NotificationSettingsEvents
|
||||||
data object ClearNotificationChangeError : NotificationSettingsEvents
|
data object ClearNotificationChangeError : NotificationSettingsEvents
|
||||||
|
data object ChangePushProvider : NotificationSettingsEvents
|
||||||
|
data object CancelChangePushProvider : NotificationSettingsEvents
|
||||||
|
data class SetPushProvider(val index: Int) : NotificationSettingsEvents
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,17 +20,25 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import io.element.android.libraries.architecture.AsyncAction
|
import io.element.android.libraries.architecture.AsyncAction
|
||||||
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
import io.element.android.libraries.architecture.runCatchingUpdatingState
|
||||||
import io.element.android.libraries.matrix.api.MatrixClient
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
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 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.UserPushStore
|
||||||
import io.element.android.libraries.pushstore.api.UserPushStoreFactory
|
import io.element.android.libraries.pushstore.api.UserPushStoreFactory
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.FlowPreview
|
import kotlinx.coroutines.FlowPreview
|
||||||
import kotlinx.coroutines.flow.debounce
|
import kotlinx.coroutines.flow.debounce
|
||||||
|
|
@ -44,7 +52,8 @@ class NotificationSettingsPresenter @Inject constructor(
|
||||||
private val notificationSettingsService: NotificationSettingsService,
|
private val notificationSettingsService: NotificationSettingsService,
|
||||||
private val userPushStoreFactory: UserPushStoreFactory,
|
private val userPushStoreFactory: UserPushStoreFactory,
|
||||||
private val matrixClient: MatrixClient,
|
private val matrixClient: MatrixClient,
|
||||||
private val systemNotificationsEnabledProvider: SystemNotificationsEnabledProvider
|
private val pushService: PushService,
|
||||||
|
private val systemNotificationsEnabledProvider: SystemNotificationsEnabledProvider,
|
||||||
) : Presenter<NotificationSettingsState> {
|
) : Presenter<NotificationSettingsState> {
|
||||||
@Composable
|
@Composable
|
||||||
override fun present(): NotificationSettingsState {
|
override fun present(): NotificationSettingsState {
|
||||||
|
|
@ -68,6 +77,60 @@ class NotificationSettingsPresenter @Inject constructor(
|
||||||
observeNotificationSettings(matrixSettings)
|
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 }.toImmutableList()
|
||||||
|
}
|
||||||
|
|
||||||
|
var currentDistributorName by remember { mutableStateOf<AsyncData<String>>(AsyncData.Uninitialized) }
|
||||||
|
var refreshPushProvider by remember { mutableIntStateOf(0) }
|
||||||
|
|
||||||
|
LaunchedEffect(refreshPushProvider) {
|
||||||
|
val p = pushService.getCurrentPushProvider()
|
||||||
|
val name = p?.getCurrentDistributor(matrixClient)?.name
|
||||||
|
currentDistributorName = if (name != null) {
|
||||||
|
AsyncData.Success(name)
|
||||||
|
} else {
|
||||||
|
AsyncData.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 = AsyncData.Loading(currentDistributorName.dataOrNull())
|
||||||
|
data.let { (pushProvider, distributor) ->
|
||||||
|
pushService.registerWith(
|
||||||
|
matrixClient = matrixClient,
|
||||||
|
pushProvider = pushProvider,
|
||||||
|
distributor = distributor
|
||||||
|
)
|
||||||
|
.fold(
|
||||||
|
{
|
||||||
|
refreshPushProvider++
|
||||||
|
},
|
||||||
|
{
|
||||||
|
currentDistributorName = AsyncData.Failure(it)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun handleEvents(event: NotificationSettingsEvents) {
|
fun handleEvents(event: NotificationSettingsEvents) {
|
||||||
when (event) {
|
when (event) {
|
||||||
is NotificationSettingsEvents.SetAtRoomNotificationsEnabled -> {
|
is NotificationSettingsEvents.SetAtRoomNotificationsEnabled -> {
|
||||||
|
|
@ -88,6 +151,9 @@ class NotificationSettingsPresenter @Inject constructor(
|
||||||
systemNotificationsEnabled.value = systemNotificationsEnabledProvider.notificationsEnabled()
|
systemNotificationsEnabled.value = systemNotificationsEnabledProvider.notificationsEnabled()
|
||||||
}
|
}
|
||||||
NotificationSettingsEvents.ClearNotificationChangeError -> changeNotificationSettingAction.value = AsyncAction.Uninitialized
|
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
|
appNotificationsEnabled = appNotificationsEnabled.value
|
||||||
),
|
),
|
||||||
changeNotificationSettingAction = changeNotificationSettingAction.value,
|
changeNotificationSettingAction = changeNotificationSettingAction.value,
|
||||||
|
currentPushDistributor = currentDistributorName,
|
||||||
|
availablePushDistributors = distributorNames,
|
||||||
|
showChangePushProviderDialog = showChangePushProviderDialog,
|
||||||
eventSink = ::handleEvents
|
eventSink = ::handleEvents
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,18 @@ package io.element.android.features.preferences.impl.notifications
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import io.element.android.libraries.architecture.AsyncAction
|
import io.element.android.libraries.architecture.AsyncAction
|
||||||
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||||
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
|
|
||||||
@Immutable
|
@Immutable
|
||||||
data class NotificationSettingsState(
|
data class NotificationSettingsState(
|
||||||
val matrixSettings: MatrixSettings,
|
val matrixSettings: MatrixSettings,
|
||||||
val appSettings: AppSettings,
|
val appSettings: AppSettings,
|
||||||
val changeNotificationSettingAction: AsyncAction<Unit>,
|
val changeNotificationSettingAction: AsyncAction<Unit>,
|
||||||
|
val currentPushDistributor: AsyncData<String>,
|
||||||
|
val availablePushDistributors: ImmutableList<String>,
|
||||||
|
val showChangePushProviderDialog: Boolean,
|
||||||
val eventSink: (NotificationSettingsEvents) -> Unit,
|
val eventSink: (NotificationSettingsEvents) -> Unit,
|
||||||
) {
|
) {
|
||||||
sealed interface MatrixSettings {
|
sealed interface MatrixSettings {
|
||||||
|
|
@ -46,4 +51,10 @@ data class NotificationSettingsState(
|
||||||
val systemNotificationsEnabled: Boolean,
|
val systemNotificationsEnabled: Boolean,
|
||||||
val appNotificationsEnabled: Boolean,
|
val appNotificationsEnabled: Boolean,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the advanced settings should be shown.
|
||||||
|
* This is true if the current push distributor is in a failure state or if there are multiple push distributors available.
|
||||||
|
*/
|
||||||
|
val showAdvancedSettings: Boolean = currentPushDistributor.isFailure() || availablePushDistributors.size > 1
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,14 +18,26 @@ package io.element.android.features.preferences.impl.notifications
|
||||||
|
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
import io.element.android.libraries.architecture.AsyncAction
|
import io.element.android.libraries.architecture.AsyncAction
|
||||||
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||||
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
|
|
||||||
open class NotificationSettingsStateProvider : PreviewParameterProvider<NotificationSettingsState> {
|
open class NotificationSettingsStateProvider : PreviewParameterProvider<NotificationSettingsState> {
|
||||||
override val values: Sequence<NotificationSettingsState>
|
override val values: Sequence<NotificationSettingsState>
|
||||||
get() = sequenceOf(
|
get() = sequenceOf(
|
||||||
|
aValidNotificationSettingsState(systemNotificationsEnabled = false),
|
||||||
aValidNotificationSettingsState(),
|
aValidNotificationSettingsState(),
|
||||||
aValidNotificationSettingsState(changeNotificationSettingAction = AsyncAction.Loading),
|
aValidNotificationSettingsState(changeNotificationSettingAction = AsyncAction.Loading),
|
||||||
aValidNotificationSettingsState(changeNotificationSettingAction = AsyncAction.Failure(Throwable("error"))),
|
aValidNotificationSettingsState(changeNotificationSettingAction = AsyncAction.Failure(Throwable("error"))),
|
||||||
|
aValidNotificationSettingsState(
|
||||||
|
availablePushDistributors = listOf("Firebase"),
|
||||||
|
changeNotificationSettingAction = AsyncAction.Failure(Throwable("error")),
|
||||||
|
),
|
||||||
|
aValidNotificationSettingsState(availablePushDistributors = listOf("Firebase")),
|
||||||
|
aValidNotificationSettingsState(showChangePushProviderDialog = true),
|
||||||
|
aValidNotificationSettingsState(currentPushDistributor = AsyncData.Loading()),
|
||||||
|
aValidNotificationSettingsState(currentPushDistributor = AsyncData.Failure(Exception("Failed to change distributor"))),
|
||||||
aInvalidNotificationSettingsState(),
|
aInvalidNotificationSettingsState(),
|
||||||
aInvalidNotificationSettingsState(fixFailed = true),
|
aInvalidNotificationSettingsState(fixFailed = true),
|
||||||
)
|
)
|
||||||
|
|
@ -36,7 +48,11 @@ fun aValidNotificationSettingsState(
|
||||||
atRoomNotificationsEnabled: Boolean = true,
|
atRoomNotificationsEnabled: Boolean = true,
|
||||||
callNotificationsEnabled: Boolean = true,
|
callNotificationsEnabled: Boolean = true,
|
||||||
inviteForMeNotificationsEnabled: Boolean = true,
|
inviteForMeNotificationsEnabled: Boolean = true,
|
||||||
|
systemNotificationsEnabled: Boolean = true,
|
||||||
appNotificationEnabled: Boolean = true,
|
appNotificationEnabled: Boolean = true,
|
||||||
|
currentPushDistributor: AsyncData<String> = AsyncData.Success("Firebase"),
|
||||||
|
availablePushDistributors: List<String> = listOf("Firebase", "ntfy"),
|
||||||
|
showChangePushProviderDialog: Boolean = false,
|
||||||
eventSink: (NotificationSettingsEvents) -> Unit = {},
|
eventSink: (NotificationSettingsEvents) -> Unit = {},
|
||||||
) = NotificationSettingsState(
|
) = NotificationSettingsState(
|
||||||
matrixSettings = NotificationSettingsState.MatrixSettings.Valid(
|
matrixSettings = NotificationSettingsState.MatrixSettings.Valid(
|
||||||
|
|
@ -47,10 +63,13 @@ fun aValidNotificationSettingsState(
|
||||||
defaultOneToOneNotificationMode = RoomNotificationMode.ALL_MESSAGES,
|
defaultOneToOneNotificationMode = RoomNotificationMode.ALL_MESSAGES,
|
||||||
),
|
),
|
||||||
appSettings = NotificationSettingsState.AppSettings(
|
appSettings = NotificationSettingsState.AppSettings(
|
||||||
systemNotificationsEnabled = false,
|
systemNotificationsEnabled = systemNotificationsEnabled,
|
||||||
appNotificationsEnabled = appNotificationEnabled,
|
appNotificationsEnabled = appNotificationEnabled,
|
||||||
),
|
),
|
||||||
changeNotificationSettingAction = changeNotificationSettingAction,
|
changeNotificationSettingAction = changeNotificationSettingAction,
|
||||||
|
currentPushDistributor = currentPushDistributor,
|
||||||
|
availablePushDistributors = availablePushDistributors.toImmutableList(),
|
||||||
|
showChangePushProviderDialog = showChangePushProviderDialog,
|
||||||
eventSink = eventSink,
|
eventSink = eventSink,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -66,5 +85,8 @@ fun aInvalidNotificationSettingsState(
|
||||||
appNotificationsEnabled = true,
|
appNotificationsEnabled = true,
|
||||||
),
|
),
|
||||||
changeNotificationSettingAction = AsyncAction.Uninitialized,
|
changeNotificationSettingAction = AsyncAction.Uninitialized,
|
||||||
|
currentPushDistributor = AsyncData.Uninitialized,
|
||||||
|
availablePushDistributors = persistentListOf(),
|
||||||
|
showChangePushProviderDialog = false,
|
||||||
eventSink = eventSink,
|
eventSink = eventSink,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -16,27 +16,38 @@
|
||||||
|
|
||||||
package io.element.android.features.preferences.impl.notifications
|
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.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||||
import io.element.android.features.preferences.impl.R
|
import io.element.android.features.preferences.impl.R
|
||||||
import io.element.android.libraries.androidutils.system.startNotificationSettingsIntent
|
import io.element.android.libraries.androidutils.system.startNotificationSettingsIntent
|
||||||
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
import io.element.android.libraries.designsystem.atomic.molecules.DialogLikeBannerMolecule
|
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.async.AsyncActionView
|
||||||
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
|
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.PreferenceCategory
|
||||||
import io.element.android.libraries.designsystem.components.preferences.PreferencePage
|
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.PreferenceSwitch
|
||||||
import io.element.android.libraries.designsystem.components.preferences.PreferenceText
|
import io.element.android.libraries.designsystem.components.preferences.PreferenceText
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
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.designsystem.utils.OnLifecycleEvent
|
||||||
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
|
||||||
import io.element.android.libraries.ui.strings.CommonStrings
|
import io.element.android.libraries.ui.strings.CommonStrings
|
||||||
|
import kotlinx.collections.immutable.toImmutableList
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A view that allows a user edit their global notification settings.
|
* A view that allows a user edit their global notification settings.
|
||||||
|
|
@ -69,7 +80,7 @@ fun NotificationSettingsView(
|
||||||
NotificationSettingsState.MatrixSettings.Uninitialized -> return@PreferencePage
|
NotificationSettingsState.MatrixSettings.Uninitialized -> return@PreferencePage
|
||||||
is NotificationSettingsState.MatrixSettings.Valid -> NotificationSettingsContentView(
|
is NotificationSettingsState.MatrixSettings.Valid -> NotificationSettingsContentView(
|
||||||
matrixSettings = state.matrixSettings,
|
matrixSettings = state.matrixSettings,
|
||||||
systemSettings = state.appSettings,
|
state = state,
|
||||||
onNotificationsEnabledChanged = { state.eventSink(NotificationSettingsEvents.SetNotificationsEnabled(it)) },
|
onNotificationsEnabledChanged = { state.eventSink(NotificationSettingsEvents.SetNotificationsEnabled(it)) },
|
||||||
onGroupChatsClicked = { onOpenEditDefault(false) },
|
onGroupChatsClicked = { onOpenEditDefault(false) },
|
||||||
onDirectChatsClicked = { onOpenEditDefault(true) },
|
onDirectChatsClicked = { onOpenEditDefault(true) },
|
||||||
|
|
@ -92,7 +103,7 @@ fun NotificationSettingsView(
|
||||||
@Composable
|
@Composable
|
||||||
private fun NotificationSettingsContentView(
|
private fun NotificationSettingsContentView(
|
||||||
matrixSettings: NotificationSettingsState.MatrixSettings.Valid,
|
matrixSettings: NotificationSettingsState.MatrixSettings.Valid,
|
||||||
systemSettings: NotificationSettingsState.AppSettings,
|
state: NotificationSettingsState,
|
||||||
onNotificationsEnabledChanged: (Boolean) -> Unit,
|
onNotificationsEnabledChanged: (Boolean) -> Unit,
|
||||||
onGroupChatsClicked: () -> Unit,
|
onGroupChatsClicked: () -> Unit,
|
||||||
onDirectChatsClicked: () -> Unit,
|
onDirectChatsClicked: () -> Unit,
|
||||||
|
|
@ -103,6 +114,7 @@ private fun NotificationSettingsContentView(
|
||||||
onTroubleshootNotificationsClicked: () -> Unit,
|
onTroubleshootNotificationsClicked: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
val systemSettings: NotificationSettingsState.AppSettings = state.appSettings
|
||||||
if (systemSettings.appNotificationsEnabled && !systemSettings.systemNotificationsEnabled) {
|
if (systemSettings.appNotificationsEnabled && !systemSettings.systemNotificationsEnabled) {
|
||||||
PreferenceText(
|
PreferenceText(
|
||||||
icon = CompoundIcons.NotificationsOffSolid(),
|
icon = CompoundIcons.NotificationsOffSolid(),
|
||||||
|
|
@ -169,6 +181,52 @@ private fun NotificationSettingsContentView(
|
||||||
onClick = onTroubleshootNotificationsClicked
|
onClick = onTroubleshootNotificationsClicked
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (state.showAdvancedSettings) {
|
||||||
|
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) {
|
||||||
|
AsyncData.Uninitialized,
|
||||||
|
is AsyncData.Loading -> ListItemContent.Custom {
|
||||||
|
CircularProgressIndicator(
|
||||||
|
modifier = Modifier
|
||||||
|
.progressSemantics()
|
||||||
|
.size(20.dp),
|
||||||
|
strokeWidth = 2.dp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
is AsyncData.Failure -> ListItemContent.Text(
|
||||||
|
stringResource(id = CommonStrings.common_error)
|
||||||
|
)
|
||||||
|
is AsyncData.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) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ interface SystemNotificationsEnabledProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SingleIn(AppScope::class)
|
@SingleIn(AppScope::class)
|
||||||
@ContributesBinding(AppScope::class, boundType = SystemNotificationsEnabledProvider::class)
|
@ContributesBinding(AppScope::class)
|
||||||
class DefaultSystemNotificationsEnabledProvider @Inject constructor(
|
class DefaultSystemNotificationsEnabledProvider @Inject constructor(
|
||||||
@ApplicationContext private val context: Context,
|
@ApplicationContext private val context: Context,
|
||||||
) : SystemNotificationsEnabledProvider {
|
) : SystemNotificationsEnabledProvider {
|
||||||
|
|
|
||||||
|
|
@ -21,16 +21,8 @@ import app.cash.molecule.moleculeFlow
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.compound.theme.Theme
|
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.InMemoryAppPreferencesStore
|
||||||
import io.element.android.libraries.preferences.test.InMemorySessionPreferencesStore
|
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.WarmUpRule
|
||||||
import io.element.android.tests.testutils.awaitLastSequentialItem
|
import io.element.android.tests.testutils.awaitLastSequentialItem
|
||||||
import kotlinx.coroutines.test.runTest
|
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(
|
private fun createAdvancedSettingsPresenter(
|
||||||
appPreferencesStore: InMemoryAppPreferencesStore = InMemoryAppPreferencesStore(),
|
appPreferencesStore: InMemoryAppPreferencesStore = InMemoryAppPreferencesStore(),
|
||||||
sessionPreferencesStore: InMemorySessionPreferencesStore = InMemorySessionPreferencesStore(),
|
sessionPreferencesStore: InMemorySessionPreferencesStore = InMemorySessionPreferencesStore(),
|
||||||
matrixClient: MatrixClient = FakeMatrixClient(),
|
|
||||||
pushService: PushService = FakePushService(),
|
|
||||||
) = AdvancedSettingsPresenter(
|
) = AdvancedSettingsPresenter(
|
||||||
appPreferencesStore = appPreferencesStore,
|
appPreferencesStore = appPreferencesStore,
|
||||||
sessionPreferencesStore = sessionPreferencesStore,
|
sessionPreferencesStore = sessionPreferencesStore,
|
||||||
matrixClient = matrixClient,
|
|
||||||
pushService = pushService,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,6 @@ package io.element.android.features.preferences.impl.advanced
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
|
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
|
||||||
import androidx.compose.ui.test.junit4.createAndroidComposeRule
|
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 androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import io.element.android.compound.theme.Theme
|
import io.element.android.compound.theme.Theme
|
||||||
import io.element.android.features.preferences.impl.R
|
import io.element.android.features.preferences.impl.R
|
||||||
|
|
@ -34,7 +32,6 @@ import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.rules.TestRule
|
import org.junit.rules.TestRule
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.robolectric.annotation.Config
|
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
@RunWith(AndroidJUnit4::class)
|
||||||
class AdvancedSettingsViewTest {
|
class AdvancedSettingsViewTest {
|
||||||
|
|
@ -103,33 +100,6 @@ class AdvancedSettingsViewTest {
|
||||||
rule.clickOn(R.string.screen_advanced_settings_share_presence)
|
rule.clickOn(R.string.screen_advanced_settings_share_presence)
|
||||||
eventsRecorder.assertSingle(AdvancedSettingsEvents.SetSharePresenceEnabled(true))
|
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(
|
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.molecule.moleculeFlow
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import io.element.android.libraries.architecture.AsyncData
|
||||||
|
import io.element.android.libraries.matrix.api.MatrixClient
|
||||||
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_THROWABLE
|
import io.element.android.libraries.matrix.test.A_THROWABLE
|
||||||
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||||
import io.element.android.libraries.matrix.test.notificationsettings.FakeNotificationSettingsService
|
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.libraries.pushstore.test.userpushstore.FakeUserPushStoreFactory
|
||||||
|
import io.element.android.tests.testutils.awaitLastSequentialItem
|
||||||
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
|
||||||
|
|
@ -230,14 +238,95 @@ 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(AsyncData.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).isInstanceOf(AsyncData.Loading::class.java)
|
||||||
|
skipItems(1)
|
||||||
|
val lastItem = awaitItem()
|
||||||
|
assertThat(lastItem.currentPushDistributor).isEqualTo(AsyncData.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).isInstanceOf(AsyncData.Loading::class.java)
|
||||||
|
val lastItem = awaitItem()
|
||||||
|
assertThat(lastItem.currentPushDistributor).isInstanceOf(AsyncData.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(
|
private fun createNotificationSettingsPresenter(
|
||||||
notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService()
|
notificationSettingsService: FakeNotificationSettingsService = FakeNotificationSettingsService(),
|
||||||
|
pushService: PushService = FakePushService(),
|
||||||
): NotificationSettingsPresenter {
|
): NotificationSettingsPresenter {
|
||||||
val matrixClient = FakeMatrixClient(notificationSettingsService = notificationSettingsService)
|
val matrixClient = FakeMatrixClient(notificationSettingsService = notificationSettingsService)
|
||||||
return NotificationSettingsPresenter(
|
return NotificationSettingsPresenter(
|
||||||
notificationSettingsService = notificationSettingsService,
|
notificationSettingsService = notificationSettingsService,
|
||||||
userPushStoreFactory = FakeUserPushStoreFactory(),
|
userPushStoreFactory = FakeUserPushStoreFactory(),
|
||||||
matrixClient = matrixClient,
|
matrixClient = matrixClient,
|
||||||
|
pushService = pushService,
|
||||||
systemNotificationsEnabledProvider = FakeSystemNotificationsEnabledProvider(),
|
systemNotificationsEnabledProvider = FakeSystemNotificationsEnabledProvider(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ package io.element.android.features.preferences.impl.notifications
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
|
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
|
||||||
import androidx.compose.ui.test.junit4.createAndroidComposeRule
|
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 androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import io.element.android.features.preferences.impl.R
|
import io.element.android.features.preferences.impl.R
|
||||||
import io.element.android.libraries.architecture.AsyncAction
|
import io.element.android.libraries.architecture.AsyncAction
|
||||||
|
|
@ -248,6 +250,43 @@ 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.assertList(
|
||||||
|
listOf(
|
||||||
|
NotificationSettingsEvents.RefreshSystemNotificationsEnabled,
|
||||||
|
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.assertList(
|
||||||
|
listOf(
|
||||||
|
NotificationSettingsEvents.RefreshSystemNotificationsEnabled,
|
||||||
|
NotificationSettingsEvents.SetPushProvider(1),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setNotificationSettingsView(
|
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setNotificationSettingsView(
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,8 @@ sealed interface AsyncData<out T> {
|
||||||
fun isSuccess(): Boolean = this is Success<T>
|
fun isSuccess(): Boolean = this is Success<T>
|
||||||
|
|
||||||
fun isUninitialized(): Boolean = this == Uninitialized
|
fun isUninitialized(): Boolean = this == Uninitialized
|
||||||
|
|
||||||
|
fun isReady() = isSuccess() || isFailure()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend inline fun <T> MutableState<AsyncData<T>>.runCatchingUpdatingState(
|
suspend inline fun <T> MutableState<AsyncData<T>>.runCatchingUpdatingState(
|
||||||
|
|
|
||||||
|
|
@ -30,19 +30,26 @@ class FakePushService(
|
||||||
},
|
},
|
||||||
) : PushService {
|
) : PushService {
|
||||||
override suspend fun getCurrentPushProvider(): PushProvider? {
|
override suspend fun getCurrentPushProvider(): PushProvider? {
|
||||||
return availablePushProviders.firstOrNull()
|
return registeredPushProvider ?: availablePushProviders.firstOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getAvailablePushProviders(): List<PushProvider> {
|
override fun getAvailablePushProviders(): List<PushProvider> {
|
||||||
return availablePushProviders
|
return availablePushProviders
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var registeredPushProvider: PushProvider? = null
|
||||||
|
|
||||||
override suspend fun registerWith(
|
override suspend fun registerWith(
|
||||||
matrixClient: MatrixClient,
|
matrixClient: MatrixClient,
|
||||||
pushProvider: PushProvider,
|
pushProvider: PushProvider,
|
||||||
distributor: Distributor,
|
distributor: Distributor,
|
||||||
): Result<Unit> = simulateLongTask {
|
): Result<Unit> = simulateLongTask {
|
||||||
return registerWithLambda(matrixClient, pushProvider, distributor)
|
return registerWithLambda(matrixClient, pushProvider, distributor)
|
||||||
|
.also {
|
||||||
|
if (it.isSuccess) {
|
||||||
|
registeredPushProvider = pushProvider
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun testPush(): Boolean = simulateLongTask {
|
override suspend fun testPush(): Boolean = simulateLongTask {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:fde2f5bfe13c4c775cbbea215a6a4d8fe9e474f5939e41b2ae9c23238871dedb
|
oid sha256:de588d3ef8770778779d09b2f883e4327c4cc3afce98d33aab32298e32ca070a
|
||||||
size 50191
|
size 44474
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:1f20dda0c0ce1757da7014083cfa0c602eed2bd1019ddbd0566668338b6697a1
|
oid sha256:342ef5ebb8ece155939816d6ba04298b5827dd1c125891986ee3d6389c75fe64
|
||||||
size 49764
|
size 43970
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:b6fd202a1f27239b3a6d4f587538905d01bd0fcfa745262535c050e37600e71f
|
oid sha256:92ed07e7bea55582c88ca8c8f3918c1058a5f56a1f7a196fd8080c37bff6bc52
|
||||||
size 36066
|
size 35864
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:6fcca4452f2523e8ec8601efc5a2c08b85e1b198992020fce3d75799d046d68a
|
oid sha256:4219e66ccebc52570ee2193b9a4b564a8c9c370c051a8c377e4ad12a9f3f8ffb
|
||||||
size 49778
|
size 44001
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:22b20d44483d246fb0b10a96d2e243195b2c2c45df4721337c77be0f4261d596
|
|
||||||
size 42891
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:462452d822da2efa59ba1e6451d9ff8fecd9b1dc3a7c96bbae2c61be845b140f
|
|
||||||
size 49428
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:a414a44619f982494a64348f82149e2d9ac41d8a7c963135f5ec3d5eede0c4eb
|
|
||||||
size 49513
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:876406e0e009f3d874cf1b9101702c82de792b6f66d4cb0870b03dafef124afa
|
oid sha256:706666dd4351887061879359d6947daef5ce74e552784b18bd0216b233ee6048
|
||||||
size 47270
|
size 41826
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:f3576179a7bd4c23ecc0567c4f38282af12d34d93d988b17dad54a307a69699d
|
oid sha256:731f570f939af1f515f030f03420aeca39880100707e74e4ebe2e3433ac56a95
|
||||||
size 46897
|
size 41441
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:4f8372768cb4605bf5e3d889d847eb08bd71e0fee9fa62a60d99f04d583618e4
|
oid sha256:9d7cadd4ed9e918a52a7b7ab0c6416c0cb06b1d77900c68606c0f532a6b0647c
|
||||||
size 31772
|
size 31551
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:7dc86ad9c4246582c4468bcb0c0c1c566e76c56a73813d3a1040b4836f5f9ba6
|
oid sha256:ffa635614cbf5a57c4b481c99eadaf56777342090fbc26441be3e413b16ff95b
|
||||||
size 46872
|
size 41436
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:5ef2574271233ac991ea92ef9b5b00fec488ea14c3d75cc8a308bbe4b11e5a63
|
|
||||||
size 37557
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:76a2946b89cd562a090b43e14f752d61c161a3409e3169ab1e88d78e325048bd
|
|
||||||
size 46391
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:edac5e24157eaa960bcf320c3f4fdd79f0a62bf09b47b36193d9936e953d3489
|
|
||||||
size 46511
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:99305274c67826ec479cf4b6a59fa8f74c14b28a95134dc03b2a48c56978b3a4
|
oid sha256:a8bef2322de14cf0f3ad58f5f9cfca7408786df13412912f3ea8ce80260237c8
|
||||||
size 52197
|
size 46099
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:585f8dcbeef19fbba8e3cddcba7c8ec2831a704ba3fbb3cc05369d42444d919c
|
||||||
|
size 47975
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:b962fecf66081c6ec25db8e1223be414863f92c798f7b81a65a45331faeb510b
|
oid sha256:e1fc41de78e04e330a3e2fbbc0f336c4b2a16cd669fa6e27dd767765567790a2
|
||||||
size 52481
|
size 44620
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:b5ae68e5b9dcf951dbc7a77e6606daaa86eceee6b8b54c4fc5072774f149dae2
|
oid sha256:579b86c488d72d9a1b4b0e8180a7f3a06992699f69dabe03df4732ea9a8cd584
|
||||||
size 47346
|
size 44638
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:585f8dcbeef19fbba8e3cddcba7c8ec2831a704ba3fbb3cc05369d42444d919c
|
oid sha256:579b86c488d72d9a1b4b0e8180a7f3a06992699f69dabe03df4732ea9a8cd584
|
||||||
size 47975
|
size 44638
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:a8bef2322de14cf0f3ad58f5f9cfca7408786df13412912f3ea8ce80260237c8
|
||||||
|
size 46099
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:cb04bfe4a65161812715d39c5c1804a376280811d6acb4cefef70453cbec6b74
|
||||||
|
size 44791
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:a8bef2322de14cf0f3ad58f5f9cfca7408786df13412912f3ea8ce80260237c8
|
||||||
|
size 46099
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:a8bef2322de14cf0f3ad58f5f9cfca7408786df13412912f3ea8ce80260237c8
|
||||||
|
size 46099
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:b5ae68e5b9dcf951dbc7a77e6606daaa86eceee6b8b54c4fc5072774f149dae2
|
||||||
|
size 47346
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:9db8ff8c0eb9b213bf6e1be3cda89e39f56912228515d8dc81fca12bc43375d4
|
oid sha256:58998d16988946399afc639051f4f4b0952386d395444f9d2dabb815d74a5e05
|
||||||
size 48582
|
size 42254
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:e6f6367b13643ae480f3d555ea3506bc4caeddeb51c0cd20de6c906b9886e5a5
|
||||||
|
size 45015
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:4b9d896358e78ad6aa4587cc3910f264c7fe9bc3bfc29542356f60a933594ea2
|
oid sha256:588fed33aacf895de33de1740d2377f1a7d686d33ae4c7c461dade81341798ba
|
||||||
size 47822
|
size 40955
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:4eacf4ac22f6c49b96f0891bf53fcc96bd333a6b42e66c7ac12aa4be03232667
|
oid sha256:13927d3530cbe0a98fca927df5412f9c92edae99f33326f7aeb140fd73a30a78
|
||||||
size 45141
|
size 39733
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:e6f6367b13643ae480f3d555ea3506bc4caeddeb51c0cd20de6c906b9886e5a5
|
oid sha256:13927d3530cbe0a98fca927df5412f9c92edae99f33326f7aeb140fd73a30a78
|
||||||
size 45015
|
size 39733
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:58998d16988946399afc639051f4f4b0952386d395444f9d2dabb815d74a5e05
|
||||||
|
size 42254
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:c729ce75714b35fe84346e72f551b0a4e63e19b1d35285b398e69258d07da99f
|
||||||
|
size 39134
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:58998d16988946399afc639051f4f4b0952386d395444f9d2dabb815d74a5e05
|
||||||
|
size 42254
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:58998d16988946399afc639051f4f4b0952386d395444f9d2dabb815d74a5e05
|
||||||
|
size 42254
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:4eacf4ac22f6c49b96f0891bf53fcc96bd333a6b42e66c7ac12aa4be03232667
|
||||||
|
size 45141
|
||||||
Loading…
Add table
Add a link
Reference in a new issue