Skip to content

Commit 17678ad

Browse files
authored
Merge pull request #2928 from element-hq/feature/bma/movePushSetting
Move push provider setting
2 parents f74032d + 35a02a2 commit 17678ad

File tree

52 files changed

+376
-317
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+376
-317
lines changed

changelog.d/2912.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Move push provider setting to the "Notifications" screen and display it only when several push provider are available.

features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsEvents.kt

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,4 @@ sealed interface AdvancedSettingsEvents {
2424
data object ChangeTheme : AdvancedSettingsEvents
2525
data object CancelChangeTheme : AdvancedSettingsEvents
2626
data class SetTheme(val theme: Theme) : AdvancedSettingsEvents
27-
data object ChangePushProvider : AdvancedSettingsEvents
28-
data object CancelChangePushProvider : AdvancedSettingsEvents
29-
data class SetPushProvider(val index: Int) : AdvancedSettingsEvents
3027
}

features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsPresenter.kt

Lines changed: 0 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,8 @@
1717
package io.element.android.features.preferences.impl.advanced
1818

1919
import androidx.compose.runtime.Composable
20-
import androidx.compose.runtime.LaunchedEffect
2120
import androidx.compose.runtime.collectAsState
2221
import androidx.compose.runtime.getValue
23-
import androidx.compose.runtime.mutableIntStateOf
2422
import androidx.compose.runtime.mutableStateOf
2523
import androidx.compose.runtime.remember
2624
import androidx.compose.runtime.rememberCoroutineScope
@@ -29,22 +27,13 @@ import io.element.android.compound.theme.Theme
2927
import io.element.android.compound.theme.mapToTheme
3028
import io.element.android.features.preferences.api.store.AppPreferencesStore
3129
import io.element.android.features.preferences.api.store.SessionPreferencesStore
32-
import io.element.android.libraries.architecture.AsyncAction
3330
import io.element.android.libraries.architecture.Presenter
34-
import io.element.android.libraries.matrix.api.MatrixClient
35-
import io.element.android.libraries.push.api.PushService
36-
import io.element.android.libraries.pushproviders.api.Distributor
37-
import io.element.android.libraries.pushproviders.api.PushProvider
38-
import kotlinx.collections.immutable.toImmutableList
39-
import kotlinx.coroutines.CoroutineScope
4031
import kotlinx.coroutines.launch
4132
import javax.inject.Inject
4233

