diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/compose/SettingsPages.kt b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/compose/SettingsPages.kt index 945ec4f48..053f2bfef 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/compose/SettingsPages.kt +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/compose/SettingsPages.kt @@ -524,3 +524,59 @@ private fun NotifRow(title: String, sub: String, tag: NotifTag, key: String?, di Box(Modifier.fillMaxWidth().height(1.dp).background(c.tile)) } } + +/** «Allow installing updates» sheet (F_UpdateInstall), before the system page opens. */ +@Composable +internal fun InstallPermissionSheet(onOpen: () -> Unit, onDismiss: () -> Unit) +{ + val c = LocalShxColors.current + org.strongswan.android.ui.compose.design.ShxSheet(onDismiss = onDismiss) + { + Column(verticalArrangement = Arrangement.spacedBy(14.dp)) + { + Column(verticalArrangement = Arrangement.spacedBy(6.dp), modifier = Modifier.padding(horizontal = 4.dp)) + { + Text(stringResource(R.string.install_perm_title), style = ShxType.sheetTitle, color = c.text) + Text(stringResource(R.string.install_perm_text), style = ShxType.note.copy(fontSize = 14.sp, lineHeight = 21.sp, fontWeight = FontWeight.Normal), color = c.textSoft) + } + ShxPanel(padding = androidx.compose.foundation.layout.PaddingValues(horizontal = 16.dp, vertical = 14.dp)) + { + Column(verticalArrangement = Arrangement.spacedBy(10.dp)) + { + Text(stringResource(R.string.install_perm_preview).uppercase(), style = ShxType.section.copy(fontSize = 12.sp), color = c.accentText) + Row( + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(12.dp), + modifier = Modifier.fillMaxWidth().clip(RoundedCornerShape(16.dp)).background(c.tile).padding(horizontal = 12.dp, vertical = 10.dp), + ) + { + Column(Modifier.weight(1f), verticalArrangement = Arrangement.spacedBy(2.dp)) + { + Text(stringResource(R.string.install_perm_switch), style = ShxType.body.copy(fontWeight = FontWeight.Bold), color = c.text) + Text("SHX VPN", style = ShxType.meta.copy(fontWeight = FontWeight.Normal), color = c.textSub) + } + /* a picture of the system switch, not a control */ + Box(Modifier.size(44.dp, 26.dp).clip(RoundedCornerShape(13.dp)).background(c.accent).padding(3.dp), contentAlignment = Alignment.CenterEnd) + { + Box(Modifier.size(20.dp).clip(CircleShape).background(Color.White)) + } + } + Text(stringResource(R.string.install_perm_hint), style = ShxType.note.copy(lineHeight = 19.sp, fontWeight = FontWeight.Normal), color = c.textSoft) + } + } + Row( + horizontalArrangement = Arrangement.spacedBy(10.dp), + modifier = Modifier.fillMaxWidth().clip(RoundedCornerShape(18.dp)).background(c.successContainer).padding(horizontal = 14.dp, vertical = 12.dp), + ) + { + Icon(ShxIcons.Shield, contentDescription = null, tint = c.onSuccess, modifier = Modifier.size(20.dp)) + Text(stringResource(R.string.install_perm_safe), style = ShxType.note.copy(lineHeight = 19.sp, fontWeight = FontWeight.Normal), color = c.onSuccess) + } + Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) + { + ShxButton(stringResource(R.string.install_perm_later), onDismiss, style = ShxButtonStyle.OUTLINE, modifier = Modifier.weight(1f)) + ShxButton(stringResource(R.string.install_perm_open), onOpen, modifier = Modifier.weight(2f)) + } + } + } +} diff --git a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/compose/SettingsScreen.kt b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/compose/SettingsScreen.kt index a92841387..6b5f42204 100644 --- a/src/frontends/android/app/src/main/java/org/strongswan/android/ui/compose/SettingsScreen.kt +++ b/src/frontends/android/app/src/main/java/org/strongswan/android/ui/compose/SettingsScreen.kt @@ -175,6 +175,7 @@ fun SettingsScreen(profiles: List, showTitle: Boolean = true) val updateManager = remember { UpdateManager.getInstance(context) } val updateState by updateManager.state.collectAsStateWithLifecycle() var showUpdateConfirm by remember { mutableStateOf(false) } + var showInstallPermission by remember { mutableStateOf(false) } val snackbarHostState = remember { SnackbarHostState() } val scope = rememberCoroutineScope() @@ -196,10 +197,20 @@ fun SettingsScreen(profiles: List, showTitle: Boolean = true) updateManager.downloadAndInstall() } else - { - unknownSourcesLauncher.launch(UpdateInstaller.createInstallPermissionIntent(context)) + { /* F_UpdateInstall explains the system page first */ + showInstallPermission = true } } + if (showInstallPermission) + { + InstallPermissionSheet( + onOpen = { + showInstallPermission = false + unknownSourcesLauncher.launch(UpdateInstaller.createInstallPermissionIntent(context)) + }, + onDismiss = { showInstallPermission = false }, + ) + } var pageState by rememberSaveable { mutableStateOf(SettingsPage.ROOT) } /* from a sub page "back" returns to the settings list, not out of the tab */ diff --git a/src/frontends/android/app/src/main/res/values-ru/strings.xml b/src/frontends/android/app/src/main/res/values-ru/strings.xml index c16707033..46099049d 100644 --- a/src/frontends/android/app/src/main/res/values-ru/strings.xml +++ b/src/frontends/android/app/src/main/res/values-ru/strings.xml @@ -1129,4 +1129,12 @@ Туннель и маршруты %1$s · шаг %2$d из 4 Подключаемся… + Разрешите установку обновлений + SHX VPN обновляется сам, без Google Play. Android один раз спросит, можно ли приложению устанавливать обновления. + Вы увидите такой экран + Разрешить установку из этого источника + Включите переключатель и нажмите «Назад» — установка продолжится. + Безопасно: приложение ставит только файлы с подписью SHX и проверенной контрольной суммой. + Не сейчас + Открыть разрешение diff --git a/src/frontends/android/app/src/main/res/values/strings.xml b/src/frontends/android/app/src/main/res/values/strings.xml index 478bc3486..ab39acf60 100644 --- a/src/frontends/android/app/src/main/res/values/strings.xml +++ b/src/frontends/android/app/src/main/res/values/strings.xml @@ -1115,4 +1115,12 @@ Tunnel and routes %1$s · step %2$d of 4 Connecting… + Allow installing updates + SHX VPN updates itself, without Google Play. Android asks once whether the app may install updates. + You will see this screen + Allow from this source + Turn the switch on and tap «Back» — the installation continues. + Safe: the app only installs files signed by SHX with a verified checksum. + Not now + Open permission