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>
This commit is contained in:
Stanislav Dmitrenko
2022-12-12 22:27:28 +03:00
committed by GitHub
parent 1eb4030080
commit bd4c7dffbf
11 changed files with 119 additions and 30 deletions

View File

@@ -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

View File

@@ -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
}

View File

@@ -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)) {

View File

@@ -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
}
}

View File

@@ -16,6 +16,7 @@ import kotlinx.coroutines.launch
enum class OnboardingStage {
Step1_SimpleXInfo,
Step2_CreateProfile,
Step3_SetNotificationsMode,
OnboardingComplete
}

View File

@@ -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<NotificationsMode>, 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))
}

View File

@@ -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<OnboardingStage?>, 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<OnboardingStage?>,

View File

@@ -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<ValueTitleDesc<NotificationsMode>> {
private fun notificationModes(): List<ValueTitleDesc<NotificationsMode>> {
val res = ArrayList<ValueTitleDesc<NotificationsMode>>()
res.add(
ValueTitleDesc(
@@ -211,3 +192,23 @@ fun notificationPreviewModes(): List<ValueTitleDesc<NotificationPreviewMode>> {
)
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()
}

View File

@@ -905,4 +905,4 @@
<string name="message_deletion_prohibited_in_chat">In dieser Gruppe ist das unwiederbringliche Löschen von Nachrichten verboten.</string>
<string name="group_members_can_send_voice">Gruppenmitglieder können Sprachnachrichten senden.</string>
<string name="voice_messages_are_prohibited">In dieser Gruppe sind Sprachnachrichten untersagt.</string>
</resources>
</resources>

View File

@@ -545,6 +545,9 @@
<string name="read_more_in_github">Узнайте больше из нашего GitHub репозитория.</string>
<string name="read_more_in_github_with_link">Узнайте больше из нашего <font color="#0088ff">GitHub репозитория</font>.</string>
<!-- SetNotificationsMode.kt -->
<string name="use_chat">Использовать чат</string>
<!-- MakeConnection -->
<string name="paste_the_link_you_received">Вставить полученную ссылку</string>

View File

@@ -545,6 +545,17 @@
<string name="read_more_in_github">Read more in our GitHub repository.</string>
<string name="read_more_in_github_with_link">Read more in our <font color="#0088ff">GitHub repository</font>.</string>
<!-- SetNotificationsMode.kt -->
<string name="use_chat">Use chat</string>
<string name="onboarding_notifications_mode_title">Private notifications</string>
<string name="onboarding_notifications_mode_subtitle">It can be changed later via settings.</string>
<string name="onboarding_notifications_mode_off">When app is running</string>
<string name="onboarding_notifications_mode_periodic">Periodic</string>
<string name="onboarding_notifications_mode_service">Instant</string>
<string name="onboarding_notifications_mode_off_desc"><b>Best for battery</b>. You will receive notifications only when the app is running, background service will NOT be used.</string>
<string name="onboarding_notifications_mode_periodic_desc"><b>Good for battery</b>. Background service checks for new messages every 10 minutes. You may miss calls and urgent messages.</string>
<string name="onboarding_notifications_mode_service_desc"><b>Uses more battery</b>! Background service is always running notifications will be shown as soon as the messages are available.</string>
<!-- MakeConnection -->
<string name="paste_the_link_you_received">Paste received link</string>