From bd4c7dffbf71ac49353914d114c4fcd30573c467 Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Mon, 12 Dec 2022 22:27:28 +0300 Subject: [PATCH] android: Notification mode selection in onboarding stage (#1535) * android: Notification mode selection in onboarding stage * Change * Different texts * Disable service starting until on-boarding finishes * refactor, change strings * update layout * update layout Co-authored-by: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> --- .../java/chat/simplex/app/MainActivity.kt | 1 + .../main/java/chat/simplex/app/SimplexApp.kt | 6 +- .../java/chat/simplex/app/model/SimpleXAPI.kt | 3 + .../chat/simplex/app/views/WelcomeView.kt | 4 +- .../app/views/onboarding/OnboardingView.kt | 1 + .../views/onboarding/SetNotificationsMode.kt | 68 +++++++++++++++++++ .../app/views/onboarding/SimpleXInfo.kt | 7 +- .../usersettings/NotificationsSettingsView.kt | 43 ++++++------ .../app/src/main/res/values-de/strings.xml | 2 +- .../app/src/main/res/values-ru/strings.xml | 3 + .../app/src/main/res/values/strings.xml | 11 +++ 11 files changed, 119 insertions(+), 30 deletions(-) create mode 100644 apps/android/app/src/main/java/chat/simplex/app/views/onboarding/SetNotificationsMode.kt diff --git a/apps/android/app/src/main/java/chat/simplex/app/MainActivity.kt b/apps/android/app/src/main/java/chat/simplex/app/MainActivity.kt index 0aabca7ee8..556c5e2fed 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/MainActivity.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/MainActivity.kt @@ -395,6 +395,7 @@ fun MainPage( } onboarding == OnboardingStage.Step1_SimpleXInfo -> SimpleXInfo(chatModel, onboarding = true) onboarding == OnboardingStage.Step2_CreateProfile -> CreateProfile(chatModel) + onboarding == OnboardingStage.Step3_SetNotificationsMode -> SetNotificationsMode(chatModel) } ModalManager.shared.showInView() val invitation = chatModel.activeCallInvitation.value diff --git a/apps/android/app/src/main/java/chat/simplex/app/SimplexApp.kt b/apps/android/app/src/main/java/chat/simplex/app/SimplexApp.kt index 0139143a58..d45dc24550 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/SimplexApp.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/SimplexApp.kt @@ -115,8 +115,12 @@ class SimplexApp: Application(), LifecycleEventObserver { * after calling [ChatController.showBackgroundServiceNoticeIfNeeded] notification mode in prefs can be changed. * It can happen when app was started and a user enables battery optimization while app in background * */ - if (chatModel.chatRunning.value != false && appPreferences.notificationsMode.get() == NotificationsMode.SERVICE.name) + if (chatModel.chatRunning.value != false && + chatModel.onboardingStage.value == OnboardingStage.OnboardingComplete && + appPreferences.notificationsMode.get() == NotificationsMode.SERVICE.name + ) { SimplexService.start(applicationContext) + } } else -> isAppOnForeground = false } diff --git a/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt b/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt index 30f5bd2fe3..440cfb4ebf 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/model/SimpleXAPI.kt @@ -1249,6 +1249,9 @@ open class ChatController(var ctrl: ChatCtrl?, val ntfManager: NtfManager, val a fun showBackgroundServiceNoticeIfNeeded() { val mode = NotificationsMode.valueOf(appPrefs.notificationsMode.get()!!) Log.d(TAG, "showBackgroundServiceNoticeIfNeeded") + // Nothing to do if mode is OFF. Can be selected on on-boarding stage + if (mode == NotificationsMode.OFF) return + if (!appPrefs.backgroundServiceNoticeShown.get()) { // the branch for the new users who have never seen service notice if (!mode.requiresIgnoringBattery || isIgnoringBatteryOptimizations(appContext)) { diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/WelcomeView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/WelcomeView.kt index 4ed162ec02..75bf2e1fd4 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/WelcomeView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/WelcomeView.kt @@ -111,9 +111,7 @@ fun createProfile(chatModel: ChatModel, displayName: String, fullName: String) { Profile(displayName, fullName, null) ) chatModel.controller.startChat(user) - chatModel.controller.showBackgroundServiceNoticeIfNeeded() - SimplexService.start(chatModel.controller.appContext) - chatModel.onboardingStage.value = OnboardingStage.OnboardingComplete + chatModel.onboardingStage.value = OnboardingStage.Step3_SetNotificationsMode } } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/onboarding/OnboardingView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/onboarding/OnboardingView.kt index 08435f75e7..ffc18d9021 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/onboarding/OnboardingView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/onboarding/OnboardingView.kt @@ -16,6 +16,7 @@ import kotlinx.coroutines.launch enum class OnboardingStage { Step1_SimpleXInfo, Step2_CreateProfile, + Step3_SetNotificationsMode, OnboardingComplete } diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/onboarding/SetNotificationsMode.kt b/apps/android/app/src/main/java/chat/simplex/app/views/onboarding/SetNotificationsMode.kt new file mode 100644 index 0000000000..a96f517208 --- /dev/null +++ b/apps/android/app/src/main/java/chat/simplex/app/views/onboarding/SetNotificationsMode.kt @@ -0,0 +1,68 @@ +package chat.simplex.app.views.onboarding + +import androidx.annotation.StringRes +import androidx.compose.foundation.* +import androidx.compose.foundation.layout.* +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.* +import androidx.compose.runtime.* +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import chat.simplex.app.R +import chat.simplex.app.model.ChatModel +import chat.simplex.app.ui.theme.* +import chat.simplex.app.views.helpers.* +import chat.simplex.app.views.usersettings.NotificationsMode +import chat.simplex.app.views.usersettings.changeNotificationsMode + +@Composable +fun SetNotificationsMode(m: ChatModel) { + Column( + Modifier + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .padding(20.dp) + ) { + AppBarTitle(stringResource(R.string.onboarding_notifications_mode_title), false) + val currentMode = rememberSaveable { mutableStateOf(NotificationsMode.default) } + Text(stringResource(R.string.onboarding_notifications_mode_subtitle)) + Spacer(Modifier.padding(DEFAULT_PADDING_HALF)) + NotificationButton(currentMode, NotificationsMode.OFF, R.string.onboarding_notifications_mode_off, R.string.onboarding_notifications_mode_off_desc) + NotificationButton(currentMode, NotificationsMode.PERIODIC, R.string.onboarding_notifications_mode_periodic, R.string.onboarding_notifications_mode_periodic_desc) + NotificationButton(currentMode, NotificationsMode.SERVICE, R.string.onboarding_notifications_mode_service, R.string.onboarding_notifications_mode_service_desc) + Spacer(Modifier.fillMaxHeight().weight(1f)) + Box(Modifier.fillMaxWidth().padding(bottom = 16.dp), contentAlignment = Alignment.Center) { + OnboardingActionButton(R.string.use_chat, OnboardingStage.OnboardingComplete, m.onboardingStage) { + changeNotificationsMode(currentMode.value, m) + } + } + Spacer(Modifier.fillMaxHeight().weight(1f)) + } +} + +@Composable +private fun NotificationButton(currentMode: MutableState, mode: NotificationsMode, @StringRes title: Int, @StringRes description: Int) { + TextButton( + onClick = { currentMode.value = mode }, + border = BorderStroke(1.dp, color = if (currentMode.value == mode) MaterialTheme.colors.primary else HighOrLowlight.copy(alpha = 0.5f)), + shape = RoundedCornerShape(15.dp), + ) { + Column(Modifier.padding(bottom = 6.dp).padding(horizontal = 8.dp)) { + Text( + stringResource(title), + style = MaterialTheme.typography.h2, + fontWeight = FontWeight.Medium, + color = if (currentMode.value == mode) MaterialTheme.colors.primary else HighOrLowlight, + modifier = Modifier.padding(bottom = 4.dp) + ) + Text(annotatedStringResource(description), color = MaterialTheme.colors.onBackground, lineHeight = 24.sp) + } + } + Spacer(Modifier.height(DEFAULT_PADDING)) +} diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/onboarding/SimpleXInfo.kt b/apps/android/app/src/main/java/chat/simplex/app/views/onboarding/SimpleXInfo.kt index 89b1114ce1..5576150c6e 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/onboarding/SimpleXInfo.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/onboarding/SimpleXInfo.kt @@ -25,7 +25,6 @@ import chat.simplex.app.model.ChatModel import chat.simplex.app.model.User import chat.simplex.app.ui.theme.* import chat.simplex.app.views.helpers.ModalManager -import chat.simplex.app.views.helpers.generalGetString @Composable fun SimpleXInfo(chatModel: ChatModel, onboarding: Boolean = true) { @@ -105,14 +104,14 @@ private fun InfoRow(icon: Painter, @StringRes titleId: Int, @StringRes textId: I @Composable fun OnboardingActionButton(user: User?, onboardingStage: MutableState, onclick: (() -> Unit)? = null) { if (user == null) { - ActionButton(R.string.create_your_profile, onboarding = OnboardingStage.Step2_CreateProfile, onboardingStage, onclick) + OnboardingActionButton(R.string.create_your_profile, onboarding = OnboardingStage.Step2_CreateProfile, onboardingStage, onclick) } else { - ActionButton(R.string.make_private_connection, onboarding = OnboardingStage.OnboardingComplete, onboardingStage, onclick) + OnboardingActionButton(R.string.make_private_connection, onboarding = OnboardingStage.OnboardingComplete, onboardingStage, onclick) } } @Composable -private fun ActionButton( +fun OnboardingActionButton( @StringRes labelId: Int, onboarding: OnboardingStage?, onboardingStage: MutableState, diff --git a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/NotificationsSettingsView.kt b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/NotificationsSettingsView.kt index 6206979e75..8f56be3c33 100644 --- a/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/NotificationsSettingsView.kt +++ b/apps/android/app/src/main/java/chat/simplex/app/views/usersettings/NotificationsSettingsView.kt @@ -46,25 +46,6 @@ enum class NotificationPreviewMode { fun NotificationsSettingsView( chatModel: ChatModel, ) { - val onNotificationsModeSelected = { mode: NotificationsMode -> - chatModel.controller.appPrefs.notificationsMode.set(mode.name) - if (mode.requiresIgnoringBattery && !chatModel.controller.isIgnoringBatteryOptimizations(chatModel.controller.appContext)) { - chatModel.controller.appPrefs.backgroundServiceNoticeShown.set(false) - } - chatModel.notificationsMode.value = mode - SimplexService.StartReceiver.toggleReceiver(mode == NotificationsMode.SERVICE) - CoroutineScope(Dispatchers.Default).launch { - if (mode == NotificationsMode.SERVICE) - SimplexService.start(SimplexApp.context) - else - SimplexService.safeStopService(SimplexApp.context) - } - - if (mode != NotificationsMode.PERIODIC) { - MessagesFetcherWorker.cancelAll() - } - chatModel.controller.showBackgroundServiceNoticeIfNeeded() - } val onNotificationPreviewModeSelected = { mode: NotificationPreviewMode -> chatModel.controller.appPrefs.notificationPreviewMode.set(mode.name) chatModel.notificationPreviewMode.value = mode @@ -76,7 +57,7 @@ fun NotificationsSettingsView( showPage = { page -> ModalManager.shared.showModalCloseable(true) { when (page) { - CurrentPage.NOTIFICATIONS_MODE -> NotificationsModeView(chatModel.notificationsMode, onNotificationsModeSelected) + CurrentPage.NOTIFICATIONS_MODE -> NotificationsModeView(chatModel.notificationsMode) { changeNotificationsMode(it, chatModel) } CurrentPage.NOTIFICATION_PREVIEW_MODE -> NotificationPreviewView(chatModel.notificationPreviewMode, onNotificationPreviewModeSelected) } } @@ -159,7 +140,7 @@ fun NotificationPreviewView( } // mode, name, description -fun notificationModes(): List> { +private fun notificationModes(): List> { val res = ArrayList>() res.add( ValueTitleDesc( @@ -211,3 +192,23 @@ fun notificationPreviewModes(): List> { ) return res } + +fun changeNotificationsMode(mode: NotificationsMode, chatModel: ChatModel) { + chatModel.controller.appPrefs.notificationsMode.set(mode.name) + if (mode.requiresIgnoringBattery && !chatModel.controller.isIgnoringBatteryOptimizations(chatModel.controller.appContext)) { + chatModel.controller.appPrefs.backgroundServiceNoticeShown.set(false) + } + chatModel.notificationsMode.value = mode + SimplexService.StartReceiver.toggleReceiver(mode == NotificationsMode.SERVICE) + CoroutineScope(Dispatchers.Default).launch { + if (mode == NotificationsMode.SERVICE) + SimplexService.start(SimplexApp.context) + else + SimplexService.safeStopService(SimplexApp.context) + } + + if (mode != NotificationsMode.PERIODIC) { + MessagesFetcherWorker.cancelAll() + } + chatModel.controller.showBackgroundServiceNoticeIfNeeded() +} diff --git a/apps/android/app/src/main/res/values-de/strings.xml b/apps/android/app/src/main/res/values-de/strings.xml index 5be348eccb..9c325922b5 100644 --- a/apps/android/app/src/main/res/values-de/strings.xml +++ b/apps/android/app/src/main/res/values-de/strings.xml @@ -905,4 +905,4 @@ In dieser Gruppe ist das unwiederbringliche Löschen von Nachrichten verboten. Gruppenmitglieder können Sprachnachrichten senden. In dieser Gruppe sind Sprachnachrichten untersagt. - \ No newline at end of file + diff --git a/apps/android/app/src/main/res/values-ru/strings.xml b/apps/android/app/src/main/res/values-ru/strings.xml index 772d3a912a..b69aed78b5 100644 --- a/apps/android/app/src/main/res/values-ru/strings.xml +++ b/apps/android/app/src/main/res/values-ru/strings.xml @@ -545,6 +545,9 @@ Узнайте больше из нашего GitHub репозитория. Узнайте больше из нашего GitHub репозитория. + + Использовать чат + Вставить полученную ссылку diff --git a/apps/android/app/src/main/res/values/strings.xml b/apps/android/app/src/main/res/values/strings.xml index 4863d5e273..bb3bb545ca 100644 --- a/apps/android/app/src/main/res/values/strings.xml +++ b/apps/android/app/src/main/res/values/strings.xml @@ -545,6 +545,17 @@ Read more in our GitHub repository. Read more in our GitHub repository. + + Use chat + Private notifications + It can be changed later via settings. + When app is running + Periodic + Instant + Best for battery. You will receive notifications only when the app is running, background service will NOT be used. + Good for battery. Background service checks for new messages every 10 minutes. You may miss calls and urgent messages. + Uses more battery! Background service is always running – notifications will be shown as soon as the messages are available. + Paste received link