android: predictive back scale for settings pages and remediation detail
This commit is contained in:
1 parent
2681233449
commit
dc6e1e32fb
3 files changed
+77
-3
No files matched your search
+4
-1
@@ -61,6 +61,7 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.strongswan.android.R
|
||||
import org.strongswan.android.ui.compose.components.PredictiveBackScale
|
||||
import org.strongswan.android.logic.imc.RemediationInstruction
|
||||
import org.strongswan.android.ui.compose.components.ShxCard
|
||||
import org.strongswan.android.ui.compose.components.ShxEmptyState
|
||||
@@ -127,7 +128,8 @@ private fun RemediationUi(
|
||||
onFinish: () -> Unit,
|
||||
)
|
||||
{
|
||||
BackHandler(enabled = selected != null) { onSelect(null) }
|
||||
PredictiveBackScale(enabled = selected != null, onBack = { onSelect(null) }, modifier = Modifier.fillMaxSize())
|
||||
{
|
||||
Column(Modifier.fillMaxSize())
|
||||
{
|
||||
TopAppBar(
|
||||
@@ -246,4 +248,5 @@ private fun RemediationUi(
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-2
@@ -96,6 +96,7 @@ import androidx.compose.material3.Icon
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import org.strongswan.android.ui.compose.components.PredictiveBackScale
|
||||
import org.strongswan.android.R
|
||||
import org.strongswan.android.data.VpnProfile
|
||||
import org.strongswan.android.logic.StrongSwanApplication
|
||||
@@ -178,14 +179,18 @@ fun SettingsScreen(profiles: List<VpnProfile>, showTitle: Boolean = true)
|
||||
|
||||
var pageState by rememberSaveable { mutableStateOf(SettingsPage.ROOT) }
|
||||
/* from a sub page "back" returns to the settings list, not out of the tab */
|
||||
BackHandler(enabled = pageState != SettingsPage.ROOT) { pageState = SettingsPage.ROOT }
|
||||
val effects = MaterialTheme.motionScheme.defaultEffectsSpec<Float>()
|
||||
val spatial = MaterialTheme.motionScheme.defaultSpatialSpec<androidx.compose.ui.unit.IntOffset>()
|
||||
|
||||
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.TopCenter)
|
||||
{
|
||||
PredictiveBackScale(
|
||||
enabled = pageState != SettingsPage.ROOT,
|
||||
onBack = { pageState = SettingsPage.ROOT },
|
||||
modifier = Modifier.widthIn(max = 640.dp).fillMaxSize(),
|
||||
)
|
||||
{
|
||||
AnimatedContent(
|
||||
modifier = Modifier.widthIn(max = 640.dp),
|
||||
targetState = pageState,
|
||||
transitionSpec = {
|
||||
val forward = targetState != SettingsPage.ROOT
|
||||
@@ -533,6 +538,7 @@ fun SettingsScreen(profiles: List<VpnProfile>, showTitle: Boolean = true)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
ShxSnackbarHost(
|
||||
hostState = snackbarHostState,
|
||||
modifier = Modifier.align(Alignment.BottomCenter),
|
||||
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2026 SHX VPN
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
package org.strongswan.android.ui.compose.components
|
||||
|
||||
import androidx.activity.compose.PredictiveBackHandler
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableFloatStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlin.coroutines.cancellation.CancellationException
|
||||
|
||||
/**
|
||||
* Handles the system back gesture for in-screen navigation (a sub page that returns
|
||||
* to its parent): while the user drags, the content shrinks slightly and rounds its
|
||||
* corners, then [onBack] runs when the gesture is committed.
|
||||
*/
|
||||
@Composable
|
||||
fun PredictiveBackScale(
|
||||
enabled: Boolean,
|
||||
onBack: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
content: @Composable () -> Unit,
|
||||
)
|
||||
{
|
||||
var progress by remember { mutableFloatStateOf(0f) }
|
||||
PredictiveBackHandler(enabled = enabled) { events ->
|
||||
try
|
||||
{
|
||||
events.collect { progress = it.progress }
|
||||
onBack()
|
||||
progress = 0f
|
||||
}
|
||||
catch (e: CancellationException)
|
||||
{
|
||||
progress = 0f
|
||||
throw e
|
||||
}
|
||||
}
|
||||
Box(
|
||||
modifier
|
||||
.graphicsLayer {
|
||||
val scale = 1f - 0.08f * progress
|
||||
scaleX = scale
|
||||
scaleY = scale
|
||||
}
|
||||
.clip(RoundedCornerShape((progress * 28f).dp)),
|
||||
)
|
||||
{
|
||||
content()
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user