android: install-permission sheet before updating as in the Final 2026 mockup

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
DenozordecandClaude Opus 5.5 committed 2026-10-12 14:42:18 +07:00
1 parent 92e2f4f069
commit 15ad5c1151
4 files changed
+85 -2

No files matched your search

@@ -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))
}
}
}
}
@@ -175,6 +175,7 @@ fun SettingsScreen(profiles: List<VpnProfile>, 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<VpnProfile>, 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 */
@@ -1129,4 +1129,12 @@
<string name="connect_step_tunnel">Туннель и маршруты</string>
<string name="home_connect_step">%1$s · шаг %2$d из 4</string>
<string name="home_connecting">Подключаемся…</string>
<string name="install_perm_title">Разрешите установку обновлений</string>
<string name="install_perm_text">SHX VPN обновляется сам, без Google Play. Android один раз спросит, можно ли приложению устанавливать обновления.</string>
<string name="install_perm_preview">Вы увидите такой экран</string>
<string name="install_perm_switch">Разрешить установку из этого источника</string>
<string name="install_perm_hint">Включите переключатель и нажмите «Назад» — установка продолжится.</string>
<string name="install_perm_safe">Безопасно: приложение ставит только файлы с подписью SHX и проверенной контрольной суммой.</string>
<string name="install_perm_later">Не сейчас</string>
<string name="install_perm_open">Открыть разрешение</string>
</resources>
@@ -1115,4 +1115,12 @@
<string name="connect_step_tunnel">Tunnel and routes</string>
<string name="home_connect_step">%1$s · step %2$d of 4</string>
<string name="home_connecting">Connecting…</string>
<string name="install_perm_title">Allow installing updates</string>
<string name="install_perm_text">SHX VPN updates itself, without Google Play. Android asks once whether the app may install updates.</string>
<string name="install_perm_preview">You will see this screen</string>
<string name="install_perm_switch">Allow from this source</string>
<string name="install_perm_hint">Turn the switch on and tap «Back» — the installation continues.</string>
<string name="install_perm_safe">Safe: the app only installs files signed by SHX with a verified checksum.</string>
<string name="install_perm_later">Not now</string>
<string name="install_perm_open">Open permission</string>
</resources>