components batch-2: draw CollapsingScaffold + OptionPicker from floret-kit
All checks were successful
CI / ci (push) Successful in 8m37s

Agendula now sources the collapsing settings/sub-screen scaffold and the
full-screen single-select picker (FullScreenPicker/OptionPicker) from the kit's
components module. Deletes the app copies; repoints SettingsScreen imports and
adds the FullScreenPicker import in ReminderLeadPicker. Submodule re-pinned.
ReminderFormatting stays app-local (needs a label-callback API — separate pass).

Clean composite build + tests + lintDebug + debug assemble green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-28 13:25:53 +02:00
parent a5ddf16537
commit 069ae38b2c
5 changed files with 4 additions and 168 deletions

View File

@@ -1,84 +0,0 @@
package de.jeanlucmakiola.agendula.ui.common
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LargeTopAppBar
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import de.jeanlucmakiola.agendula.R
/**
* Shared collapsing scaffold for the settings hub, its sub-screens and the
* full-screen pickers: a [LargeTopAppBar] that collapses on scroll, a back
* button, and a vertically scrolling content column. Ported from Calendula so
* the two apps' settings read as one family. The content lays out the connected
* grouped rows.
*/
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CollapsingScaffold(
title: String,
onBack: () -> Unit,
modifier: Modifier = Modifier,
content: @Composable ColumnScope.() -> Unit,
) {
val scrollBehavior =
TopAppBarDefaults.exitUntilCollapsedScrollBehavior(rememberTopAppBarState())
Scaffold(
modifier = modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.surface)
.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
LargeTopAppBar(
title = { Text(title) },
navigationIcon = {
IconButton(onClick = onBack) {
Icon(
Icons.AutoMirrored.Rounded.ArrowBack,
contentDescription = stringResource(R.string.back),
)
}
},
scrollBehavior = scrollBehavior,
colors = TopAppBarDefaults.largeTopAppBarColors(
scrolledContainerColor = MaterialTheme.colorScheme.surface,
),
)
},
) { innerPadding ->
Column(
modifier = Modifier
.padding(innerPadding)
// Consume the scaffold's bar insets so imePadding adds only the
// keyboard height beyond them (max, not sum).
.consumeWindowInsets(innerPadding)
.fillMaxSize()
.background(MaterialTheme.colorScheme.surface)
.imePadding()
.verticalScroll(rememberScrollState())
.padding(top = 8.dp, bottom = 24.dp),
content = content,
)
}
}

View File

@@ -1,81 +0,0 @@
package de.jeanlucmakiola.agendula.ui.common
import de.jeanlucmakiola.floret.components.positionOf
import de.jeanlucmakiola.floret.components.GroupedRow
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Check
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties
/**
* Shared full-screen scaffold for selection pickers: a full-bleed [Dialog] that
* reuses [CollapsingScaffold] (collapsing title + back), so a picker is visually
* identical to a settings sub-page and uses the full width. [content] places the
* connected grouped rows; selecting one calls [onDismiss]. Ported from Calendula.
*/
@Composable
fun FullScreenPicker(
title: String,
onDismiss: () -> Unit,
content: @Composable ColumnScope.() -> Unit,
) {
Dialog(
onDismissRequest = onDismiss,
properties = DialogProperties(
usePlatformDefaultWidth = false,
decorFitsSystemWindows = false,
),
) {
CollapsingScaffold(title = title, onBack = onDismiss, content = content)
}
}
/**
* General single-select picker, full-screen: each option is a connected grouped
* row and the current one carries a check. The drop-in for the family's option
* dialogs (theme, default list, reminder offset, …).
*/
@Composable
fun <T> OptionPicker(
title: String,
options: List<T>,
selected: T,
label: @Composable (T) -> String,
onSelect: (T) -> Unit,
onDismiss: () -> Unit,
leading: (@Composable (T) -> Unit)? = null,
) {
FullScreenPicker(title = title, onDismiss = onDismiss) {
options.forEachIndexed { index, option ->
val isSelected = option == selected
GroupedRow(
title = label(option),
position = positionOf(index, options.size),
selected = isSelected,
leading = leading?.let { { it(option) } },
trailing = if (isSelected) {
{ SelectedCheck() }
} else {
null
},
onClick = {
onSelect(option)
onDismiss()
},
)
}
}
}
@Composable
private fun SelectedCheck() {
Icon(
imageVector = Icons.Rounded.Check,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary,
)
}

View File

@@ -1,5 +1,6 @@
package de.jeanlucmakiola.agendula.ui.common package de.jeanlucmakiola.agendula.ui.common
import de.jeanlucmakiola.floret.components.FullScreenPicker
import de.jeanlucmakiola.floret.components.Position import de.jeanlucmakiola.floret.components.Position
import de.jeanlucmakiola.floret.components.positionOf import de.jeanlucmakiola.floret.components.positionOf
import de.jeanlucmakiola.floret.components.InlineTextField import de.jeanlucmakiola.floret.components.InlineTextField

View File

@@ -87,9 +87,9 @@ import de.jeanlucmakiola.agendula.R
import de.jeanlucmakiola.agendula.data.prefs.ListReminderOverride import de.jeanlucmakiola.agendula.data.prefs.ListReminderOverride
import de.jeanlucmakiola.agendula.data.prefs.ThemeMode import de.jeanlucmakiola.agendula.data.prefs.ThemeMode
import de.jeanlucmakiola.agendula.domain.TaskFormField import de.jeanlucmakiola.agendula.domain.TaskFormField
import de.jeanlucmakiola.agendula.ui.common.CollapsingScaffold import de.jeanlucmakiola.floret.components.CollapsingScaffold
import de.jeanlucmakiola.floret.components.GroupedRow import de.jeanlucmakiola.floret.components.GroupedRow
import de.jeanlucmakiola.agendula.ui.common.OptionPicker import de.jeanlucmakiola.floret.components.OptionPicker
import de.jeanlucmakiola.floret.components.Position import de.jeanlucmakiola.floret.components.Position
import de.jeanlucmakiola.agendula.ui.common.ReminderLeadPicker import de.jeanlucmakiola.agendula.ui.common.ReminderLeadPicker
import de.jeanlucmakiola.floret.components.pastelize import de.jeanlucmakiola.floret.components.pastelize