4334
class AdvancedSettingsPresenter @Inject constructor(
4435
private val appPreferencesStore: AppPreferencesStore,
4536
private val sessionPreferencesStore: SessionPreferencesStore,
46-
private val matrixClient: MatrixClient,
47-
private val pushService: PushService,
4837
) : Presenter<AdvancedSettingsState> {
4938
@Composable
5039
override fun present(): AdvancedSettingsState {
@@ -61,61 +50,6 @@ class AdvancedSettingsPresenter @Inject constructor(
6150
.collectAsState(initial = Theme.System)
6251
var showChangeThemeDialog by remember { mutableStateOf(false) }
6352

64-
// List of PushProvider -> Distributor
65-
val distributors = remember {
66-
pushService.getAvailablePushProviders()
67-
.flatMap { pushProvider ->
68-
pushProvider.getDistributors().map { distributor ->
69-
pushProvider to distributor
70-
}
71-
}
72-
}
73-
// List of Distributor names
74-
val distributorNames = remember {
75-
distributors.map { it.second.name }
76-
}
77-
78-
var currentDistributorName by remember { mutableStateOf<AsyncAction<String>>(AsyncAction.Uninitialized) }
79-
var refreshPushProvider by remember { mutableIntStateOf(0) }
80-
81-
LaunchedEffect(refreshPushProvider) {
82-
val p = pushService.getCurrentPushProvider()
83-
val name = p?.getCurrentDistributor(matrixClient)?.name
84-
currentDistributorName = if (name != null) {
85-
AsyncAction.Success(name)
86-
} else {
87-
AsyncAction.Failure(Exception("Failed to get current push provider"))
88-
}
89-
}
90-
91-
var showChangePushProviderDialog by remember { mutableStateOf(false) }
92-
93-
fun CoroutineScope.changePushProvider(
94-
data: Pair<PushProvider, Distributor>?
95-
) = launch {
96-
showChangePushProviderDialog = false
97-
data ?: return@launch
98-
// No op if the value is the same.
99-
if (data.second.name == currentDistributorName.dataOrNull()) return@launch
100-
currentDistributorName = AsyncAction.Loading
101-
data.let { (pushProvider, distributor) ->
102-
pushService.registerWith(
103-
matrixClient = matrixClient,
104-
pushProvider = pushProvider,
105-
distributor = distributor
106-
)
107-
.fold(
108-
{
109-
currentDistributorName = AsyncAction.Success(distributor.name)
110-
refreshPushProvider++
111-
},
112-
{
113-
currentDistributorName = AsyncAction.Failure(it)
114-
}
115-
)
116-
}
117-
}
118-
11953
fun handleEvents(event: AdvancedSettingsEvents) {
12054
when (event) {
12155
is AdvancedSettingsEvents.SetDeveloperModeEnabled -> localCoroutineScope.launch {
@@ -130,9 +64,6 @@ class AdvancedSettingsPresenter @Inject constructor(
13064
appPreferencesStore.setTheme(event.theme.name)
13165
showChangeThemeDialog = false
13266
}
133-
AdvancedSettingsEvents.ChangePushProvider -> showChangePushProviderDialog = true
134-
AdvancedSettingsEvents.CancelChangePushProvider -> showChangePushProviderDialog = false
135-
is AdvancedSettingsEvents.SetPushProvider -> localCoroutineScope.changePushProvider(distributors.getOrNull(event.index))
13667
}
13768
}
13869

@@ -141,9 +72,6 @@ class AdvancedSettingsPresenter @Inject constructor(
14172
isSharePresenceEnabled = isSharePresenceEnabled,
14273
theme = theme,
14374
showChangeThemeDialog = showChangeThemeDialog,
144-
currentPushDistributor = currentDistributorName,
145-
availablePushDistributors = distributorNames.toImmutableList(),
146-
showChangePushProviderDialog = showChangePushProviderDialog,
14775
eventSink = { handleEvents(it) }
14876
)
14977
}

features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsState.kt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,11 @@
1717
package io.element.android.features.preferences.impl.advanced
1818

1919
import io.element.android.compound.theme.Theme
20-
import io.element.android.libraries.architecture.AsyncAction
21-
import kotlinx.collections.immutable.ImmutableList
2220

2321
data class AdvancedSettingsState(
2422
val isDeveloperModeEnabled: Boolean,
2523
val isSharePresenceEnabled: Boolean,
2624
val theme: Theme,
2725
val showChangeThemeDialog: Boolean,
28-
val currentPushDistributor: AsyncAction<String>,
29-
val availablePushDistributors: ImmutableList<String>,
30-
val showChangePushProviderDialog: Boolean,
3126
val eventSink: (AdvancedSettingsEvents) -> Unit
3227
)

features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsStateProvider.kt

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ package io.element.android.features.preferences.impl.advanced
1818

1919
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
2020
import io.element.android.compound.theme.Theme
21-
import io.element.android.libraries.architecture.AsyncAction
22-
import kotlinx.collections.immutable.toImmutableList
2321

2422
open class AdvancedSettingsStateProvider : PreviewParameterProvider<AdvancedSettingsState> {
2523
override val values: Sequence<AdvancedSettingsState>
@@ -28,27 +26,18 @@ open class AdvancedSettingsStateProvider : PreviewParameterProvider<AdvancedSett
2826
aAdvancedSettingsState(isDeveloperModeEnabled = true),
2927
aAdvancedSettingsState(showChangeThemeDialog = true),
3028
aAdvancedSettingsState(isSendPublicReadReceiptsEnabled = true),
31-
aAdvancedSettingsState(showChangePushProviderDialog = true),
32-
aAdvancedSettingsState(currentPushDistributor = AsyncAction.Loading),
33-
aAdvancedSettingsState(currentPushDistributor = AsyncAction.Failure(Exception("Failed to change distributor"))),
3429
)
3530
}
3631

3732
fun aAdvancedSettingsState(
3833
isDeveloperModeEnabled: Boolean = false,
3934
isSendPublicReadReceiptsEnabled: Boolean = false,
4035
showChangeThemeDialog: Boolean = false,
41-
currentPushDistributor: AsyncAction<String> = AsyncAction.Success("Firebase"),
42-
availablePushDistributors: List<String> = listOf("Firebase", "ntfy"),
43-
showChangePushProviderDialog: Boolean = false,
4436
eventSink: (AdvancedSettingsEvents) -> Unit = {},
4537
) = AdvancedSettingsState(
4638
isDeveloperModeEnabled = isDeveloperModeEnabled,
4739
isSharePresenceEnabled = isSendPublicReadReceiptsEnabled,
4840
theme = Theme.System,
4941
showChangeThemeDialog = showChangeThemeDialog,
50-
currentPushDistributor = currentPushDistributor,
51-
availablePushDistributors = availablePushDistributors.toImmutableList(),
52-
showChangePushProviderDialog = showChangePushProviderDialog,
5342
eventSink = eventSink
5443
)

features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/advanced/AdvancedSettingsView.kt

Lines changed: 0 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,19 @@
1616

1717
package io.element.android.features.preferences.impl.advanced
1818

19-
import androidx.compose.foundation.layout.size
20-
import androidx.compose.foundation.progressSemantics
2119
import androidx.compose.runtime.Composable
2220
import androidx.compose.ui.Modifier
2321
import androidx.compose.ui.res.stringResource
2422
import androidx.compose.ui.tooling.preview.PreviewParameter
25-
import androidx.compose.ui.unit.dp
2623
import io.element.android.compound.theme.Theme
2724
import io.element.android.compound.theme.themes
2825
import io.element.android.features.preferences.impl.R
29-
import io.element.android.libraries.architecture.AsyncAction
3026
import io.element.android.libraries.designsystem.components.dialogs.ListOption
3127
import io.element.android.libraries.designsystem.components.dialogs.SingleSelectionDialog
3228
import io.element.android.libraries.designsystem.components.list.ListItemContent
3329
import io.element.android.libraries.designsystem.components.preferences.PreferencePage
3430
import io.element.android.libraries.designsystem.preview.ElementPreview
3531
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
36-
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
3732
import io.element.android.libraries.designsystem.theme.components.ListItem
3833
import io.element.android.libraries.designsystem.theme.components.Text
3934
import io.element.android.libraries.ui.strings.CommonStrings
@@ -86,34 +81,6 @@ fun AdvancedSettingsView(
8681
),
8782
onClick = { state.eventSink(AdvancedSettingsEvents.SetSharePresenceEnabled(!state.isSharePresenceEnabled)) }
8883
)
89-
ListItem(
90-
headlineContent = {
91-
Text(text = stringResource(id = R.string.screen_advanced_settings_push_provider_android))
92-
},
93-
trailingContent = when (state.currentPushDistributor) {
94-
AsyncAction.Uninitialized,
95-
AsyncAction.Confirming,
96-
AsyncAction.Loading -> ListItemContent.Custom {
97-
CircularProgressIndicator(
98-
modifier = Modifier
99-
.progressSemantics()
100-
.size(20.dp),
101-
strokeWidth = 2.dp
102-
)
103-
}
104-
is AsyncAction.Failure -> ListItemContent.Text(
105-
stringResource(id = CommonStrings.common_error)
106-
)
107-
is AsyncAction.Success -> ListItemContent.Text(
108-
state.currentPushDistributor.dataOrNull() ?: ""
109-
)
110-
},
111-
onClick = {
112-
if (state.currentPushDistributor.isReady()) {
113-
state.eventSink(AdvancedSettingsEvents.ChangePushProvider)
114-
}
115-
}
116-
)
11784
}
11885

