android: 2.14.0 - minSdk 23 + adaptive navigation (Stage 3)
- minSdkVersion 21 -> 23 (device is Android 17, no other users); jni Application.mk: APP_PLATFORM android-23 + -DHAVE_SIGWAITINFO (the NDK sysroot declares sigwaitinfo since API 23, conflicting with strongSwan's fallback prototype; the system implementation is used now) - replace the bottom NavigationBar with NavigationSuiteScaffold (bottom bar on phones, navigation rail in landscape/on tablets); item colors keep the brand palette via NavigationSuiteItemColors(bar/rail/drawer) - HomeScreen applies statusBarsPadding itself (the adaptive scaffold no longer pads the content area) - predictive back was already enabled (android:enableOnBackInvokedCallback)
This commit is contained in:
1 parent
285d14e996
commit
2c69cbe775
4 files changed
+71
-33
No files matched your search
@@ -34,11 +34,11 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "one.shx.strongswan.ext"
|
applicationId "one.shx.strongswan.ext"
|
||||||
compileSdk = 36
|
compileSdk = 36
|
||||||
minSdkVersion 21
|
minSdkVersion 23
|
||||||
targetSdkVersion 36
|
targetSdkVersion 36
|
||||||
|
|
||||||
versionCode 152
|
versionCode 153
|
||||||
versionName "2.13.15"
|
versionName "2.14.0"
|
||||||
|
|
||||||
/* Base URL of the update storage, trailing slash included */
|
/* Base URL of the update storage, trailing slash included */
|
||||||
buildConfigField "String", "UPDATE_BASE_URL", "\"${updateBaseUrl}\""
|
buildConfigField "String", "UPDATE_BASE_URL", "\"${updateBaseUrl}\""
|
||||||
@@ -146,15 +146,15 @@ dependencies {
|
|||||||
implementation 'androidx.work:work-runtime-ktx:2.10.1'
|
implementation 'androidx.work:work-runtime-ktx:2.10.1'
|
||||||
implementation 'com.google.android.material:material:1.13.0'
|
implementation 'com.google.android.material:material:1.13.0'
|
||||||
|
|
||||||
/* BOM 2025.12.01 (compose 1.10) требует minSdk 23 — приложение поддерживает API 21.
|
/* BOM 2025.12.01 (compose 1.10, Expressive-тема) — отдельная задача после
|
||||||
2025.09.01 = первый BOM с material3 1.4.0 (Expressive) на compose 1.9 (minSdk 21). */
|
стабилизации; 2025.09.01 = material3 1.4.0 на compose 1.9. */
|
||||||
def composeBom = platform('androidx.compose:compose-bom:2025.09.01')
|
def composeBom = platform('androidx.compose:compose-bom:2025.09.01')
|
||||||
implementation composeBom
|
implementation composeBom
|
||||||
implementation 'androidx.compose.ui:ui'
|
implementation 'androidx.compose.ui:ui'
|
||||||
implementation 'androidx.compose.material3:material3'
|
implementation 'androidx.compose.material3:material3'
|
||||||
implementation 'androidx.compose.material3:material3-window-size-class'
|
implementation 'androidx.compose.material3:material3-window-size-class'
|
||||||
/* adaptive-navigation-suite требует minSdk 23 (adaptive:1.2.0) — подключить на этапе 3
|
/* adaptive-navigation-suite (NavigationSuiteScaffold): BOM 1.4.0, требует minSdk 23 */
|
||||||
вместе с решением о minSdk; сейчас приложение поддерживает API 21 */
|
implementation 'androidx.compose.material3:material3-adaptive-navigation-suite'
|
||||||
implementation 'androidx.compose.material:material-icons-extended'
|
implementation 'androidx.compose.material:material-icons-extended'
|
||||||
implementation 'androidx.activity:activity-compose:1.11.0'
|
implementation 'androidx.activity:activity-compose:1.11.0'
|
||||||
implementation 'androidx.navigation:navigation-compose:2.9.4'
|
implementation 'androidx.navigation:navigation-compose:2.9.4'
|
||||||
|
|||||||
+4
-1
@@ -44,6 +44,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.statusBarsPadding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.LazyListState
|
import androidx.compose.foundation.lazy.LazyListState
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
@@ -191,7 +192,9 @@ fun HomeScreen(
|
|||||||
StatusGlowBackground(color = statusColor, active = connected || connecting)
|
StatusGlowBackground(color = statusColor, active = connected || connecting)
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
state = listState,
|
state = listState,
|
||||||
modifier = Modifier.fillMaxSize(),
|
/* the adaptive navigation scaffold no longer pads the content area,
|
||||||
|
* so the status headline offsets itself below the status bar */
|
||||||
|
modifier = Modifier.fillMaxSize().statusBarsPadding(),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|||||||
+56
-24
@@ -24,10 +24,8 @@ import androidx.compose.foundation.clickable
|
|||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
@@ -43,13 +41,15 @@ import androidx.compose.material3.AlertDialog
|
|||||||
import androidx.compose.material3.Checkbox
|
import androidx.compose.material3.Checkbox
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.NavigationBar
|
|
||||||
import androidx.compose.material3.NavigationBarItem
|
|
||||||
import androidx.compose.material3.NavigationBarItemDefaults
|
import androidx.compose.material3.NavigationBarItemDefaults
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.NavigationDrawerItemDefaults
|
||||||
|
import androidx.compose.material3.NavigationRailItemDefaults
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
|
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteItemColors
|
||||||
|
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScope
|
||||||
|
import androidx.compose.material3.adaptive.navigationsuite.NavigationSuiteScaffold
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
@@ -57,6 +57,7 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.compositeOver
|
import androidx.compose.ui.graphics.compositeOver
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
@@ -107,17 +108,18 @@ fun ShxApp(viewModel: HomeViewModel = viewModel())
|
|||||||
/* the home list keeps its scroll state across tab switches */
|
/* the home list keeps its scroll state across tab switches */
|
||||||
val homeListState = rememberLazyListState()
|
val homeListState = rememberLazyListState()
|
||||||
|
|
||||||
Scaffold(
|
/* adaptive navigation: bottom bar on phones, navigation rail in landscape
|
||||||
bottomBar = {
|
* and on tablets (Stage 3 of ui-ux-plan). Item colors are built here in a
|
||||||
ShxBottomBar(selected = state.tab, onSelect = viewModel::setTab)
|
* composable context - the items lambda itself does not compose. */
|
||||||
|
val navItemColors = shxNavigationItemColors()
|
||||||
|
NavigationSuiteScaffold(
|
||||||
|
navigationSuiteItems = {
|
||||||
|
ShxNavigationSuiteItems(selected = state.tab, onSelect = viewModel::setTab, colors = navItemColors)
|
||||||
},
|
},
|
||||||
containerColor = MaterialTheme.colorScheme.background,
|
containerColor = MaterialTheme.colorScheme.background,
|
||||||
) { padding ->
|
) {
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier
|
modifier = Modifier.fillMaxSize(),
|
||||||
.fillMaxSize()
|
|
||||||
.padding(padding)
|
|
||||||
.consumeWindowInsets(padding),
|
|
||||||
color = MaterialTheme.colorScheme.background,
|
color = MaterialTheme.colorScheme.background,
|
||||||
) {
|
) {
|
||||||
AnimatedContent(
|
AnimatedContent(
|
||||||
@@ -206,14 +208,51 @@ private fun ShareProfileDialog(profile: VpnProfile, onDismiss: () -> Unit, onCon
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Item colors for the adaptive navigation suite, keeping the brand palette. */
|
||||||
@Composable
|
@Composable
|
||||||
private fun ShxBottomBar(selected: ShxTab, onSelect: (ShxTab) -> Unit)
|
private fun shxNavigationItemColors(): NavigationSuiteItemColors
|
||||||
{
|
{
|
||||||
val bg = MaterialTheme.colorScheme.surfaceContainer
|
val bg = MaterialTheme.colorScheme.surfaceContainer
|
||||||
val indicator = MaterialTheme.colorScheme.primary.copy(alpha = 0.32f).compositeOver(bg)
|
val indicator = MaterialTheme.colorScheme.primary.copy(alpha = 0.32f).compositeOver(bg)
|
||||||
NavigationBar(containerColor = bg, tonalElevation = 0.dp) {
|
return NavigationSuiteItemColors(
|
||||||
|
navigationBarItemColors = NavigationBarItemDefaults.colors(
|
||||||
|
selectedIconColor = MaterialTheme.colorScheme.primary,
|
||||||
|
unselectedIconColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
selectedTextColor = MaterialTheme.colorScheme.primary,
|
||||||
|
unselectedTextColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
indicatorColor = indicator,
|
||||||
|
),
|
||||||
|
navigationRailItemColors = NavigationRailItemDefaults.colors(
|
||||||
|
selectedIconColor = MaterialTheme.colorScheme.primary,
|
||||||
|
unselectedIconColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
selectedTextColor = MaterialTheme.colorScheme.primary,
|
||||||
|
unselectedTextColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
indicatorColor = indicator,
|
||||||
|
),
|
||||||
|
navigationDrawerItemColors = NavigationDrawerItemDefaults.colors(
|
||||||
|
selectedContainerColor = indicator,
|
||||||
|
unselectedContainerColor = Color.Transparent,
|
||||||
|
selectedIconColor = MaterialTheme.colorScheme.primary,
|
||||||
|
unselectedIconColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
selectedTextColor = MaterialTheme.colorScheme.primary,
|
||||||
|
unselectedTextColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the app tabs as navigation suite items. The scope's item() is a
|
||||||
|
* plain registration function - only the icon/label lambdas compose - so
|
||||||
|
* colors are built outside (in a composable context) and passed in.
|
||||||
|
*/
|
||||||
|
private fun NavigationSuiteScope.ShxNavigationSuiteItems(
|
||||||
|
selected: ShxTab,
|
||||||
|
onSelect: (ShxTab) -> Unit,
|
||||||
|
colors: NavigationSuiteItemColors,
|
||||||
|
)
|
||||||
|
{
|
||||||
ShxTab.entries.forEach { tab ->
|
ShxTab.entries.forEach { tab ->
|
||||||
NavigationBarItem(
|
item(
|
||||||
selected = tab == selected,
|
selected = tab == selected,
|
||||||
onClick = { onSelect(tab) },
|
onClick = { onSelect(tab) },
|
||||||
icon = {
|
icon = {
|
||||||
@@ -223,17 +262,10 @@ private fun ShxBottomBar(selected: ShxTab, onSelect: (ShxTab) -> Unit)
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
label = { Text(stringResource(tab.label())) },
|
label = { Text(stringResource(tab.label())) },
|
||||||
colors = NavigationBarItemDefaults.colors(
|
colors = colors,
|
||||||
selectedIconColor = MaterialTheme.colorScheme.primary,
|
|
||||||
unselectedIconColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
|
||||||
selectedTextColor = MaterialTheme.colorScheme.primary,
|
|
||||||
unselectedTextColor = MaterialTheme.colorScheme.onSurfaceVariant,
|
|
||||||
indicatorColor = indicator,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun ShxTab.icon(selected: Boolean): ImageVector = when (this)
|
private fun ShxTab.icon(selected: Boolean): ImageVector = when (this)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
APP_PLATFORM := android-21
|
APP_PLATFORM := android-23
|
||||||
APP_SUPPORT_FLEXIBLE_PAGE_SIZES := true
|
APP_SUPPORT_FLEXIBLE_PAGE_SIZES := true
|
||||||
APP_ABI := armeabi-v7a arm64-v8a x86_64
|
APP_ABI := armeabi-v7a arm64-v8a x86_64
|
||||||
|
# minSdk 23: the NDK sysroot declares sigwaitinfo() (introduced in API 23),
|
||||||
|
# so use the system implementation instead of strongSwan's fallback prototype
|
||||||
|
APP_CFLAGS += -DHAVE_SIGWAITINFO
|
||||||
Reference in new issue
Block a user