Push notifications UI is done, code still needs to be checked.

This commit is contained in:
hayk888997
2026-02-10 03:05:21 +04:00
parent 43ebf99e71
commit 0ef46a718e
3 changed files with 133 additions and 43 deletions
@@ -8,7 +8,9 @@ import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.text.AnnotatedString
import dev.icerock.moko.resources.compose.painterResource
import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
@@ -31,28 +33,46 @@ fun SetNotificationsMode(m: ChatModel) {
CompositionLocalProvider(LocalAppBarHandler provides rememberAppBarHandler()) {
ModalView({}, showClose = false) {
ColumnWithScrollBar(Modifier.themedBackground(bgLayerSize = LocalAppBarHandler.current?.backgroundGraphicsLayerSize, bgLayer = LocalAppBarHandler.current?.backgroundGraphicsLayer)) {
Box(Modifier.align(Alignment.CenterHorizontally)) {
AppBarTitle(stringResource(MR.strings.onboarding_notifications_mode_title), bottomPadding = DEFAULT_PADDING)
}
val currentMode = rememberSaveable { mutableStateOf(NotificationsMode.default) }
Column(Modifier.padding(horizontal = DEFAULT_ONBOARDING_HORIZONTAL_PADDING).fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
Column(
Modifier
.fillMaxWidth()
.padding(horizontal = DEFAULT_ONBOARDING_HORIZONTAL_PADDING)
.padding(top = DEFAULT_PADDING),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = stringResource(MR.strings.onboarding_notifications_mode_title),
style = MaterialTheme.typography.h1,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colors.onBackground,
textAlign = TextAlign.Center
)
Spacer(Modifier.height(DEFAULT_PADDING))
OnboardingInformationButton(
stringResource(MR.strings.onboarding_notifications_mode_subtitle),
onClick = { ModalManager.fullscreen.showModalCloseable { NotificationBatteryUsageInfo() } }
)
}
Spacer(Modifier.weight(1f))
Column(Modifier.padding(horizontal = DEFAULT_ONBOARDING_HORIZONTAL_PADDING)) {
SelectableCard(currentMode, NotificationsMode.SERVICE, stringResource(MR.strings.onboarding_notifications_mode_service), annotatedStringResource(MR.strings.onboarding_notifications_mode_service_desc_short)) {
currentMode.value = NotificationsMode.SERVICE
}
SelectableCard(currentMode, NotificationsMode.PERIODIC, stringResource(MR.strings.onboarding_notifications_mode_periodic), annotatedStringResource(MR.strings.onboarding_notifications_mode_periodic_desc_short)) {
currentMode.value = NotificationsMode.PERIODIC
}
SelectableCard(currentMode, NotificationsMode.OFF, stringResource(MR.strings.onboarding_notifications_mode_off), annotatedStringResource(MR.strings.onboarding_notifications_mode_off_desc_short)) {
currentMode.value = NotificationsMode.OFF
}
// Notification options with connecting line
Column(
Modifier
.fillMaxWidth()
.padding(horizontal = DEFAULT_ONBOARDING_HORIZONTAL_PADDING),
horizontalAlignment = Alignment.CenterHorizontally
) {
NotificationOptionsWithConnector(
currentMode = currentMode,
onModeSelected = { currentMode.value = it }
)
}
Spacer(Modifier.weight(1f))
Column(Modifier.widthIn(max = if (appPlatform.isAndroid) 450.dp else 1000.dp).align(Alignment.CenterHorizontally), horizontalAlignment = Alignment.CenterHorizontally) {
OnboardingActionButton(
@@ -77,31 +97,99 @@ fun SetNotificationsMode(m: ChatModel) {
expect fun SetNotificationsModeAdditions()
@Composable
fun <T> SelectableCard(currentValue: State<T>, newValue: T, title: String, description: AnnotatedString, onSelected: (T) -> Unit) {
TextButton(
onClick = { onSelected(newValue) },
border = BorderStroke(1.dp, color = if (currentValue.value == newValue) MaterialTheme.colors.primary else MaterialTheme.colors.secondary.copy(alpha = 0.5f)),
shape = RoundedCornerShape(35.dp),
private fun NotificationOptionsWithConnector(
currentMode: State<NotificationsMode>,
onModeSelected: (NotificationsMode) -> Unit
) {
val options = listOf(
NotificationsMode.SERVICE to (stringResource(MR.strings.onboarding_notifications_mode_service) to annotatedStringResource(MR.strings.onboarding_notifications_mode_service_desc_short)),
NotificationsMode.PERIODIC to (stringResource(MR.strings.onboarding_notifications_mode_periodic) to annotatedStringResource(MR.strings.onboarding_notifications_mode_periodic_desc_short)),
NotificationsMode.OFF to (stringResource(MR.strings.onboarding_notifications_mode_off) to annotatedStringResource(MR.strings.onboarding_notifications_mode_off_desc_short))
)
val iconResByMode = mapOf(
NotificationsMode.SERVICE to MR.images.ic_bolt_filled,
NotificationsMode.PERIODIC to MR.images.ic_schedule,
NotificationsMode.OFF to MR.images.ic_refresh
)
Column(
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Column(Modifier.padding(horizontal = 10.dp).padding(top = 4.dp, bottom = 8.dp).fillMaxWidth()) {
Text(
title,
style = MaterialTheme.typography.h3,
fontWeight = FontWeight.Medium,
color = if (currentValue.value == newValue) MaterialTheme.colors.primary else MaterialTheme.colors.secondary,
modifier = Modifier.padding(bottom = 8.dp).align(Alignment.CenterHorizontally),
textAlign = TextAlign.Center
)
Text(description,
Modifier.align(Alignment.CenterHorizontally),
fontSize = 15.sp,
color = MaterialTheme.colors.onBackground,
lineHeight = 24.sp,
textAlign = TextAlign.Center
options.forEachIndexed { index, (mode, titleDesc) ->
val (title, description) = titleDesc
SelectableCard(
currentValue = currentMode,
newValue = mode,
title = title,
description = description,
onSelected = { onModeSelected(mode) },
icon = painterResource(iconResByMode[mode]!!)
)
if (index < options.size - 1) {
Spacer(Modifier.height(16.dp))
}
}
}
}
@Composable
fun <T> SelectableCard(
currentValue: State<T>,
newValue: T,
title: String,
description: AnnotatedString,
onSelected: (T) -> Unit,
icon: Painter? = null
) {
val isSelected = currentValue.value == newValue
val borderColor = if (isSelected) MaterialTheme.colors.primary else MaterialTheme.colors.secondary.copy(alpha = 0.5f)
val titleColor = if (isSelected) MaterialTheme.colors.primary else MaterialTheme.colors.secondary
val iconTint = if (isSelected) MaterialTheme.colors.primary else MaterialTheme.colors.secondary
TextButton(
onClick = { onSelected(newValue) },
border = BorderStroke(2.dp, color = borderColor),
shape = RoundedCornerShape(18.dp),
modifier = Modifier.fillMaxWidth()
) {
Row(
Modifier
.padding(horizontal = 12.dp)
.padding(vertical = 8.dp)
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically
) {
if (icon != null) {
Icon(
painter = icon,
contentDescription = null,
tint = iconTint,
modifier = Modifier.size(24.dp)
)
Spacer(Modifier.width(12.dp))
}
Column {
Text(
title,
style = MaterialTheme.typography.h4,
fontWeight = FontWeight.Bold,
color = titleColor,
textAlign = TextAlign.Start
)
Text(
description,
fontSize = 15.sp,
color = MaterialTheme.colors.onBackground,
lineHeight = 20.sp,
textAlign = TextAlign.Start
)
}
}
}
Spacer(Modifier.height(14.dp))
}
@Composable
@@ -190,7 +190,8 @@ fun OnboardingInformationButton(
Icon(
painterResource(MR.images.ic_info),
null,
tint = MaterialTheme.colors.primary
tint = MaterialTheme.colors.primary,
modifier = Modifier.size(22.dp)
)
// https://issuetracker.google.com/issues/206039942#comment32
var textLayoutResult: TextLayoutResult? by remember { mutableStateOf(null) }
@@ -219,6 +220,7 @@ fun OnboardingInformationButton(
textLayoutResult = it
},
style = MaterialTheme.typography.button,
fontWeight = FontWeight.Bold,
color = MaterialTheme.colors.primary
)
}
@@ -1324,18 +1324,18 @@
<string name="read_more_in_github_with_link"><![CDATA[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">How it affects battery</string>
<string name="onboarding_notifications_mode_off">When app is running</string>
<string name="use_chat">OK</string>
<string name="onboarding_notifications_mode_title">Push notifications</string>
<string name="onboarding_notifications_mode_subtitle">How it affects privacy</string>
<string name="onboarding_notifications_mode_off">No push server</string>
<string name="onboarding_notifications_mode_periodic">Periodic</string>
<string name="onboarding_notifications_mode_service">Instant</string>
<string name="onboarding_notifications_mode_off_desc"><![CDATA[<b>Best for battery</b>. You will receive notifications only when the app is running (NO background service).]]></string>
<string name="onboarding_notifications_mode_off_desc_short">No background service</string>
<string name="onboarding_notifications_mode_off_desc_short">Check messages when allowed.</string>
<string name="onboarding_notifications_mode_periodic_desc"><![CDATA[<b>Good for battery</b>. App checks messages every 10 minutes. You may miss calls or urgent messages.]]></string>
<string name="onboarding_notifications_mode_periodic_desc_short">Check messages every 10 minutes</string>
<string name="onboarding_notifications_mode_periodic_desc_short">Check messages every 20 min.</string>
<string name="onboarding_notifications_mode_service_desc"><![CDATA[<b>Uses more battery</b>! App always runs in background notifications are shown instantly.]]></string>
<string name="onboarding_notifications_mode_service_desc_short">App always runs in background</string>
<string name="onboarding_notifications_mode_service_desc_short">E2E encrypted notifications.</string>
<string name="onboarding_notifications_mode_battery">Notifications and battery</string>
<!-- SetupDatabasePassphrase.kt -->