mirror of
https://github.com/d4rken-org/capod.git
synced 2026-09-16 19:26:12 -04:00
fix(ui): Draw all screens edge-to-edge under system bars
Scrolling content now slides under the transparent status and navigation bars instead of clipping at the inset boundary. Adds PaddingValues.plus and systemBarsAndCutoutInsets helpers, moves inset consumption from scroll viewports into content padding on every screen, fixes reorder auto-scroll thresholds for content padding, adds IME handling to form screens, and removes the unused EdgeToEdgeHelper.
This commit is contained in:
@@ -87,7 +87,7 @@ The monitor-layer glue (`monitor/core/aap/`) described above wires this stack in
|
|||||||
|
|
||||||
### Common Utilities
|
### Common Utilities
|
||||||
|
|
||||||
- `EdgeToEdgeHelper`: Handles Android edge-to-edge display insets
|
- `common/compose/InsetsExtensions.kt`: `PaddingValues.plus` operator and `systemBarsAndCutoutInsets` for laying out non-Scaffold screens edge-to-edge
|
||||||
|
|
||||||
## Build Configuration
|
## Build Configuration
|
||||||
|
|
||||||
|
|||||||
@@ -5,11 +5,17 @@ import androidx.compose.foundation.layout.Box
|
|||||||
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.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.only
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.safeDrawing
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
@@ -133,10 +139,12 @@ fun SupporterStatusScreen(
|
|||||||
Scaffold(
|
Scaffold(
|
||||||
containerColor = MaterialTheme.colorScheme.surface,
|
containerColor = MaterialTheme.colorScheme.surface,
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
Box(modifier = Modifier.padding(paddingValues)) {
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(paddingValues)
|
||||||
.padding(horizontal = 24.dp),
|
.padding(horizontal = 24.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
@@ -238,6 +246,7 @@ fun SupporterStatusScreen(
|
|||||||
onClick = onNavigateUp,
|
onClick = onNavigateUp,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.TopStart)
|
.align(Alignment.TopStart)
|
||||||
|
.windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Start))
|
||||||
.padding(4.dp),
|
.padding(4.dp),
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
@@ -272,10 +281,12 @@ fun UpgradeScreen(
|
|||||||
snackbarHost = { SnackbarHost(snackbarHostState) },
|
snackbarHost = { SnackbarHost(snackbarHostState) },
|
||||||
containerColor = MaterialTheme.colorScheme.surface,
|
containerColor = MaterialTheme.colorScheme.surface,
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
Box(modifier = Modifier.padding(paddingValues)) {
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(paddingValues)
|
||||||
.padding(horizontal = 24.dp),
|
.padding(horizontal = 24.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
@@ -402,6 +413,7 @@ fun UpgradeScreen(
|
|||||||
onClick = onNavigateUp,
|
onClick = onNavigateUp,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.TopStart)
|
.align(Alignment.TopStart)
|
||||||
|
.windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Start))
|
||||||
.padding(4.dp),
|
.padding(4.dp),
|
||||||
) {
|
) {
|
||||||
Icon(
|
Icon(
|
||||||
|
|||||||
@@ -8,12 +8,17 @@ import androidx.compose.foundation.layout.Column
|
|||||||
import androidx.compose.foundation.layout.ColumnScope
|
import androidx.compose.foundation.layout.ColumnScope
|
||||||
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.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.only
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.safeDrawing
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.layout.widthIn
|
import androidx.compose.foundation.layout.widthIn
|
||||||
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
@@ -105,7 +110,7 @@ internal fun UpgradeScreenContainer(
|
|||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
containerColor = MaterialTheme.colorScheme.surface,
|
containerColor = MaterialTheme.colorScheme.surface,
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
Box(modifier = Modifier.padding(paddingValues)) {
|
Box(modifier = Modifier.fillMaxSize()) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
@@ -114,6 +119,7 @@ internal fun UpgradeScreenContainer(
|
|||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
.padding(paddingValues)
|
||||||
// widthIn BEFORE fillMaxWidth: reversed, fillMaxWidth would pin the min to
|
// widthIn BEFORE fillMaxWidth: reversed, fillMaxWidth would pin the min to
|
||||||
// the full screen and the 560dp cap would never take effect on wide screens.
|
// the full screen and the 560dp cap would never take effect on wide screens.
|
||||||
.widthIn(max = 560.dp)
|
.widthIn(max = 560.dp)
|
||||||
@@ -129,6 +135,7 @@ internal fun UpgradeScreenContainer(
|
|||||||
onClick = onNavigateUp,
|
onClick = onNavigateUp,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.TopStart)
|
.align(Alignment.TopStart)
|
||||||
|
.windowInsetsPadding(WindowInsets.safeDrawing.only(WindowInsetsSides.Top + WindowInsetsSides.Start))
|
||||||
.padding(4.dp),
|
.padding(4.dp),
|
||||||
) {
|
) {
|
||||||
// Matches capod's app-wide back-button convention (no navigate-up string exists).
|
// Matches capod's app-wide back-button convention (no navigate-up string exists).
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
package eu.darken.capod.common
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.view.View
|
|
||||||
import androidx.core.view.ViewCompat
|
|
||||||
import androidx.core.view.WindowInsetsCompat
|
|
||||||
import eu.darken.capod.common.debug.logging.logTag
|
|
||||||
|
|
||||||
|
|
||||||
class EdgeToEdgeHelper(activity: Activity) {
|
|
||||||
|
|
||||||
private val tag = logTag("EdgeToEdge", "$activity")
|
|
||||||
|
|
||||||
fun insetsPadding(
|
|
||||||
view: View,
|
|
||||||
left: Boolean = false,
|
|
||||||
top: Boolean = false,
|
|
||||||
right: Boolean = false,
|
|
||||||
bottom: Boolean = false,
|
|
||||||
) {
|
|
||||||
ViewCompat.setOnApplyWindowInsetsListener(view) { v: View, insets: WindowInsetsCompat ->
|
|
||||||
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
|
||||||
val displayCutout = insets.getInsets(WindowInsetsCompat.Type.displayCutout())
|
|
||||||
|
|
||||||
v.setPadding(
|
|
||||||
if (left) maxOf(systemBars.left, displayCutout.left) else v.paddingLeft,
|
|
||||||
if (top) maxOf(systemBars.top, displayCutout.top) else v.paddingTop,
|
|
||||||
if (right) maxOf(systemBars.right, displayCutout.right) else v.paddingRight,
|
|
||||||
if (bottom) maxOf(systemBars.bottom, displayCutout.bottom) else v.paddingBottom,
|
|
||||||
)
|
|
||||||
insets
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package eu.darken.capod.common.compose
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.displayCutout
|
||||||
|
import androidx.compose.foundation.layout.systemBars
|
||||||
|
import androidx.compose.foundation.layout.union
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
|
|
||||||
|
operator fun PaddingValues.plus(other: PaddingValues): PaddingValues = object : PaddingValues {
|
||||||
|
override fun calculateLeftPadding(layoutDirection: LayoutDirection): Dp =
|
||||||
|
this@plus.calculateLeftPadding(layoutDirection) + other.calculateLeftPadding(layoutDirection)
|
||||||
|
override fun calculateTopPadding(): Dp = this@plus.calculateTopPadding() + other.calculateTopPadding()
|
||||||
|
override fun calculateRightPadding(layoutDirection: LayoutDirection): Dp =
|
||||||
|
this@plus.calculateRightPadding(layoutDirection) + other.calculateRightPadding(layoutDirection)
|
||||||
|
override fun calculateBottomPadding(): Dp = this@plus.calculateBottomPadding() + other.calculateBottomPadding()
|
||||||
|
}
|
||||||
|
|
||||||
|
val systemBarsAndCutoutInsets: WindowInsets
|
||||||
|
@Composable get() = WindowInsets.systemBars.union(WindowInsets.displayCutout)
|
||||||
@@ -127,16 +127,16 @@ fun <T> ReorderableAutoScroll(state: ReorderableState<T>) {
|
|||||||
if (!state.isDragging) return@LaunchedEffect
|
if (!state.isDragging) return@LaunchedEffect
|
||||||
while (isActive) {
|
while (isActive) {
|
||||||
val layoutInfo = state.lazyListState.layoutInfo
|
val layoutInfo = state.lazyListState.layoutInfo
|
||||||
val viewportStart = layoutInfo.viewportStartOffset
|
val contentStart = layoutInfo.viewportStartOffset + layoutInfo.beforeContentPadding
|
||||||
val viewportEnd = layoutInfo.viewportEndOffset
|
val contentEnd = layoutInfo.viewportEndOffset - layoutInfo.afterContentPadding
|
||||||
val draggedIdx = state.draggedIndex ?: break
|
val draggedIdx = state.draggedIndex ?: break
|
||||||
val draggedItem = layoutInfo.visibleItemsInfo.firstOrNull { it.index == draggedIdx }
|
val draggedItem = layoutInfo.visibleItemsInfo.firstOrNull { it.index == draggedIdx }
|
||||||
if (draggedItem != null) {
|
if (draggedItem != null) {
|
||||||
val itemCenter = draggedItem.offset + draggedItem.size / 2 + state.dragOffsetY
|
val itemCenter = draggedItem.offset + draggedItem.size / 2 + state.dragOffsetY
|
||||||
val scrollSpeed = 8f
|
val scrollSpeed = 8f
|
||||||
val delta = when {
|
val delta = when {
|
||||||
itemCenter < viewportStart + scrollThresholdPx -> -scrollSpeed
|
itemCenter < contentStart + scrollThresholdPx -> -scrollSpeed
|
||||||
itemCenter > viewportEnd - scrollThresholdPx -> scrollSpeed
|
itemCenter > contentEnd - scrollThresholdPx -> scrollSpeed
|
||||||
else -> 0f
|
else -> 0f
|
||||||
}
|
}
|
||||||
if (delta != 0f) state.lazyListState.scrollBy(delta)
|
if (delta != 0f) state.lazyListState.scrollBy(delta)
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.Box
|
|||||||
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.WindowInsets
|
|
||||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
@@ -16,7 +15,6 @@ import androidx.compose.foundation.layout.height
|
|||||||
import androidx.compose.foundation.layout.only
|
import androidx.compose.foundation.layout.only
|
||||||
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.systemBars
|
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
@@ -54,6 +52,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import eu.darken.capod.R
|
import eu.darken.capod.R
|
||||||
import eu.darken.capod.common.compose.Preview2
|
import eu.darken.capod.common.compose.Preview2
|
||||||
import eu.darken.capod.common.compose.PreviewWrapper
|
import eu.darken.capod.common.compose.PreviewWrapper
|
||||||
|
import eu.darken.capod.common.compose.systemBarsAndCutoutInsets
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -68,16 +67,12 @@ fun RecorderScreen(
|
|||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
Box(modifier = modifier.fillMaxSize()) {
|
Box(modifier = modifier.fillMaxSize()) {
|
||||||
if (state.isWorking) {
|
Column(modifier = Modifier.fillMaxSize()) {
|
||||||
LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
|
|
||||||
}
|
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.weight(1f)
|
||||||
.windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal))
|
|
||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
.padding(bottom = 80.dp),
|
.windowInsetsPadding(systemBarsAndCutoutInsets.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)),
|
||||||
) {
|
) {
|
||||||
// Hero section
|
// Hero section
|
||||||
HeroSection()
|
HeroSection()
|
||||||
@@ -109,9 +104,13 @@ fun RecorderScreen(
|
|||||||
onDiscard = onDiscard,
|
onDiscard = onDiscard,
|
||||||
onKeep = onKeep,
|
onKeep = onKeep,
|
||||||
onShare = onShare,
|
onShare = onShare,
|
||||||
modifier = Modifier.align(Alignment.BottomCenter),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (state.isWorking) {
|
||||||
|
LinearProgressIndicator(modifier = Modifier.fillMaxWidth())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -373,7 +372,9 @@ private fun BottomActionBar(
|
|||||||
color = MaterialTheme.colorScheme.surfaceContainerHigh,
|
color = MaterialTheme.colorScheme.surfaceContainerHigh,
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.padding(12.dp),
|
modifier = Modifier
|
||||||
|
.windowInsetsPadding(systemBarsAndCutoutInsets.only(WindowInsetsSides.Bottom + WindowInsetsSides.Horizontal))
|
||||||
|
.padding(12.dp),
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
) {
|
) {
|
||||||
OutlinedButton(
|
OutlinedButton(
|
||||||
@@ -415,7 +416,6 @@ private fun BottomActionBar(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Bottom)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.content.Intent
|
|||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
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.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
@@ -270,7 +271,8 @@ fun DeviceSettingsScreen(
|
|||||||
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
|
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier.padding(paddingValues),
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentPadding = paddingValues,
|
||||||
) {
|
) {
|
||||||
// Device Info
|
// Device Info
|
||||||
if (device != null) {
|
if (device != null) {
|
||||||
|
|||||||
@@ -50,9 +50,9 @@ fun OnboardingScreen(
|
|||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
|
.verticalScroll(rememberScrollState())
|
||||||
.padding(innerPadding)
|
.padding(innerPadding)
|
||||||
.padding(horizontal = 32.dp)
|
.padding(horizontal = 32.dp),
|
||||||
.verticalScroll(rememberScrollState()),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
) {
|
) {
|
||||||
Spacer(modifier = Modifier.height(48.dp))
|
Spacer(modifier = Modifier.height(48.dp))
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import androidx.activity.compose.rememberLauncherForActivityResult
|
|||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.foundation.layout.PaddingValues
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
@@ -48,6 +47,7 @@ import eu.darken.capod.R
|
|||||||
import eu.darken.capod.common.SystemTimeSource
|
import eu.darken.capod.common.SystemTimeSource
|
||||||
import eu.darken.capod.common.compose.Preview2
|
import eu.darken.capod.common.compose.Preview2
|
||||||
import eu.darken.capod.common.compose.PreviewWrapper
|
import eu.darken.capod.common.compose.PreviewWrapper
|
||||||
|
import eu.darken.capod.common.compose.plus
|
||||||
import eu.darken.capod.common.compose.preview.MockPodDataProvider
|
import eu.darken.capod.common.compose.preview.MockPodDataProvider
|
||||||
import eu.darken.capod.common.error.ErrorEventHandler
|
import eu.darken.capod.common.error.ErrorEventHandler
|
||||||
import eu.darken.capod.common.navigation.NavigationEventHandler
|
import eu.darken.capod.common.navigation.NavigationEventHandler
|
||||||
@@ -278,10 +278,8 @@ fun OverviewScreen(
|
|||||||
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
|
snackbarHost = { SnackbarHost(hostState = snackbarHostState) },
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier
|
modifier = Modifier.fillMaxSize(),
|
||||||
.fillMaxSize()
|
contentPadding = innerPadding + PaddingValues(horizontal = 8.dp, vertical = 4.dp),
|
||||||
.padding(innerPadding),
|
|
||||||
contentPadding = PaddingValues(horizontal = 8.dp, vertical = 4.dp),
|
|
||||||
) {
|
) {
|
||||||
// 1. Permission cards
|
// 1. Permission cards
|
||||||
items(
|
items(
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package eu.darken.capod.main.ui.presscontrols
|
package eu.darken.capod.main.ui.presscontrols
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
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.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
@@ -176,7 +177,10 @@ fun PressControlsScreen(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
LazyColumn(modifier = Modifier.padding(paddingValues)) {
|
LazyColumn(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentPadding = paddingValues,
|
||||||
|
) {
|
||||||
item("description") {
|
item("description") {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.press_controls_description),
|
text = stringResource(R.string.press_controls_description),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package eu.darken.capod.main.ui.settings
|
package eu.darken.capod.main.ui.settings
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.twotone.ArrowBack
|
import androidx.compose.material.icons.automirrored.twotone.ArrowBack
|
||||||
@@ -105,7 +105,10 @@ fun SettingsScreen(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
LazyColumn(modifier = Modifier.padding(innerPadding)) {
|
LazyColumn(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentPadding = innerPadding,
|
||||||
|
) {
|
||||||
item {
|
item {
|
||||||
SettingsBaseItem(
|
SettingsBaseItem(
|
||||||
title = stringResource(R.string.settings_general_label),
|
title = stringResource(R.string.settings_general_label),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package eu.darken.capod.main.ui.settings.acks
|
package eu.darken.capod.main.ui.settings.acks
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.twotone.ArrowBack
|
import androidx.compose.material.icons.automirrored.twotone.ArrowBack
|
||||||
@@ -54,7 +54,10 @@ fun AcknowledgementsScreen(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
LazyColumn(modifier = Modifier.padding(innerPadding)) {
|
LazyColumn(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentPadding = innerPadding,
|
||||||
|
) {
|
||||||
item {
|
item {
|
||||||
SettingsCategoryHeader(text = stringResource(R.string.general_thank_you_label))
|
SettingsCategoryHeader(text = stringResource(R.string.general_thank_you_label))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package eu.darken.capod.main.ui.settings.general
|
package eu.darken.capod.main.ui.settings.general
|
||||||
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
@@ -105,7 +106,10 @@ fun GeneralSettingsScreen(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
LazyColumn(modifier = Modifier.padding(innerPadding)) {
|
LazyColumn(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentPadding = innerPadding,
|
||||||
|
) {
|
||||||
item {
|
item {
|
||||||
SettingsCategoryHeader(text = stringResource(R.string.settings_category_appearance_label))
|
SettingsCategoryHeader(text = stringResource(R.string.settings_category_appearance_label))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.Arrangement
|
|||||||
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.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
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
|
||||||
@@ -228,7 +229,10 @@ fun SupportScreen(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
LazyColumn(modifier = Modifier.padding(innerPadding)) {
|
LazyColumn(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
contentPadding = innerPadding,
|
||||||
|
) {
|
||||||
item {
|
item {
|
||||||
SettingsBaseItem(
|
SettingsBaseItem(
|
||||||
title = stringResource(R.string.troubleshooter_title),
|
title = stringResource(R.string.troubleshooter_title),
|
||||||
|
|||||||
+6
-2
@@ -9,8 +9,10 @@ import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
|||||||
import androidx.compose.foundation.layout.FlowRow
|
import androidx.compose.foundation.layout.FlowRow
|
||||||
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.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.imePadding
|
||||||
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.width
|
import androidx.compose.foundation.layout.width
|
||||||
@@ -241,12 +243,14 @@ fun ContactFormScreen(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
snackbarHost = { SnackbarHost(snackbarHostState) },
|
snackbarHost = { SnackbarHost(snackbarHostState, modifier = Modifier.imePadding()) },
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(innerPadding)
|
.fillMaxSize()
|
||||||
|
.imePadding()
|
||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(innerPadding)
|
||||||
.padding(16.dp),
|
.padding(16.dp),
|
||||||
verticalArrangement = Arrangement.spacedBy(12.dp),
|
verticalArrangement = Arrangement.spacedBy(12.dp),
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -22,15 +22,14 @@ import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
|||||||
import androidx.compose.foundation.layout.FlowRow
|
import androidx.compose.foundation.layout.FlowRow
|
||||||
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.WindowInsets
|
|
||||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.imePadding
|
||||||
import androidx.compose.foundation.layout.only
|
import androidx.compose.foundation.layout.only
|
||||||
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.systemBars
|
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
@@ -77,6 +76,7 @@ import eu.darken.capod.R
|
|||||||
import eu.darken.capod.common.compose.Preview2
|
import eu.darken.capod.common.compose.Preview2
|
||||||
import eu.darken.capod.common.compose.PreviewWrapper
|
import eu.darken.capod.common.compose.PreviewWrapper
|
||||||
import eu.darken.capod.common.compose.preview.MockPodDataProvider
|
import eu.darken.capod.common.compose.preview.MockPodDataProvider
|
||||||
|
import eu.darken.capod.common.compose.systemBarsAndCutoutInsets
|
||||||
import eu.darken.capod.pods.core.apple.PodModel
|
import eu.darken.capod.pods.core.apple.PodModel
|
||||||
import eu.darken.capod.profiles.core.DeviceProfile
|
import eu.darken.capod.profiles.core.DeviceProfile
|
||||||
|
|
||||||
@@ -102,12 +102,13 @@ fun WidgetConfigurationScreen(
|
|||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal)),
|
.imePadding(),
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
|
.windowInsetsPadding(systemBarsAndCutoutInsets.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal))
|
||||||
.padding(top = 24.dp, bottom = 16.dp),
|
.padding(top = 24.dp, bottom = 16.dp),
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
@@ -347,7 +348,7 @@ fun WidgetConfigurationScreen(
|
|||||||
|
|
||||||
// Bottom bar
|
// Bottom bar
|
||||||
Surface(tonalElevation = 3.dp) {
|
Surface(tonalElevation = 3.dp) {
|
||||||
Column(modifier = Modifier.windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Bottom))) {
|
Column(modifier = Modifier.windowInsetsPadding(systemBarsAndCutoutInsets.only(WindowInsetsSides.Bottom + WindowInsetsSides.Horizontal))) {
|
||||||
if (!state.isPro) {
|
if (!state.isPro) {
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(R.string.common_feature_requires_pro_msg),
|
text = stringResource(R.string.common_feature_requires_pro_msg),
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import androidx.compose.foundation.Image
|
|||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
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.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
@@ -44,6 +45,7 @@ import eu.darken.capod.R
|
|||||||
import eu.darken.capod.common.compose.Preview2
|
import eu.darken.capod.common.compose.Preview2
|
||||||
import eu.darken.capod.common.compose.PreviewWrapper
|
import eu.darken.capod.common.compose.PreviewWrapper
|
||||||
import eu.darken.capod.common.compose.ReorderableAutoScroll
|
import eu.darken.capod.common.compose.ReorderableAutoScroll
|
||||||
|
import eu.darken.capod.common.compose.plus
|
||||||
import eu.darken.capod.common.compose.preview.MockPodDataProvider
|
import eu.darken.capod.common.compose.preview.MockPodDataProvider
|
||||||
import eu.darken.capod.common.compose.reorderableItemModifier
|
import eu.darken.capod.common.compose.reorderableItemModifier
|
||||||
import eu.darken.capod.common.compose.rememberReorderableState
|
import eu.darken.capod.common.compose.rememberReorderableState
|
||||||
@@ -123,9 +125,8 @@ fun DeviceManagerScreen(
|
|||||||
val showDragHandles = reorderableState.items.size >= 2
|
val showDragHandles = reorderableState.items.size >= 2
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
state = lazyListState,
|
state = lazyListState,
|
||||||
modifier = Modifier
|
modifier = Modifier.fillMaxSize(),
|
||||||
.fillMaxSize()
|
contentPadding = innerPadding + PaddingValues(bottom = 88.dp),
|
||||||
.padding(innerPadding),
|
|
||||||
) {
|
) {
|
||||||
itemsIndexed(
|
itemsIndexed(
|
||||||
items = reorderableState.items,
|
items = reorderableState.items,
|
||||||
|
|||||||
+3
-1
@@ -8,6 +8,7 @@ import androidx.compose.foundation.layout.Spacer
|
|||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.imePadding
|
||||||
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.width
|
import androidx.compose.foundation.layout.width
|
||||||
@@ -199,8 +200,9 @@ fun DeviceProfileCreationScreen(
|
|||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(innerPadding)
|
.imePadding()
|
||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
|
.padding(innerPadding)
|
||||||
.padding(16.dp),
|
.padding(16.dp),
|
||||||
) {
|
) {
|
||||||
DeviceInfoCard(
|
DeviceInfoCard(
|
||||||
|
|||||||
@@ -76,8 +76,8 @@ fun TroubleShooterScreen(
|
|||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(innerPadding)
|
.verticalScroll(rememberScrollState())
|
||||||
.verticalScroll(rememberScrollState()),
|
.padding(innerPadding),
|
||||||
) {
|
) {
|
||||||
Card(
|
Card(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package eu.darken.capod.common.compose
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import io.kotest.matchers.shouldBe
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import testhelpers.BaseTest
|
||||||
|
|
||||||
|
class InsetsExtensionsTest : BaseTest() {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `plus - sums start-end padding under Ltr`() {
|
||||||
|
val a = PaddingValues(start = 4.dp, top = 8.dp, end = 12.dp, bottom = 16.dp)
|
||||||
|
val b = PaddingValues(start = 1.dp, top = 2.dp, end = 3.dp, bottom = 4.dp)
|
||||||
|
val sum = a + b
|
||||||
|
sum.calculateLeftPadding(LayoutDirection.Ltr) shouldBe 5.dp
|
||||||
|
sum.calculateRightPadding(LayoutDirection.Ltr) shouldBe 15.dp
|
||||||
|
sum.calculateTopPadding() shouldBe 10.dp
|
||||||
|
sum.calculateBottomPadding() shouldBe 20.dp
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `plus - sums start-end padding under Rtl`() {
|
||||||
|
val a = PaddingValues(start = 4.dp, top = 8.dp, end = 12.dp, bottom = 16.dp)
|
||||||
|
val b = PaddingValues(start = 1.dp, top = 2.dp, end = 3.dp, bottom = 4.dp)
|
||||||
|
val sum = a + b
|
||||||
|
sum.calculateLeftPadding(LayoutDirection.Rtl) shouldBe 15.dp
|
||||||
|
sum.calculateRightPadding(LayoutDirection.Rtl) shouldBe 5.dp
|
||||||
|
sum.calculateTopPadding() shouldBe 10.dp
|
||||||
|
sum.calculateBottomPadding() shouldBe 20.dp
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user