Share side-inset padding, fix keyboard gap on detail and edit (#152)
This commit is contained in:
1 parent
d562cf85f2
commit
984da3c61c
6 files changed
+58
-32
No files matched your search
+2
-1
@@ -10,7 +10,8 @@ All notable changes to this project are documented here. The format follows
|
||||
### Fixed
|
||||
- With 3-button navigation, the navigation bar no longer covers the last home
|
||||
search results, and in landscape it no longer covers the home screen, the
|
||||
task list or the home top bar's buttons (#152).
|
||||
task list or the home top bar's buttons. The task details and editor no
|
||||
longer leave an empty gap between the open keyboard and the text (#152).
|
||||
|
||||
## [1.3.1] - 2026-11-09
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package de.jeanlucmakiola.agendula.ui.common
|
||||
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.calculateEndPadding
|
||||
import androidx.compose.foundation.layout.calculateStartPadding
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
/**
|
||||
* Pads by the start/end of a scaffold's [inner] padding and consumes it, so a
|
||||
* side navigation bar or cutout (3-button nav in landscape) is cleared once.
|
||||
*/
|
||||
@Composable
|
||||
fun Modifier.sideInsetsPadding(inner: PaddingValues): Modifier {
|
||||
val layoutDirection = LocalLayoutDirection.current
|
||||
val sides = PaddingValues(
|
||||
start = inner.calculateStartPadding(layoutDirection),
|
||||
top = 0.dp,
|
||||
end = inner.calculateEndPadding(layoutDirection),
|
||||
bottom = 0.dp,
|
||||
)
|
||||
return this.padding(sides).consumeWindowInsets(sides)
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.heightIn
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
@@ -268,6 +269,9 @@ private fun DetailBody(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(inner)
|
||||
// Consume the bar insets so imePadding adds only what the keyboard
|
||||
// covers beyond them.
|
||||
.consumeWindowInsets(inner)
|
||||
// Shrink the scroll viewport by the keyboard so the focused add-subtask
|
||||
// field scrolls into view above the IME instead of being hidden.
|
||||
.imePadding()
|
||||
|
||||
@@ -57,6 +57,7 @@ import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
@@ -219,7 +220,9 @@ fun TaskEditScreen(
|
||||
viewModel = viewModel,
|
||||
scroll = scroll,
|
||||
onTitleBottom = { titleBottom = it },
|
||||
modifier = Modifier.padding(inner),
|
||||
// Consumed so EditContent's imePadding adds only what the keyboard
|
||||
// covers beyond the bars.
|
||||
modifier = Modifier.padding(inner).consumeWindowInsets(inner),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -31,14 +31,13 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
||||
import androidx.compose.foundation.layout.asPaddingValues
|
||||
import androidx.compose.foundation.layout.calculateEndPadding
|
||||
import androidx.compose.foundation.layout.calculateStartPadding
|
||||
import androidx.compose.foundation.layout.displayCutout
|
||||
import androidx.compose.foundation.layout.ime
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.only
|
||||
import androidx.compose.foundation.layout.systemBars
|
||||
import androidx.compose.foundation.layout.union
|
||||
import androidx.compose.foundation.layout.windowInsetsBottomHeight
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
@@ -84,7 +83,6 @@ import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
@@ -110,6 +108,7 @@ import de.jeanlucmakiola.agendula.ui.common.LocalUse24HourFormat
|
||||
import de.jeanlucmakiola.agendula.ui.common.ShapedActionButton
|
||||
import de.jeanlucmakiola.agendula.ui.common.SyncPullBox
|
||||
import de.jeanlucmakiola.agendula.ui.common.priorityAccent
|
||||
import de.jeanlucmakiola.agendula.ui.common.sideInsetsPadding
|
||||
import de.jeanlucmakiola.agendula.ui.tasklist.priorityLabel
|
||||
import de.jeanlucmakiola.floret.components.positionOf
|
||||
import de.jeanlucmakiola.floret.time.formatDateTimeCompact
|
||||
@@ -163,7 +162,6 @@ fun ListsScreen(
|
||||
// System back closes search before leaving the screen.
|
||||
BackHandler(enabled = searchActive, onBack = closeSearch)
|
||||
|
||||
val layoutDirection = LocalLayoutDirection.current
|
||||
Scaffold(
|
||||
modifier = modifier,
|
||||
topBar = {
|
||||
@@ -192,12 +190,10 @@ fun ListsScreen(
|
||||
available = syncAvailable && !searchActive,
|
||||
syncing = syncing,
|
||||
onSync = viewModel::syncAll,
|
||||
// Side insets too: in landscape a 3-button navigation bar sits at the side.
|
||||
modifier = Modifier.fillMaxSize().padding(
|
||||
start = inner.calculateStartPadding(layoutDirection),
|
||||
top = inner.calculateTopPadding(),
|
||||
end = inner.calculateEndPadding(layoutDirection),
|
||||
),
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(top = inner.calculateTopPadding())
|
||||
.sideInsetsPadding(inner),
|
||||
) {
|
||||
when (val s = state) {
|
||||
ListsUiState.Loading -> Unit // brief; avoids a flash before first emission
|
||||
@@ -530,7 +526,10 @@ private fun HomeTopBar(
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.windowInsetsPadding(WindowInsets.systemBars.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal))
|
||||
.windowInsetsPadding(
|
||||
WindowInsets.systemBars.union(WindowInsets.displayCutout)
|
||||
.only(WindowInsetsSides.Top + WindowInsetsSides.Horizontal),
|
||||
)
|
||||
.height(72.dp)
|
||||
.padding(horizontal = 12.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
@@ -690,15 +689,13 @@ private fun SearchResults(
|
||||
}
|
||||
} else {
|
||||
// The last result scrolls clear of the navigation bar and the keyboard.
|
||||
LazyColumn(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentPadding = WindowInsets.navigationBars.union(WindowInsets.ime)
|
||||
.only(WindowInsetsSides.Bottom)
|
||||
.asPaddingValues(),
|
||||
) {
|
||||
LazyColumn(modifier = Modifier.fillMaxSize()) {
|
||||
items(results, key = { it.occurrenceKey }) { task ->
|
||||
UpcomingRow(task = task, onClick = { onOpenTask(task) })
|
||||
}
|
||||
item(key = "bottom-inset") {
|
||||
Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.navigationBars.union(WindowInsets.ime)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,6 @@ import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.calculateEndPadding
|
||||
import androidx.compose.foundation.layout.calculateStartPadding
|
||||
import androidx.compose.foundation.layout.ime
|
||||
import androidx.compose.foundation.layout.isImeVisible
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
@@ -92,7 +90,6 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.draw.rotate
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.SolidColor
|
||||
@@ -118,6 +115,7 @@ import de.jeanlucmakiola.agendula.ui.common.LocalUse24HourFormat
|
||||
import de.jeanlucmakiola.agendula.ui.common.SyncPullBox
|
||||
import de.jeanlucmakiola.agendula.ui.common.ignoringEdgeSwipes
|
||||
import de.jeanlucmakiola.agendula.ui.common.priorityAccent
|
||||
import de.jeanlucmakiola.agendula.ui.common.sideInsetsPadding
|
||||
import de.jeanlucmakiola.agendula.ui.lists.ListEditorSheet
|
||||
import de.jeanlucmakiola.agendula.ui.lists.listWriteFailureMessage
|
||||
import de.jeanlucmakiola.agendula.ui.lists.ListWriteFailure
|
||||
@@ -253,14 +251,7 @@ fun TaskListScreen(
|
||||
}
|
||||
},
|
||||
) { inner ->
|
||||
// Side insets too: in landscape a 3-button navigation bar sits at the side.
|
||||
val layoutDirection = LocalLayoutDirection.current
|
||||
Box(
|
||||
modifier = Modifier.fillMaxSize().padding(
|
||||
start = inner.calculateStartPadding(layoutDirection),
|
||||
end = inner.calculateEndPadding(layoutDirection),
|
||||
),
|
||||
) {
|
||||
Box(modifier = Modifier.fillMaxSize().sideInsetsPadding(inner)) {
|
||||
SyncPullBox(
|
||||
available = syncAvailable,
|
||||
syncing = syncing,
|
||||
@@ -270,7 +261,10 @@ fun TaskListScreen(
|
||||
) {
|
||||
when (val s = state) {
|
||||
TaskListUiState.Loading -> Unit // brief; avoids a flash before first emission
|
||||
TaskListUiState.Failure -> CenteredMessage(stringResource(R.string.task_list_failure), inner)
|
||||
TaskListUiState.Failure -> CenteredMessage(
|
||||
stringResource(R.string.task_list_failure),
|
||||
PaddingValues(top = inner.calculateTopPadding(), bottom = inner.calculateBottomPadding()),
|
||||
)
|
||||
is TaskListUiState.Content -> TaskListBody(
|
||||
s, filter, inner, onOpenTask, onRequestDelete, viewModel,
|
||||
onClearCompleted = if (listId != null && list?.isReadOnly != true) ({ confirmClear = true }) else null,
|
||||
|
||||
Reference in new issue
Block a user