From 56af44b00b9c4a86b227d058f0551b1a58d70e4b Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Thu, 26 Oct 2023 18:53:42 -0400 Subject: [PATCH] - Makes sure to offer a None option on the PushNotification Distributor List - Makes sure to not ask again if the person has already replied. - Makes sure to not ask if there is no Unified Push app installed. - Moves the code to a Component instead of a Custom Screen. - Adds i18n messaging. - Uses the existing Spinner Dialog for consistency --- .../components/SelectNotificationProvider.kt | 110 ++++++++++++++++ .../loggedIn/CustomNotificationScreen.kt | 117 ------------------ .../amethyst/LocalPreferences.kt | 3 +- .../vitorpamplona/amethyst/model/Settings.kt | 3 +- .../amethyst/ui/components/TextSpinner.kt | 26 +++- .../amethyst/ui/navigation/AppNavigation.kt | 5 +- .../ui/screen/SharedPreferencesViewModel.kt | 11 +- .../ui/screen/loggedIn/NotificationScreen.kt | 5 + .../ui/screen/loggedIn/SettingsScreen.kt | 5 + app/src/main/res/values/strings.xml | 7 ++ .../components/SelectNotificationProvider.kt | 12 ++ .../loggedIn/CustomNotificationScreen.kt | 18 --- 12 files changed, 179 insertions(+), 143 deletions(-) create mode 100644 app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt delete mode 100644 app/src/fdroid/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/CustomNotificationScreen.kt create mode 100644 app/src/play/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt delete mode 100644 app/src/play/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/CustomNotificationScreen.kt diff --git a/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt b/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt new file mode 100644 index 000000000..069b549dc --- /dev/null +++ b/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt @@ -0,0 +1,110 @@ +package com.vitorpamplona.amethyst.ui.components + +import android.util.Log +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.service.notifications.PushDistributorHandler +import com.vitorpamplona.amethyst.ui.screen.SharedPreferencesViewModel +import com.vitorpamplona.amethyst.ui.screen.loggedIn.SettingsRow +import com.vitorpamplona.amethyst.ui.screen.loggedIn.SpinnerSelectionDialog +import com.vitorpamplona.amethyst.ui.screen.loggedIn.TitleExplainer +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList + +@Composable +fun SelectNotificationProvider(sharedPreferencesViewModel: SharedPreferencesViewModel) { + if (!sharedPreferencesViewModel.sharedPrefs.dontShowPushNotificationSelector) { + val context = LocalContext.current + var distributorPresent by remember { + mutableStateOf(PushDistributorHandler.savedDistributorExists()) + } + if (!distributorPresent) { + LoadDistributors() { currentDistributor, list, readableListWithExplainer -> + if (!readableListWithExplainer.isEmpty()) { + SpinnerSelectionDialog( + title = stringResource(id = R.string.select_push_server), + options = readableListWithExplainer, + onSelect = { index -> + if (list[index] == "None") { + PushDistributorHandler.forceRemoveDistributor(context) + sharedPreferencesViewModel.dontShowPushNotificationSelector() + } else { + val fullDistributorName = list[index] + PushDistributorHandler.saveDistributor(fullDistributorName) + } + distributorPresent = true + Log.d("Amethyst", "NotificationScreen: Distributor registered.") + }, + onDismiss = { + distributorPresent = true + Log.d("Amethyst", "NotificationScreen: Distributor dialog dismissed.") + } + ) + } + } + } else { + val currentDistributor = PushDistributorHandler.getSavedDistributor() + PushDistributorHandler.saveDistributor(currentDistributor) + } + } +} + +@Composable +fun LoadDistributors( + onInner: @Composable (String, ImmutableList, ImmutableList) -> Unit +) { + val currentDistributor = PushDistributorHandler.getSavedDistributor().ifBlank { null } ?: "None" + + val list = remember { + PushDistributorHandler.getInstalledDistributors().plus("None").toImmutableList() + } + + val readableListWithExplainer = + PushDistributorHandler.formattedDistributorNames() + .mapIndexed { index, name -> + TitleExplainer( + name, + stringResource(id = R.string.push_server_uses_app_explainer, list[index]) + ) + } + .plus( + TitleExplainer( + stringResource(id = R.string.push_server_none), + stringResource(id = R.string.push_server_none_explainer) + ) + ) + .toImmutableList() + + onInner( + currentDistributor, + list, + readableListWithExplainer + ) +} + +@Composable +fun PushNotificationSettingsRow(sharedPreferencesViewModel: SharedPreferencesViewModel) { + val context = LocalContext.current + + LoadDistributors() { currentDistributor, list, readableListWithExplainer -> + SettingsRow( + R.string.push_server_title, + R.string.push_server_explainer, + selectedItens = readableListWithExplainer, + selectedIndex = list.indexOf(currentDistributor) + ) { index -> + if (list[index] == "None") { + sharedPreferencesViewModel.dontShowPushNotificationSelector() + PushDistributorHandler.forceRemoveDistributor(context) + } else { + PushDistributorHandler.saveDistributor(list[index]) + } + } + } +} diff --git a/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/CustomNotificationScreen.kt b/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/CustomNotificationScreen.kt deleted file mode 100644 index a91cf4984..000000000 --- a/app/src/fdroid/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/CustomNotificationScreen.kt +++ /dev/null @@ -1,117 +0,0 @@ -package com.vitorpamplona.amethyst.ui.screen.loggedIn - -import android.util.Log -import androidx.compose.foundation.background -import androidx.compose.foundation.border -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Surface -import androidx.compose.material3.TextButton -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment.Companion.CenterHorizontally -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.window.Dialog -import com.halilibo.richtext.markdown.Markdown -import com.halilibo.richtext.ui.RichTextStyle -import com.halilibo.richtext.ui.material3.Material3RichText -import com.halilibo.richtext.ui.resolveDefaults -import com.vitorpamplona.amethyst.service.notifications.PushDistributorHandler -import com.vitorpamplona.amethyst.ui.note.UserReactionsViewModel -import com.vitorpamplona.amethyst.ui.screen.NotificationViewModel -import com.vitorpamplona.amethyst.ui.theme.HalfPadding -import kotlinx.collections.immutable.ImmutableList -import kotlinx.collections.immutable.toImmutableList - -@Composable -fun CustomNotificationScreen( - notifFeedViewModel: NotificationViewModel, - userReactionsStatsModel: UserReactionsViewModel, - accountViewModel: AccountViewModel, - nav: (String) -> Unit -) { - val pushHandler = PushDistributorHandler - var distributorPresent by remember { - mutableStateOf(pushHandler.savedDistributorExists()) - } - val list = pushHandler.getInstalledDistributors() - val readableList = pushHandler.formattedDistributorNames() - if (!distributorPresent) { - SelectPushDistributor( - distrbutorList = readableList.toImmutableList(), - onDistributorSelected = { index, name -> - val fullDistributorName = list[index] - pushHandler.saveDistributor(fullDistributorName) - Log.d("Amethyst", "NotificationScreen: Distributor registered.") - }, - onDismiss = { - distributorPresent = true - Log.d("Amethyst", "NotificationScreen: Distributor dialog dismissed.") - } - ) - } else { - val currentDistributor = pushHandler.getSavedDistributor() - pushHandler.saveDistributor(currentDistributor) - } - - NotificationScreen( - notifFeedViewModel = notifFeedViewModel, - userReactionsStatsModel = userReactionsStatsModel, - accountViewModel = accountViewModel, - nav = nav - ) -} - -@Composable -fun SelectPushDistributor( - distrbutorList: ImmutableList, - onDistributorSelected: (Int, String) -> Unit, - onDismiss: () -> Unit -) { - Dialog(onDismissRequest = onDismiss) { - Surface( - modifier = Modifier - .border( - width = Dp.Hairline, - color = MaterialTheme.colorScheme.background, - shape = CircleShape - ) - .fillMaxWidth() - ) { - Column( - modifier = Modifier - .background(MaterialTheme.colorScheme.background) - ) { - Box(modifier = Modifier.align(CenterHorizontally)) { - Material3RichText( - style = RichTextStyle().resolveDefaults() - ) { - Markdown(content = "### Select a distributor") - } - } - distrbutorList.forEachIndexed { index, distributor -> - TextButton( - onClick = { - onDistributorSelected(index, distributor) - onDismiss() - }, - modifier = HalfPadding.fillMaxWidth() - ) { - Material3RichText( - style = RichTextStyle().resolveDefaults() - ) { - Markdown(content = distributor) - } - } - } - } - } - } -} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index f545887fd..7533e3e05 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -370,7 +370,8 @@ object LocalPreferences { automaticallyStartPlayback, automaticallyShowUrlPreview, automaticallyHideNavigationBars, - automaticallyShowProfilePictures + automaticallyShowProfilePictures, + false ) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt index 2a928632e..b874ab270 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt @@ -11,7 +11,8 @@ data class Settings( val automaticallyStartPlayback: ConnectivityType = ConnectivityType.ALWAYS, val automaticallyShowUrlPreview: ConnectivityType = ConnectivityType.ALWAYS, val automaticallyHideNavigationBars: BooleanType = BooleanType.ALWAYS, - val automaticallyShowProfilePictures: ConnectivityType = ConnectivityType.ALWAYS + val automaticallyShowProfilePictures: ConnectivityType = ConnectivityType.ALWAYS, + val dontShowPushNotificationSelector: Boolean = false ) enum class ThemeType(val screenCode: Int, val resourceId: Int) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/TextSpinner.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/TextSpinner.kt index e1e1eaf6f..f55e3aa01 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/TextSpinner.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/TextSpinner.kt @@ -29,6 +29,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.Color +import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.window.Dialog import com.vitorpamplona.amethyst.ui.theme.Font14SP @@ -85,11 +86,13 @@ fun TextSpinner( @Composable fun SpinnerSelectionDialog( + title: String? = null, options: ImmutableList, onDismiss: () -> Unit, onSelect: (Int) -> Unit ) { SpinnerSelectionDialog( + title = title, options = options, onSelect = onSelect, onDismiss = onDismiss @@ -104,8 +107,7 @@ fun SpinnerSelectionDialog( Spacer(modifier = Modifier.height(5.dp)) Row( horizontalArrangement = Arrangement.Start, - modifier = Modifier - .fillMaxWidth() + modifier = Modifier.fillMaxWidth() ) { Text(text = it, color = Color.Gray, fontSize = Font14SP) } @@ -115,6 +117,7 @@ fun SpinnerSelectionDialog( @Composable fun SpinnerSelectionDialog( + title: String? = null, options: ImmutableList, onSelect: (Int) -> Unit, onDismiss: () -> Unit, @@ -126,14 +129,31 @@ fun SpinnerSelectionDialog( shape = RoundedCornerShape(5.dp) ) { LazyColumn() { + title?.let { + item { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(16.dp, 16.dp), + horizontalArrangement = Arrangement.Center + ) { + Text( + text = title, + color = MaterialTheme.colorScheme.onSurface, + fontWeight = FontWeight.Bold + ) + } + Divider(color = Color.LightGray, thickness = 0.25.dp) + } + } itemsIndexed(options) { index, item -> Row( modifier = Modifier .fillMaxWidth() - .padding(16.dp, 16.dp) .clickable { onSelect(index) } + .padding(16.dp, 16.dp) ) { Column() { onRenderItem(item) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt index 57cba335e..380d5f2d6 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/navigation/AppNavigation.kt @@ -38,13 +38,13 @@ import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChatroomListScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChatroomScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.ChatroomScreenByAuthor import com.vitorpamplona.amethyst.ui.screen.loggedIn.CommunityScreen -import com.vitorpamplona.amethyst.ui.screen.loggedIn.CustomNotificationScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.DiscoverScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.GeoHashScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.HashtagScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.HiddenUsersScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.HomeScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.LoadRedirectScreen +import com.vitorpamplona.amethyst.ui.screen.loggedIn.NotificationScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.ProfileScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.SearchScreen import com.vitorpamplona.amethyst.ui.screen.loggedIn.SettingsScreen @@ -157,9 +157,10 @@ fun AppNavigation( Route.Notification.let { route -> composable(route.route, route.arguments, content = { - CustomNotificationScreen( + NotificationScreen( notifFeedViewModel = notifFeedViewModel, userReactionsStatsModel = userReactionsStatsModel, + sharedPreferencesViewModel = sharedPreferencesViewModel, accountViewModel = accountViewModel, nav = nav ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/SharedPreferencesViewModel.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/SharedPreferencesViewModel.kt index 7907e6485..6eb61fc0d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/SharedPreferencesViewModel.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/SharedPreferencesViewModel.kt @@ -30,6 +30,7 @@ class SettingsState() { var automaticallyShowUrlPreview by mutableStateOf(ConnectivityType.ALWAYS) var automaticallyHideNavigationBars by mutableStateOf(BooleanType.ALWAYS) var automaticallyShowProfilePictures by mutableStateOf(ConnectivityType.ALWAYS) + var dontShowPushNotificationSelector by mutableStateOf(false) var isOnMobileData: State = mutableStateOf(false) @@ -152,6 +153,13 @@ class SharedPreferencesViewModel : ViewModel() { } } + fun dontShowPushNotificationSelector() { + if (!sharedPrefs.dontShowPushNotificationSelector) { + sharedPrefs.dontShowPushNotificationSelector = true + saveSharedSettings() + } + } + fun updateConnectivityStatusState(isOnMobileDataState: State) { if (sharedPrefs.isOnMobileData != isOnMobileDataState) { sharedPrefs.isOnMobileData = isOnMobileDataState @@ -177,7 +185,8 @@ class SharedPreferencesViewModel : ViewModel() { sharedPrefs.automaticallyStartPlayback, sharedPrefs.automaticallyShowUrlPreview, sharedPrefs.automaticallyHideNavigationBars, - sharedPrefs.automaticallyShowProfilePictures + sharedPrefs.automaticallyShowProfilePictures, + sharedPrefs.dontShowPushNotificationSelector ) ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NotificationScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NotificationScreen.kt index 5e56c5f0f..d48cf9aa4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NotificationScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/NotificationScreen.kt @@ -47,6 +47,7 @@ import com.patrykandpatrick.vico.core.chart.line.LineChart import com.patrykandpatrick.vico.core.chart.values.ChartValues import com.patrykandpatrick.vico.core.component.shape.shader.DynamicShaders import com.vitorpamplona.amethyst.service.NostrAccountDataSource +import com.vitorpamplona.amethyst.ui.components.SelectNotificationProvider import com.vitorpamplona.amethyst.ui.navigation.Route import com.vitorpamplona.amethyst.ui.note.OneGiga import com.vitorpamplona.amethyst.ui.note.OneKilo @@ -57,6 +58,7 @@ import com.vitorpamplona.amethyst.ui.note.showCount import com.vitorpamplona.amethyst.ui.screen.NotificationViewModel import com.vitorpamplona.amethyst.ui.screen.RefresheableCardView import com.vitorpamplona.amethyst.ui.screen.ScrollStateKeys +import com.vitorpamplona.amethyst.ui.screen.SharedPreferencesViewModel import com.vitorpamplona.amethyst.ui.theme.BitcoinOrange import com.vitorpamplona.amethyst.ui.theme.RoyalBlue import com.vitorpamplona.amethyst.ui.theme.chartStyle @@ -69,9 +71,12 @@ import kotlin.math.roundToInt fun NotificationScreen( notifFeedViewModel: NotificationViewModel, userReactionsStatsModel: UserReactionsViewModel, + sharedPreferencesViewModel: SharedPreferencesViewModel, accountViewModel: AccountViewModel, nav: (String) -> Unit ) { + SelectNotificationProvider(sharedPreferencesViewModel) + WatchAccountForNotifications(notifFeedViewModel, accountViewModel) CheckifItNeedsToRequestNotificationPermission() diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt index 4eb472654..abdea0aa1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt @@ -41,6 +41,7 @@ import com.vitorpamplona.amethyst.model.ThemeType import com.vitorpamplona.amethyst.model.parseBooleanType import com.vitorpamplona.amethyst.model.parseConnectivityType import com.vitorpamplona.amethyst.model.parseThemeType +import com.vitorpamplona.amethyst.ui.components.PushNotificationSettingsRow import com.vitorpamplona.amethyst.ui.screen.SharedPreferencesViewModel import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.ui.theme.HalfVertSpacer @@ -217,6 +218,10 @@ fun SettingsScreen( ) { sharedPreferencesViewModel.updateAutomaticallyHideNavBars(parseBooleanType(it)) } + + Spacer(modifier = HalfVertSpacer) + + PushNotificationSettingsRow(sharedPreferencesViewModel) } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b03b64456..81720bada 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -645,4 +645,11 @@ Unable to create a lightning invoice before sending the zap. Element pr not found in the resulting JSON. Read-only user No reactions setup + + Select a Push Notification distributor + Push Notification + From installed UnifiedPush apps + None + Disables Push Notifications + Uses app %1$s diff --git a/app/src/play/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt b/app/src/play/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt new file mode 100644 index 000000000..1b7525dc0 --- /dev/null +++ b/app/src/play/java/com/vitorpamplona/amethyst/ui/components/SelectNotificationProvider.kt @@ -0,0 +1,12 @@ +package com.vitorpamplona.amethyst.ui.components + +import androidx.compose.runtime.Composable +import com.vitorpamplona.amethyst.ui.screen.SharedPreferencesViewModel + +@Composable +fun SelectNotificationProvider(sharedPreferencesViewModel: SharedPreferencesViewModel) { +} + +@Composable +fun PushNotificationSettingsRow(sharedPreferencesViewModel: SharedPreferencesViewModel) { +} diff --git a/app/src/play/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/CustomNotificationScreen.kt b/app/src/play/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/CustomNotificationScreen.kt deleted file mode 100644 index fd56ec9ae..000000000 --- a/app/src/play/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/CustomNotificationScreen.kt +++ /dev/null @@ -1,18 +0,0 @@ -package com.vitorpamplona.amethyst.ui.screen.loggedIn - -import androidx.compose.runtime.Composable -import com.vitorpamplona.amethyst.ui.note.UserReactionsViewModel -import com.vitorpamplona.amethyst.ui.screen.NotificationViewModel - -@Composable -fun CustomNotificationScreen( - notifFeedViewModel: NotificationViewModel, - userReactionsStatsModel: UserReactionsViewModel, - accountViewModel: AccountViewModel, - nav: (String) -> Unit -) = NotificationScreen( - notifFeedViewModel = notifFeedViewModel, - userReactionsStatsModel = userReactionsStatsModel, - accountViewModel = accountViewModel, - nav = nav -)