From 3c323ec4c41f57230cd6440dbd42f1c5d36abdfc Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Sun, 28 Jun 2026 20:57:59 +0200 Subject: [PATCH] refactor(ui): draw the grouped-list core + pickers from floret-kit components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the kit grown to carry Calendula's richer variants (previous floret-kit commit), move the last app-local UI-core onto the shared components module and bump the submodule: - Delete the app-local GroupedList.kt (Position/positionOf/GroupedRow/ CollapsingScaffold) and Picker.kt's FullScreenPicker/OptionPicker — all now come from floret-kit. Repoint every screen's imports. - The features that kept these local are preserved through the kit's new parameters: GroupedRow dimmed/container; CollapsingScaffold actions/snackbar; and predictiveBack, passed true at the settings hub/sub-screens, the calendars manager, and all full-screen pickers (the kit defaults it off, so it's opt-in). - FullScreenPicker's keyboard fix (SOFT_INPUT_ADJUST_NOTHING) and OptionPicker's header slot now live in the kit too. - Add a localized `back` string (the kit scaffold's back-button label). Bumps floret-kit 86f4480 -> d9e4e87. Compile + unit tests + lintDebug + reproducible-release guard all green. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../calendula/ui/agenda/AgendaScreen.kt | 6 +- .../calendula/ui/calendars/CalendarsScreen.kt | 7 +- .../calendula/ui/common/CalendarDrawer.kt | 3 + .../calendula/ui/common/GroupedList.kt | 219 ------------------ .../calendula/ui/common/Picker.kt | 84 +------ .../calendula/ui/edit/EventEditScreen.kt | 4 +- .../calendula/ui/filter/CalendarFilterList.kt | 4 +- .../calendula/ui/search/SearchScreen.kt | 6 +- .../calendula/ui/settings/SettingsScreen.kt | 21 +- app/src/main/res/values-de/strings.xml | 1 + app/src/main/res/values/strings.xml | 2 + floret-kit | 2 +- 12 files changed, 42 insertions(+), 317 deletions(-) delete mode 100644 app/src/main/java/de/jeanlucmakiola/calendula/ui/common/GroupedList.kt diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/agenda/AgendaScreen.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/agenda/AgendaScreen.kt index 3c63d19..8e07ca6 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/agenda/AgendaScreen.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/agenda/AgendaScreen.kt @@ -61,12 +61,12 @@ import de.jeanlucmakiola.calendula.ui.common.CalendarDrawer import de.jeanlucmakiola.calendula.ui.common.CalendarFabColumn import de.jeanlucmakiola.calendula.ui.common.CalendarFailure import de.jeanlucmakiola.calendula.ui.common.CalendarView -import de.jeanlucmakiola.calendula.ui.common.GroupedRow -import de.jeanlucmakiola.calendula.ui.common.Position +import de.jeanlucmakiola.floret.components.GroupedRow +import de.jeanlucmakiola.floret.components.Position import de.jeanlucmakiola.calendula.ui.common.ViewSwitcherPill import de.jeanlucmakiola.calendula.ui.common.next import de.jeanlucmakiola.floret.components.pastelize -import de.jeanlucmakiola.calendula.ui.common.positionOf +import de.jeanlucmakiola.floret.components.positionOf import de.jeanlucmakiola.calendula.ui.common.currentLocale import de.jeanlucmakiola.calendula.ui.common.LocalUse24HourFormat import de.jeanlucmakiola.calendula.ui.common.formatTimeOfDay diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/calendars/CalendarsScreen.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/calendars/CalendarsScreen.kt index b9ab499..db02bb4 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/calendars/CalendarsScreen.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/calendars/CalendarsScreen.kt @@ -101,11 +101,11 @@ import de.jeanlucmakiola.floret.components.DialogUnitDropdown import de.jeanlucmakiola.floret.identity.collapseExit import de.jeanlucmakiola.floret.identity.expandEnter import de.jeanlucmakiola.floret.identity.predictiveBack -import de.jeanlucmakiola.calendula.ui.common.CollapsingScaffold +import de.jeanlucmakiola.floret.components.CollapsingScaffold import de.jeanlucmakiola.calendula.ui.common.ColorSwatchRow -import de.jeanlucmakiola.calendula.ui.common.GroupedRow +import de.jeanlucmakiola.floret.components.GroupedRow import de.jeanlucmakiola.floret.components.InlineTextField -import de.jeanlucmakiola.calendula.ui.common.Position +import de.jeanlucmakiola.floret.components.Position import de.jeanlucmakiola.floret.components.pastelize import java.time.LocalDate @@ -253,6 +253,7 @@ private fun CalendarsList( title = stringResource(R.string.calendars_title), onBack = onBack, snackbarHost = { SnackbarHost(snackbarHostState) }, + predictiveBack = true, ) { // What the per-calendar / per-account switches below actually do. HintText(stringResource(R.string.calendars_disable_hint)) diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/CalendarDrawer.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/CalendarDrawer.kt index 2b66b98..15d8da2 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/CalendarDrawer.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/CalendarDrawer.kt @@ -37,6 +37,9 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import de.jeanlucmakiola.calendula.R import de.jeanlucmakiola.calendula.ui.filter.CalendarFilterList +import de.jeanlucmakiola.floret.components.GroupedRow +import de.jeanlucmakiola.floret.components.Position +import de.jeanlucmakiola.floret.components.positionOf import kotlinx.datetime.LocalDate /** diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/GroupedList.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/GroupedList.kt deleted file mode 100644 index e86b1a0..0000000 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/GroupedList.kt +++ /dev/null @@ -1,219 +0,0 @@ -package de.jeanlucmakiola.calendula.ui.common - -import androidx.compose.animation.core.animateDpAsState -import androidx.compose.foundation.background -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.interaction.collectIsPressedAsState -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.ColumnScope -import androidx.compose.foundation.layout.RowScope -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.consumeWindowInsets -import androidx.compose.foundation.layout.heightIn -import androidx.compose.foundation.layout.imePadding -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.verticalScroll -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.automirrored.filled.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.ListItem -import androidx.compose.material3.ListItemDefaults -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Surface -import androidx.compose.material3.Text -import androidx.compose.material3.TopAppBarDefaults -import androidx.compose.material3.rememberTopAppBarState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.remember -import androidx.compose.ui.Modifier -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.input.nestedscroll.nestedScroll -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp -import de.jeanlucmakiola.calendula.R -import de.jeanlucmakiola.floret.identity.predictiveBack - -/** - * Position of a row within a grouped list, after the Android-15 settings - * pattern: a run of rows shares one rounded container, with full corners at the - * group's outer edges and small corners between, separated by small gaps. - */ -enum class Position { Top, Middle, Bottom, Alone } - -/** Maps an index within a group of [count] rows to its [Position]. */ -fun positionOf(index: Int, count: Int): Position = when { - count <= 1 -> Position.Alone - index == 0 -> Position.Top - index == count - 1 -> Position.Bottom - else -> Position.Middle -} - -/** - * The app's standard full-screen list scaffold: a collapsing [LargeTopAppBar] - * whose title shrinks into the bar (next to the back button) as the content - * scrolls. Content is a scrollable column that feeds the toolbar via nested - * scroll. Used by Settings and the calendar manager so they share one shell. - */ -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun CollapsingScaffold( - title: String, - onBack: () -> Unit, - modifier: Modifier = Modifier, - snackbarHost: @Composable () -> Unit = {}, - actions: @Composable RowScope.() -> Unit = {}, - content: @Composable ColumnScope.() -> Unit, -) { - val scrollBehavior = - TopAppBarDefaults.exitUntilCollapsedScrollBehavior(rememberTopAppBarState()) - Scaffold( - modifier = modifier - .predictiveBack(onBack = onBack) - .fillMaxSize() - .background(MaterialTheme.colorScheme.surface) - .nestedScroll(scrollBehavior.nestedScrollConnection), - topBar = { - LargeTopAppBar( - title = { Text(title) }, - navigationIcon = { - IconButton(onClick = onBack) { - Icon( - Icons.AutoMirrored.Filled.ArrowBack, - contentDescription = stringResource(R.string.settings_back), - ) - } - }, - actions = actions, - scrollBehavior = scrollBehavior, - colors = TopAppBarDefaults.topAppBarColors( - scrolledContainerColor = MaterialTheme.colorScheme.surface, - ), - ) - }, - snackbarHost = snackbarHost, - ) { innerPadding -> - Column( - modifier = Modifier - .padding(innerPadding) - // Mark the scaffold's system-bar insets as consumed so the - // imePadding below adds only the keyboard height beyond them - // (max, not sum) — otherwise the nav-bar inset double-counts and - // leaves an empty strip above the keyboard. - .consumeWindowInsets(innerPadding) - .fillMaxSize() - // Paint the surface across the full area before imePadding carves - // into it, so any sliver above the keyboard reads as surface — not - // the dialog window's black — during the IME animation. - .background(MaterialTheme.colorScheme.surface) - // Shrink the scroll viewport by the keyboard inset so a focused - // field (e.g. the custom-reminder amount) can scroll into view. - .imePadding() - .verticalScroll(rememberScrollState()) - .padding(top = 8.dp, bottom = 24.dp), - content = content, - ) - } -} - -/** - * One row in a grouped list: an M3 [ListItem] over a tonal [Surface] whose - * corner radii come from its [position] (so a run of rows reads as a single - * rounded card). Corners round further on press. A null [onClick] makes the - * row non-interactive (e.g. read-only entries). [dimmed] fades the headline and - * summary to the M3 disabled emphasis while leaving the [trailing] control at - * full opacity — for rows that are present but switched off. - */ -@OptIn(ExperimentalMaterial3Api::class) -@Composable -fun GroupedRow( - title: String, - position: Position, - modifier: Modifier = Modifier, - summary: String? = null, - selected: Boolean = false, - dimmed: Boolean = false, - container: Color? = null, - minHeight: Dp = 72.dp, - leading: @Composable (() -> Unit)? = null, - trailing: @Composable (() -> Unit)? = null, - onClick: (() -> Unit)? = null, -) { - val interaction = remember { MutableInteractionSource() } - val pressed by interaction.collectIsPressedAsState() - val full by animateDpAsState(if (pressed) 36.dp else 22.dp, label = "fullCorner") - val small by animateDpAsState(if (pressed) 36.dp else 6.dp, label = "smallCorner") - val shape = when (position) { - Position.Alone -> RoundedCornerShape(full) - Position.Top -> RoundedCornerShape( - topStart = full, topEnd = full, bottomStart = small, bottomEnd = small, - ) - Position.Middle -> RoundedCornerShape(small) - Position.Bottom -> RoundedCornerShape( - topStart = small, topEnd = small, bottomStart = full, bottomEnd = full, - ) - } - val gap = when (position) { - Position.Top, Position.Middle -> Modifier.padding(bottom = 2.dp) - Position.Bottom, Position.Alone -> Modifier - } - val itemColors = if (selected) { - ListItemDefaults.colors( - containerColor = Color.Transparent, - headlineColor = MaterialTheme.colorScheme.onSecondaryContainer, - leadingIconColor = MaterialTheme.colorScheme.onSecondaryContainer, - supportingColor = MaterialTheme.colorScheme.onSecondaryContainer, - trailingIconColor = MaterialTheme.colorScheme.onSecondaryContainer, - ) - } else if (dimmed) { - // M3 disabled emphasis (0.38α) on the text/leading; the trailing control - // stays full-opacity so the toggle reads as live even on a faded row. - val muted = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.38f) - ListItemDefaults.colors( - containerColor = Color.Transparent, - headlineColor = muted, - leadingIconColor = muted, - supportingColor = muted, - ) - } else { - ListItemDefaults.colors(containerColor = Color.Transparent) - } - val item: @Composable () -> Unit = { - ListItem( - headlineContent = { Text(title) }, - supportingContent = summary?.let { text -> { Text(text) } }, - leadingContent = leading, - trailingContent = trailing, - colors = itemColors, - modifier = Modifier.heightIn(min = minHeight), - ) - } - val base = modifier - .fillMaxWidth() - .padding(horizontal = 16.dp) - .then(gap) - val containerColor = when { - selected -> MaterialTheme.colorScheme.secondaryContainer - container != null -> container - else -> MaterialTheme.colorScheme.surfaceContainerHigh - } - if (onClick != null) { - Surface( - onClick = onClick, - color = containerColor, - shape = shape, - interactionSource = interaction, - modifier = base, - ) { item() } - } else { - Surface(color = containerColor, shape = shape, modifier = base) { item() } - } -} diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/Picker.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/Picker.kt index 725eabd..cad9c7a 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/Picker.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/Picker.kt @@ -3,7 +3,6 @@ package de.jeanlucmakiola.calendula.ui.common import androidx.compose.animation.AnimatedVisibility import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth @@ -21,100 +20,29 @@ import androidx.compose.material3.SegmentedButtonDefaults import androidx.compose.material3.SingleChoiceSegmentedButtonRow import androidx.compose.material3.Surface import androidx.compose.material3.Text -import android.view.WindowManager import androidx.compose.runtime.Composable -import androidx.compose.runtime.SideEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalView import androidx.compose.ui.res.pluralStringResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import androidx.compose.ui.window.Dialog -import androidx.compose.ui.window.DialogProperties -import androidx.compose.ui.window.DialogWindowProvider import de.jeanlucmakiola.calendula.R import de.jeanlucmakiola.calendula.ui.agenda.AgendaRange import de.jeanlucmakiola.floret.components.DialogAmountField +import de.jeanlucmakiola.floret.components.FullScreenPicker +import de.jeanlucmakiola.floret.components.GroupedRow +import de.jeanlucmakiola.floret.components.Position +import de.jeanlucmakiola.floret.components.positionOf import de.jeanlucmakiola.floret.identity.collapseExit import de.jeanlucmakiola.floret.identity.expandEnter import de.jeanlucmakiola.floret.reminders.ReminderOverride import de.jeanlucmakiola.floret.reminders.ReminderUnit import de.jeanlucmakiola.floret.reminders.decomposeReminderMinutes -/** - * Shared full-screen scaffold for selection pickers: a full-bleed [Dialog] that - * reuses the app's [CollapsingScaffold] (collapsing title + back button), 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]. - */ -@Composable -fun FullScreenPicker( - title: String, - onDismiss: () -> Unit, - content: @Composable ColumnScope.() -> Unit, -) { - Dialog( - onDismissRequest = onDismiss, - properties = DialogProperties( - usePlatformDefaultWidth = false, - decorFitsSystemWindows = false, - ), - ) { - // The dialog window pans by default when the keyboard opens, which — - // combined with the content's own imePadding — leaves a fixed black gap - // above the keyboard. Switch it to ADJUST_NOTHING so the window stays - // full-screen and imePadding alone lifts the focused field. - val view = LocalView.current - SideEffect { - (view.parent as? DialogWindowProvider)?.window - ?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING) - } - 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. Drop-in for the former dialog - * (theme, week start, language, …). - */ -@Composable -fun OptionPicker( - title: String, - options: List, - selected: T, - label: @Composable (T) -> String, - onSelect: (T) -> Unit, - onDismiss: () -> Unit, - header: (@Composable ColumnScope.() -> Unit)? = null, -) { - FullScreenPicker(title = title, onDismiss = onDismiss) { - header?.invoke(this) - options.forEachIndexed { index, option -> - val isSelected = option == selected - GroupedRow( - title = label(option), - position = positionOf(index, options.size), - selected = isSelected, - trailing = if (isSelected) { - { SelectedCheck() } - } else { - null - }, - onClick = { - onSelect(option) - onDismiss() - }, - ) - } - } -} - /** * Reminder-default picker, full-screen: the grouped list (with an optional "Use * default reminder" row and a "None" row), the [presets] as lead-time rows, and @@ -145,7 +73,7 @@ fun ReminderDefaultPicker( } val rowCount = options.size + 1 // + the custom row - FullScreenPicker(title = title, onDismiss = onDismiss) { + FullScreenPicker(title = title, onDismiss = onDismiss, predictiveBack = true) { options.forEachIndexed { index, option -> val isSelected = option == selected GroupedRow( @@ -332,7 +260,7 @@ fun AgendaRangePicker( ) } - FullScreenPicker(title = title, onDismiss = onDismiss) { + FullScreenPicker(title = title, onDismiss = onDismiss, predictiveBack = true) { PickerDescription(description) // Calendar-aligned windows. diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/edit/EventEditScreen.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/edit/EventEditScreen.kt index 1ae66e2..82117da 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/edit/EventEditScreen.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/edit/EventEditScreen.kt @@ -128,8 +128,8 @@ import de.jeanlucmakiola.calendula.ui.common.eventFormFieldLabel import de.jeanlucmakiola.calendula.ui.common.MILLIS_PER_DAY import de.jeanlucmakiola.floret.components.InlineTextField import de.jeanlucmakiola.floret.components.OptionCard -import de.jeanlucmakiola.calendula.ui.common.Position -import de.jeanlucmakiola.calendula.ui.common.positionOf +import de.jeanlucmakiola.floret.components.Position +import de.jeanlucmakiola.floret.components.positionOf import de.jeanlucmakiola.calendula.ui.common.REMINDER_PRESETS import de.jeanlucmakiola.calendula.ui.common.TimePickerAlert import de.jeanlucmakiola.floret.reminders.ReminderUnit diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/filter/CalendarFilterList.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/filter/CalendarFilterList.kt index f2d7ccf..0827abd 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/filter/CalendarFilterList.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/filter/CalendarFilterList.kt @@ -21,8 +21,8 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle import de.jeanlucmakiola.calendula.R import de.jeanlucmakiola.calendula.domain.FailureReason import de.jeanlucmakiola.calendula.ui.common.CalendarColorChip -import de.jeanlucmakiola.calendula.ui.common.GroupedRow -import de.jeanlucmakiola.calendula.ui.common.positionOf +import de.jeanlucmakiola.floret.components.GroupedRow +import de.jeanlucmakiola.floret.components.positionOf /** * Calendar-visibility filter (M3), rendered inline in the navigation drawer. diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/search/SearchScreen.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/search/SearchScreen.kt index b823c5d..738fd8d 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/search/SearchScreen.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/search/SearchScreen.kt @@ -51,14 +51,14 @@ import de.jeanlucmakiola.calendula.R import de.jeanlucmakiola.calendula.domain.EventInstance import de.jeanlucmakiola.floret.identity.animateItemMotion import de.jeanlucmakiola.floret.identity.predictiveBack -import de.jeanlucmakiola.calendula.ui.common.GroupedRow +import de.jeanlucmakiola.floret.components.GroupedRow import de.jeanlucmakiola.floret.components.InlineTextField -import de.jeanlucmakiola.calendula.ui.common.Position +import de.jeanlucmakiola.floret.components.Position import de.jeanlucmakiola.calendula.ui.common.currentLocale import de.jeanlucmakiola.calendula.ui.common.LocalUse24HourFormat import de.jeanlucmakiola.calendula.ui.common.timeOfDayFormatter import de.jeanlucmakiola.floret.components.pastelize -import de.jeanlucmakiola.calendula.ui.common.positionOf +import de.jeanlucmakiola.floret.components.positionOf import java.time.Instant as JavaInstant import java.time.ZoneId import java.time.format.DateTimeFormatter diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/settings/SettingsScreen.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/settings/SettingsScreen.kt index ee7c999..baca932 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/settings/SettingsScreen.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/settings/SettingsScreen.kt @@ -98,17 +98,17 @@ import de.jeanlucmakiola.floret.crash.submitCrashReport import de.jeanlucmakiola.floret.identity.expandEnter import de.jeanlucmakiola.calendula.ui.common.AgendaRangePicker import de.jeanlucmakiola.calendula.ui.common.agendaRangeLabel -import de.jeanlucmakiola.calendula.ui.common.CollapsingScaffold -import de.jeanlucmakiola.calendula.ui.common.GroupedRow +import de.jeanlucmakiola.floret.components.CollapsingScaffold +import de.jeanlucmakiola.floret.components.GroupedRow import de.jeanlucmakiola.calendula.ui.common.IMPLEMENTED_VIEWS import de.jeanlucmakiola.calendula.ui.common.labelRes import de.jeanlucmakiola.calendula.ui.common.CalendarColorChip -import de.jeanlucmakiola.calendula.ui.common.OptionPicker -import de.jeanlucmakiola.calendula.ui.common.Position +import de.jeanlucmakiola.floret.components.OptionPicker +import de.jeanlucmakiola.floret.components.Position import de.jeanlucmakiola.calendula.ui.common.REMINDER_PRESETS import de.jeanlucmakiola.calendula.ui.common.ReminderDefaultPicker import de.jeanlucmakiola.calendula.ui.common.TimePickerAlert -import de.jeanlucmakiola.calendula.ui.common.positionOf +import de.jeanlucmakiola.floret.components.positionOf import de.jeanlucmakiola.calendula.ui.common.reminderLeadTimeLabel import de.jeanlucmakiola.calendula.ui.common.rememberCalendarSlideSpec import de.jeanlucmakiola.calendula.ui.common.currentLocale @@ -192,7 +192,7 @@ private fun SettingsHub( onOpenSection: (SettingsSection) -> Unit, onManageCalendars: () -> Unit, ) { - CollapsingScaffold(title = stringResource(R.string.settings_title), onBack = onBack) { + CollapsingScaffold(title = stringResource(R.string.settings_title), onBack = onBack, predictiveBack = true) { Box(Modifier.padding(horizontal = 16.dp)) { AboutCard() } Spacer(Modifier.height(16.dp)) @@ -312,6 +312,7 @@ private fun LanguageRow(position: Position) { if (showDialog) { OptionPicker( title = stringResource(R.string.settings_language), + predictiveBack = true, options = options, selected = current, label = { languageLabel(it) }, @@ -479,6 +480,7 @@ private fun AppearanceScreen( CollapsingScaffold( title = stringResource(R.string.settings_section_appearance), onBack = onBack, + predictiveBack = true, ) { // Theme & colour GroupedRow( @@ -575,6 +577,7 @@ private fun AppearanceScreen( if (showTheme) { OptionPicker( title = stringResource(R.string.settings_theme), + predictiveBack = true, options = ThemeMode.entries, selected = state.themeMode, label = { themeLabel(it) }, @@ -585,6 +588,7 @@ private fun AppearanceScreen( if (showWeekStart) { OptionPicker( title = stringResource(R.string.settings_week_start), + predictiveBack = true, options = WEEK_START_OPTIONS, selected = state.weekStart, label = { weekStartLabel(it) }, @@ -613,6 +617,7 @@ private fun AppearanceScreen( if (showTimeFormat) { OptionPicker( title = stringResource(R.string.settings_time_format), + predictiveBack = true, options = TimeFormatPref.entries, selected = state.timeFormat, label = { timeFormatLabel(it) }, @@ -623,6 +628,7 @@ private fun AppearanceScreen( if (showDefaultView) { OptionPicker( title = stringResource(R.string.settings_default_view), + predictiveBack = true, options = IMPLEMENTED_VIEWS, selected = state.defaultView, label = { stringResource(it.labelRes) }, @@ -641,6 +647,7 @@ private fun EventFormScreen( CollapsingScaffold( title = stringResource(R.string.settings_section_event_form), onBack = onBack, + predictiveBack = true, ) { Text( text = stringResource(R.string.settings_form_fields_hint), @@ -751,6 +758,7 @@ private fun NotificationsScreen( CollapsingScaffold( title = stringResource(R.string.settings_section_notifications), onBack = onBack, + predictiveBack = true, ) { GroupedRow( title = stringResource(R.string.settings_reminders), @@ -900,6 +908,7 @@ private fun NotificationsScreen( if (showSnooze) { OptionPicker( title = stringResource(R.string.settings_snooze_duration), + predictiveBack = true, options = SNOOZE_PRESETS, selected = state.snoozeMinutes, label = { snoozeDurationLabel(it) }, diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index acab1b9..a5d692f 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -266,6 +266,7 @@ Einstellungen Zurück + Zurück Darstellung Design System diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2d55635..6d3b502 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -266,6 +266,8 @@ Settings Back + + Back Appearance Theme System diff --git a/floret-kit b/floret-kit index 86f4480..d9e4e87 160000 --- a/floret-kit +++ b/floret-kit @@ -1 +1 @@ -Subproject commit 86f44805d16ceee9708aa11014fa67ab951dc531 +Subproject commit d9e4e877cc05450bcf121e2cb4140d0efda96f8e