11986
if (state.showChangeThemeDialog) {
@@ -130,22 +97,6 @@ fun AdvancedSettingsView(
13097
onDismissRequest = { state.eventSink(AdvancedSettingsEvents.CancelChangeTheme) },
13198
)
13299
}
133-
134-
if (state.showChangePushProviderDialog) {
135-
SingleSelectionDialog(
136-
title = stringResource(id = R.string.screen_advanced_settings_choose_distributor_dialog_title_android),
137-
options = state.availablePushDistributors.map {
138-
ListOption(title = it)
139-
}.toImmutableList(),
140-
initialSelection = state.availablePushDistributors.indexOf(state.currentPushDistributor.dataOrNull()),
141-
onOptionSelected = { index ->
142-
state.eventSink(
143-
AdvancedSettingsEvents.SetPushProvider(index)
144-
)
145-
},
146-
onDismissRequest = { state.eventSink(AdvancedSettingsEvents.CancelChangePushProvider) },
147-
)
148-
}
149100
}
150101

151102
@Composable

features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsEvents.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,7 @@ sealed interface NotificationSettingsEvents {
2525
data object FixConfigurationMismatch : NotificationSettingsEvents
2626
data object ClearConfigurationMismatchError : NotificationSettingsEvents
2727
data object ClearNotificationChangeError : NotificationSettingsEvents
28+
data object ChangePushProvider : NotificationSettingsEvents
29+
data object CancelChangePushProvider : NotificationSettingsEvents
30+
data class SetPushProvider(val index: Int) : NotificationSettingsEvents
2831
}

