android: all dialogs in the Final 2026 look (28dp card, 22/800 title, 50% scrim), login fields as form fields
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ffa38d5f28
commit
9c96c36fc6
8 files changed
+102
-33
No files matched your search
+2
-2
@@ -25,7 +25,7 @@ import android.widget.Toast
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import org.strongswan.android.ui.compose.design.ShxAlertDialog
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.getValue
|
||||
@@ -175,7 +175,7 @@ class TrustedCertificateImportActivity : AppCompatActivity()
|
||||
@androidx.compose.runtime.Composable
|
||||
private fun ConfirmImportUi(certificate: X509Certificate)
|
||||
{
|
||||
AlertDialog(
|
||||
ShxAlertDialog(
|
||||
onDismissRequest = { finish() },
|
||||
title = { Text(stringResource(R.string.import_certificate)) },
|
||||
text = { Text(certificate.getSubjectDN().toString()) },
|
||||
|
||||
+2
-2
@@ -31,7 +31,7 @@ import androidx.compose.material.icons.rounded.Remove
|
||||
import androidx.compose.material.icons.rounded.Public
|
||||
import androidx.compose.material.icons.rounded.Speed
|
||||
import androidx.compose.material.icons.rounded.Timer
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import org.strongswan.android.ui.compose.design.ShxAlertDialog
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
@@ -252,7 +252,7 @@ fun ConnectivityCheckScreen()
|
||||
if (showIntervalPicker)
|
||||
{
|
||||
val options = listOf(15, 30, 60, 300)
|
||||
AlertDialog(
|
||||
ShxAlertDialog(
|
||||
onDismissRequest = { showIntervalPicker = false },
|
||||
title = { Text(stringResource(R.string.health_check_interval)) },
|
||||
text = {
|
||||
|
||||
+2
-2
@@ -71,7 +71,7 @@ import androidx.compose.material.icons.rounded.Share
|
||||
import androidx.compose.material.icons.rounded.SignalCellularAlt
|
||||
import androidx.compose.material.icons.rounded.Edit
|
||||
import androidx.compose.material.icons.rounded.Wifi
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import org.strongswan.android.ui.compose.design.ShxAlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||
@@ -425,7 +425,7 @@ fun HomeScreen(
|
||||
}
|
||||
|
||||
pendingDelete?.let { profile ->
|
||||
AlertDialog(
|
||||
ShxAlertDialog(
|
||||
onDismissRequest = { pendingDelete = null },
|
||||
title = { Text(stringResource(R.string.delete_profile)) },
|
||||
text = { Text(profile.name ?: "") },
|
||||
|
||||
+6
-6
@@ -45,7 +45,7 @@ import androidx.compose.material.icons.rounded.Security
|
||||
import androidx.compose.material.icons.rounded.SystemUpdateAlt
|
||||
import androidx.compose.material.icons.rounded.VerifiedUser
|
||||
import androidx.compose.material.icons.rounded.Wifi
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import org.strongswan.android.ui.compose.design.ShxAlertDialog
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.RadioButton
|
||||
import androidx.compose.material3.Text
|
||||
@@ -551,7 +551,7 @@ fun SettingsScreen(profiles: List<VpnProfile>, showTitle: Boolean = true)
|
||||
{
|
||||
val options = listOf(Constants.PREF_DEFAULT_VPN_PROFILE_MRU to context.getString(R.string.pref_default_vpn_profile_mru)) +
|
||||
profiles.map { it.getUUID().toString() to (it.name ?: "") }
|
||||
AlertDialog(
|
||||
ShxAlertDialog(
|
||||
onDismissRequest = { showDefaultPicker = false },
|
||||
title = { Text(stringResource(R.string.pref_default_vpn_profile)) },
|
||||
text = {
|
||||
@@ -586,7 +586,7 @@ fun SettingsScreen(profiles: List<VpnProfile>, showTitle: Boolean = true)
|
||||
if (showCrl)
|
||||
{
|
||||
val files = remember(showCrl) { context.fileList().filter { it.startsWith("crl-") } }
|
||||
AlertDialog(
|
||||
ShxAlertDialog(
|
||||
onDismissRequest = { showCrl = false },
|
||||
title = { Text(stringResource(R.string.clear_crl_cache_title)) },
|
||||
text = {
|
||||
@@ -620,7 +620,7 @@ fun SettingsScreen(profiles: List<VpnProfile>, showTitle: Boolean = true)
|
||||
{
|
||||
val info = (updateState as UpdateState.Available).info
|
||||
val notes = info.notes["ru"] ?: info.notes["en"] ?: info.notes.values.firstOrNull() ?: ""
|
||||
AlertDialog(
|
||||
ShxAlertDialog(
|
||||
onDismissRequest = { showUpdateConfirm = false },
|
||||
title = { Text(stringResource(R.string.update_confirm_title, info.versionName)) },
|
||||
text = { if (notes.isNotEmpty()) { Text(notes) } },
|
||||
@@ -905,7 +905,7 @@ private fun SettingsRoot(onOpen: (SettingsPage) -> Unit, updateState: UpdateStat
|
||||
}
|
||||
if (showKillSwitchDialog)
|
||||
{
|
||||
AlertDialog(
|
||||
ShxAlertDialog(
|
||||
onDismissRequest = { showKillSwitchDialog = false },
|
||||
title = { Text(stringResource(R.string.kill_switch_dialog_title)) },
|
||||
text = { Text(stringResource(R.string.kill_switch_dialog_text)) },
|
||||
@@ -974,7 +974,7 @@ private fun KillSwitchRow()
|
||||
}
|
||||
if (showKillSwitchDialog)
|
||||
{
|
||||
AlertDialog(
|
||||
ShxAlertDialog(
|
||||
onDismissRequest = { showKillSwitchDialog = false },
|
||||
title = { Text(stringResource(R.string.kill_switch_dialog_title)) },
|
||||
text = { Text(stringResource(R.string.kill_switch_dialog_text)) },
|
||||
|
||||
@@ -37,7 +37,6 @@ import androidx.compose.material.icons.outlined.AltRoute
|
||||
import androidx.compose.material.icons.outlined.Home
|
||||
import androidx.compose.material.icons.outlined.Settings
|
||||
import androidx.compose.material.icons.outlined.Storage
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Checkbox
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
|
||||
+4
-4
@@ -38,7 +38,7 @@ import androidx.compose.material.icons.rounded.Add
|
||||
import androidx.compose.material.icons.rounded.Delete
|
||||
import androidx.compose.material.icons.rounded.Language
|
||||
import androidx.compose.material.icons.rounded.Wifi
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import org.strongswan.android.ui.compose.design.ShxAlertDialog
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
@@ -302,7 +302,7 @@ fun TrustedNetworksScreen(
|
||||
|
||||
if (showProfilePicker)
|
||||
{
|
||||
AlertDialog(
|
||||
ShxAlertDialog(
|
||||
onDismissRequest = { showProfilePicker = false },
|
||||
title = { Text(stringResource(R.string.auto_connect_profile)) },
|
||||
text = {
|
||||
@@ -339,7 +339,7 @@ fun TrustedNetworksScreen(
|
||||
if (showAddSsid)
|
||||
{
|
||||
var ssid by remember { mutableStateOf("") }
|
||||
AlertDialog(
|
||||
ShxAlertDialog(
|
||||
onDismissRequest = { showAddSsid = false },
|
||||
title = { Text(stringResource(R.string.auto_connect_add_network)) },
|
||||
text = {
|
||||
@@ -372,7 +372,7 @@ fun TrustedNetworksScreen(
|
||||
}
|
||||
|
||||
pendingDeleteSsid?.let { ssid ->
|
||||
AlertDialog(
|
||||
ShxAlertDialog(
|
||||
onDismissRequest = { pendingDeleteSsid = null },
|
||||
title = { Text(stringResource(R.string.auto_connect_remove_network)) },
|
||||
text = { Text(ssid) },
|
||||
|
||||
+13
-16
@@ -22,7 +22,8 @@ import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Visibility
|
||||
import androidx.compose.material.icons.rounded.VisibilityOff
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import org.strongswan.android.ui.compose.design.ShxAlertDialog
|
||||
import org.strongswan.android.ui.compose.design.ShxFormField
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
@@ -142,7 +143,7 @@ private fun cancelDialog()
|
||||
@Composable
|
||||
private fun ConfirmationUi(dialog: VpnDialog.Confirmation)
|
||||
{
|
||||
AlertDialog(
|
||||
ShxAlertDialog(
|
||||
onDismissRequest = ::cancelDialog,
|
||||
title = { Text(dialog.title) },
|
||||
text = { Text(stringResource(dialog.message)) },
|
||||
@@ -189,31 +190,28 @@ private fun LoginUi(dialog: VpnDialog.Login)
|
||||
var password by rememberSaveable { mutableStateOf("") }
|
||||
var showPassword by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
AlertDialog(
|
||||
ShxAlertDialog(
|
||||
onDismissRequest = ::cancelDialog,
|
||||
title = { Text(stringResource(R.string.login_title)) },
|
||||
text = {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(ShxSpacing.md)) {
|
||||
OutlinedTextField(
|
||||
ShxFormField(
|
||||
label = stringResource(R.string.login_username),
|
||||
value = username,
|
||||
onValueChange = { username = it },
|
||||
label = { Text(stringResource(R.string.login_username)) },
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
|
||||
enabled = false,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
|
||||
)
|
||||
OutlinedTextField(
|
||||
ShxFormField(
|
||||
label = stringResource(R.string.login_password),
|
||||
value = password,
|
||||
onValueChange = { password = it },
|
||||
label = { Text(stringResource(R.string.login_password)) },
|
||||
singleLine = true,
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Password,
|
||||
imeAction = ImeAction.Done,
|
||||
),
|
||||
visualTransformation = if (showPassword) VisualTransformation.None else PasswordVisualTransformation(),
|
||||
trailingIcon = {
|
||||
trailing = {
|
||||
IconButton(onClick = { showPassword = !showPassword }) {
|
||||
Icon(
|
||||
if (showPassword) Icons.Rounded.Visibility else Icons.Rounded.VisibilityOff,
|
||||
@@ -223,7 +221,6 @@ private fun LoginUi(dialog: VpnDialog.Login)
|
||||
)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
},
|
||||
@@ -244,7 +241,7 @@ private fun LoginUi(dialog: VpnDialog.Login)
|
||||
@Composable
|
||||
private fun CertificateRequiredUi(dialog: VpnDialog.CertificateRequired)
|
||||
{
|
||||
AlertDialog(
|
||||
ShxAlertDialog(
|
||||
onDismissRequest = ::cancelDialog,
|
||||
title = { Text(stringResource(R.string.certificate_required_title)) },
|
||||
text = { Text(stringResource(R.string.certificate_required_text)) },
|
||||
@@ -265,7 +262,7 @@ private fun CertificateRequiredUi(dialog: VpnDialog.CertificateRequired)
|
||||
@Composable
|
||||
private fun PowerWhitelistUi()
|
||||
{
|
||||
AlertDialog(
|
||||
ShxAlertDialog(
|
||||
onDismissRequest = ::cancelDialog,
|
||||
title = { Text(stringResource(R.string.power_whitelist_title)) },
|
||||
text = { Text(stringResource(R.string.power_whitelist_text)) },
|
||||
@@ -281,7 +278,7 @@ private fun PowerWhitelistUi()
|
||||
@Composable
|
||||
private fun NotSupportedUi(dialog: VpnDialog.NotSupported)
|
||||
{
|
||||
AlertDialog(
|
||||
ShxAlertDialog(
|
||||
onDismissRequest = ::cancelDialog,
|
||||
title = { Text(stringResource(R.string.vpn_not_supported_title)) },
|
||||
text = { Text(stringResource(dialog.message)) },
|
||||
|
||||
+73
@@ -757,6 +757,7 @@ fun ShxDialog(
|
||||
val c = LocalShxColors.current
|
||||
androidx.compose.ui.window.Dialog(onDismissRequest = onDismiss)
|
||||
{
|
||||
DialogScrim()
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(14.dp),
|
||||
modifier = Modifier.fillMaxWidth().clip(RoundedCornerShape(28.dp)).background(c.background).padding(24.dp),
|
||||
@@ -802,3 +803,75 @@ fun ShxDialog(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop-in for the Material AlertDialog in the mockup look (as [ShxDialog]):
|
||||
* 28dp card on the page colour, 22/800 title, 14sp soft text, buttons at the end.
|
||||
*/
|
||||
@Composable
|
||||
fun ShxAlertDialog(
|
||||
onDismissRequest: () -> Unit,
|
||||
confirmButton: @Composable () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
dismissButton: (@Composable () -> Unit)? = null,
|
||||
icon: (@Composable () -> Unit)? = null,
|
||||
title: (@Composable () -> Unit)? = null,
|
||||
text: (@Composable () -> Unit)? = null,
|
||||
)
|
||||
{
|
||||
val c = LocalShxColors.current
|
||||
androidx.compose.ui.window.Dialog(onDismissRequest = onDismissRequest)
|
||||
{
|
||||
DialogScrim()
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(14.dp),
|
||||
modifier = modifier.fillMaxWidth().clip(RoundedCornerShape(28.dp)).background(c.background).padding(24.dp),
|
||||
)
|
||||
{
|
||||
icon?.let {
|
||||
androidx.compose.runtime.CompositionLocalProvider(androidx.compose.material3.LocalContentColor provides c.onAccentContainer) { it() }
|
||||
}
|
||||
title?.let {
|
||||
androidx.compose.runtime.CompositionLocalProvider(androidx.compose.material3.LocalContentColor provides c.text) {
|
||||
androidx.compose.material3.ProvideTextStyle(ShxType.pageTitle) { it() }
|
||||
}
|
||||
}
|
||||
text?.let {
|
||||
androidx.compose.runtime.CompositionLocalProvider(androidx.compose.material3.LocalContentColor provides c.textSoft) {
|
||||
androidx.compose.material3.ProvideTextStyle(ShxType.note.copy(fontSize = 14.sp, lineHeight = 21.sp, fontWeight = FontWeight.Normal)) {
|
||||
Box(Modifier.weight(1f, fill = false)) { it() }
|
||||
}
|
||||
}
|
||||
}
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.End),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.fillMaxWidth().padding(top = 4.dp),
|
||||
)
|
||||
{
|
||||
androidx.compose.material3.ProvideTextStyle(ShxType.button.copy(fontWeight = FontWeight.Bold))
|
||||
{
|
||||
dismissButton?.invoke()
|
||||
confirmButton()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The 50% scrim of the mockup dialogs. Set on the dialog window itself:
|
||||
* hosts with a translucent theme (VpnProfileControlActivity) turn the
|
||||
* platform dim off.
|
||||
*/
|
||||
@Composable
|
||||
private fun DialogScrim()
|
||||
{
|
||||
val view = androidx.compose.ui.platform.LocalView.current
|
||||
androidx.compose.runtime.SideEffect {
|
||||
(view.parent as? androidx.compose.ui.window.DialogWindowProvider)?.window?.let {
|
||||
it.addFlags(android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND)
|
||||
it.setDimAmount(0.5f)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user