v1.0.52: fix Select button cut off on Android 16 edge-to-edge dialogs
Android 15+ enforces edge-to-edge on Dialog windows, making standard Compose WindowInsets APIs return 0 inside dialogs. Fix: use ViewCompat insets listener inside the Dialog to read actual system bar heights, with 56dp minimum to guarantee full nav bar clearance. Spacer inside the button Surface lets the elevated background extend behind the nav bar. Also make the entire local folder field tappable (not just the trailing icon) for better UX. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package com.syncflow.ui.addpair
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
@@ -105,18 +106,17 @@ fun AddPairScreen(onDone: () -> Unit, vm: AddPairViewModel = hiltViewModel()) {
|
||||
Spacer(Modifier.height(4.dp))
|
||||
|
||||
// Local folder
|
||||
Box(modifier = Modifier.fillMaxWidth()) {
|
||||
OutlinedTextField(
|
||||
value = uriToDisplay(s.localPath), onValueChange = {},
|
||||
label = { Text("Local folder") },
|
||||
leadingIcon = { Icon(Icons.Default.PhoneAndroid, null) },
|
||||
trailingIcon = {
|
||||
IconButton(onClick = { showLocalBrowser = true }) {
|
||||
Icon(Icons.Default.FolderOpen, "Browse")
|
||||
}
|
||||
},
|
||||
trailingIcon = { Icon(Icons.Default.FolderOpen, null) },
|
||||
readOnly = true, singleLine = true, modifier = Modifier.fillMaxWidth(),
|
||||
placeholder = { Text("Tap to choose folder…") },
|
||||
)
|
||||
Box(modifier = Modifier.matchParentSize().clickable { showLocalBrowser = true })
|
||||
}
|
||||
|
||||
// Remote folder
|
||||
OutlinedTextField(
|
||||
|
||||
@@ -26,9 +26,14 @@ import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
@@ -131,8 +136,25 @@ fun LocalBrowserDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
properties = DialogProperties(usePlatformDefaultWidth = false, decorFitsSystemWindows = false),
|
||||
) {
|
||||
val view = LocalView.current
|
||||
val density = LocalDensity.current
|
||||
var topInset by remember { mutableStateOf(0.dp) }
|
||||
var bottomInset by remember { mutableStateOf(56.dp) }
|
||||
DisposableEffect(view) {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(view) { _, insets ->
|
||||
val bars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
with(density) {
|
||||
topInset = bars.top.toDp()
|
||||
bottomInset = maxOf(bars.bottom.toDp(), 56.dp)
|
||||
}
|
||||
insets
|
||||
}
|
||||
ViewCompat.requestApplyInsets(view)
|
||||
onDispose { ViewCompat.setOnApplyWindowInsetsListener(view, null) }
|
||||
}
|
||||
|
||||
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.surface) {
|
||||
Column(modifier = Modifier.fillMaxSize().statusBarsPadding()) {
|
||||
Column(modifier = Modifier.fillMaxSize().padding(top = topInset)) {
|
||||
|
||||
// ── Top bar ──────────────────────────────────────────────────
|
||||
TopAppBar(
|
||||
@@ -242,7 +264,7 @@ fun LocalBrowserDialog(
|
||||
|
||||
// ── Select button ────────────────────────────────────────────
|
||||
Surface(tonalElevation = 4.dp, modifier = Modifier.fillMaxWidth()) {
|
||||
Column(modifier = Modifier.navigationBarsPadding()) {
|
||||
Column {
|
||||
Button(
|
||||
onClick = { onSelect(currentPath.absolutePath) },
|
||||
modifier = Modifier
|
||||
@@ -256,6 +278,7 @@ fun LocalBrowserDialog(
|
||||
Text("Select \"$currentFolderName\"",
|
||||
style = MaterialTheme.typography.titleSmall, fontWeight = FontWeight.SemiBold)
|
||||
}
|
||||
Spacer(Modifier.height(bottomInset))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,9 +25,13 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import com.syncflow.domain.model.RemoteFile
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -77,8 +81,25 @@ fun RemoteBrowserDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
properties = DialogProperties(usePlatformDefaultWidth = false, decorFitsSystemWindows = false),
|
||||
) {
|
||||
val view = LocalView.current
|
||||
val density = LocalDensity.current
|
||||
var topInset by remember { mutableStateOf(0.dp) }
|
||||
var bottomInset by remember { mutableStateOf(56.dp) }
|
||||
DisposableEffect(view) {
|
||||
ViewCompat.setOnApplyWindowInsetsListener(view) { _, insets ->
|
||||
val bars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
|
||||
with(density) {
|
||||
topInset = bars.top.toDp()
|
||||
bottomInset = maxOf(bars.bottom.toDp(), 56.dp)
|
||||
}
|
||||
insets
|
||||
}
|
||||
ViewCompat.requestApplyInsets(view)
|
||||
onDispose { ViewCompat.setOnApplyWindowInsetsListener(view, null) }
|
||||
}
|
||||
|
||||
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.surface) {
|
||||
Column(modifier = Modifier.fillMaxSize().statusBarsPadding()) {
|
||||
Column(modifier = Modifier.fillMaxSize().padding(top = topInset)) {
|
||||
|
||||
// ── Top bar ──────────────────────────────────────────────────
|
||||
TopAppBar(
|
||||
@@ -208,7 +229,7 @@ fun RemoteBrowserDialog(
|
||||
|
||||
// ── Select button ────────────────────────────────────────────
|
||||
Surface(tonalElevation = 4.dp, modifier = Modifier.fillMaxWidth()) {
|
||||
Column(modifier = Modifier.navigationBarsPadding()) {
|
||||
Column {
|
||||
Button(
|
||||
onClick = { onSelect(state.currentPath) },
|
||||
modifier = Modifier
|
||||
@@ -225,6 +246,7 @@ fun RemoteBrowserDialog(
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
)
|
||||
}
|
||||
Spacer(Modifier.height(bottomInset))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,2 +1,2 @@
|
||||
VERSION_NAME=1.0.47
|
||||
VERSION_CODE=48
|
||||
VERSION_NAME=1.0.52
|
||||
VERSION_CODE=53
|
||||
|
||||
Reference in New Issue
Block a user