features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/notifications/NotificationSettingsPresenter.kt

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,25 @@ import androidx.compose.runtime.Composable
2020
import androidx.compose.runtime.LaunchedEffect
2121
import androidx.compose.runtime.MutableState
2222
import androidx.compose.runtime.collectAsState
23+
import androidx.compose.runtime.getValue
24+
import androidx.compose.runtime.mutableIntStateOf
2325
import androidx.compose.runtime.mutableStateOf
2426
import androidx.compose.runtime.remember
2527
import androidx.compose.runtime.rememberCoroutineScope
28+
import androidx.compose.runtime.setValue
2629
import io.element.android.libraries.architecture.AsyncAction
30+
import io.element.android.libraries.architecture.AsyncData
2731
import io.element.android.libraries.architecture.Presenter
2832
import io.element.android.libraries.architecture.runCatchingUpdatingState
2933
import io.element.android.libraries.matrix.api.MatrixClient
3034
import io.element.android.libraries.matrix.api.notificationsettings.NotificationSettingsService
3135
import io.element.android.libraries.matrix.api.room.RoomNotificationMode
36+
import io.element.android.libraries.push.api.PushService
37+
import io.element.android.libraries.pushproviders.api.Distributor
38+
import io.element.android.libraries.pushproviders.api.PushProvider
3239
import io.element.android.libraries.pushstore.api.UserPushStore
3340
import io.element.android.libraries.pushstore.api.UserPushStoreFactory
41+
import kotlinx.collections.immutable.toImmutableList
3442
import kotlinx.coroutines.CoroutineScope
3543
import kotlinx.coroutines.FlowPreview
3644
import kotlinx.coroutines.flow.debounce
@@ -44,7 +52,8 @@ class NotificationSettingsPresenter @Inject constructor(
4452
private val notificationSettingsService: NotificationSettingsService,
4553
private val userPushStoreFactory: UserPushStoreFactory,
4654
private val matrixClient: MatrixClient,
47-
private val systemNotificationsEnabledProvider: SystemNotificationsEnabledProvider
55+
private val pushService: PushService,
56+
private val systemNotificationsEnabledProvider: SystemNotificationsEnabledProvider,
4857
) : Presenter<NotificationSettingsState> {
4958
@Composable
5059
override fun present(): NotificationSettingsState {
@@ -68,6 +77,60 @@ class NotificationSettingsPresenter @Inject constructor(
6877
observeNotificationSettings(matrixSettings)
6978
}
7079

80+
// List of PushProvider -> Distributor
81+
val distributors = remember {
82+
pushService.getAvailablePushProviders()
83+
.flatMap { pushProvider ->
84+
pushProvider.getDistributors().map { distributor ->
85+
pushProvider to distributor
86+
}
87+
}
88+
}
89+
// List of Distributor names
90+
val distributorNames = remember {
91+
distributors.map { it.second.name }.toImmutableList()
92+
}
93+
94+
var currentDistributorName by remember { mutableStateOf<AsyncData<String>>(AsyncData.Uninitialized) }
95+
var refreshPushProvider by remember { mutableIntStateOf(0) }
96+
97+
LaunchedEffect(refreshPushProvider) {
98+
val p = pushService.getCurrentPushProvider()
99+
val name = p?.getCurrentDistributor(matrixClient)?.name
100+
currentDistributorName = if (name != null) {
101+
AsyncData.Success(name)
102+
} else {
103+
AsyncData.Failure(Exception("Failed to get current push provider"))
104+
}
105+
}
106+
107+
var showChangePushProviderDialog by remember { mutableStateOf(false) }
108+
109+
fun CoroutineScope.changePushProvider(
110+
data: Pair<PushProvider, Distributor>?
111+
) = launch {
112+
showChangePushProviderDialog = false
113+
data ?: return@launch
114+
// No op if the value is the same.
115+
if (data.second.name == currentDistributorName.dataOrNull()) return@launch
116+
currentDistributorName = AsyncData.Loading(currentDistributorName.dataOrNull())
117+
data.let { (pushProvider, distributor) ->
118+
pushService.registerWith(
119+
matrixClient = matrixClient,
120+
pushProvider = pushProvider,
121+
distributor = distributor
122+
)
123+
.fold(
124+
{
125+
refreshPushProvider++
126+
},
127+
{
128+
currentDistributorName = AsyncData.Failure(it)
129+
}
130+
)
131+
}
132+
}
133+
71134
fun handleEvents(event: NotificationSettingsEvents) {
72135
when (event) {
73136
is NotificationSettingsEvents.SetAtRoomNotificationsEnabled -> {
@@ -88,6 +151,9 @@ class NotificationSettingsPresenter @Inject constructor(
88151
systemNotificationsEnabled.value = systemNotificationsEnabledProvider.notificationsEnabled()
89152
}
90153
NotificationSettingsEvents.ClearNotificationChangeError -> changeNotificationSettingAction.value = AsyncAction.Uninitialized
154+
NotificationSettingsEvents.ChangePushProvider -> showChangePushProviderDialog = true
155+
NotificationSettingsEvents.CancelChangePushProvider -> showChangePushProviderDialog = false
156+
is NotificationSettingsEvents.SetPushProvider -> localCoroutineScope.changePushProvider(distributors.getOrNull(event.index))
91157
}
92158
}
93159

@@ -98,6 +164,9 @@ class NotificationSettingsPresenter @Inject constructor(
98164
appNotificationsEnabled = appNotificationsEnabled.value
99165
),
100166
changeNotificationSettingAction = changeNotificationSettingAction.value,
167+
currentPushDistributor = currentDistributorName,
168+
availablePushDistributors = distributorNames,
169+
showChangePushProviderDialog = showChangePushProviderDialog,
101170
eventSink = ::handleEvents
102171
)
103172
}

0 commit comments

Comments
 (0)