From 976d496d21bc6a855eb0d4dbee1511ebe3373bd9 Mon Sep 17 00:00:00 2001 From: Jean-Luc Makiola Date: Mon, 6 Jul 2026 21:25:40 +0200 Subject: [PATCH] reminders: adopt floret-kit multi-value override model Bumps the floret-kit submodule to the multi-value core-reminders API (ReminderOverride.Minutes now a List) and adapts the per-list override plumbing + pickers to it. Agendula stays single-reminder: overrides are one-element (or empty) lists, reminderLeadFor takes firstOrNull, and the single-select picker wraps/unwraps listOf. On-disk format is unchanged (single values round-trip byte-identically). Verified: :app:compileDebugKotlin. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../agendula/data/prefs/SettingsPrefs.kt | 10 ++++++---- .../agendula/ui/common/ReminderLeadPicker.kt | 10 ++++++---- .../agendula/ui/settings/SettingsScreen.kt | 17 ++++++----------- floret-kit | 2 +- 4 files changed, 19 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/de/jeanlucmakiola/agendula/data/prefs/SettingsPrefs.kt b/app/src/main/java/de/jeanlucmakiola/agendula/data/prefs/SettingsPrefs.kt index 0f60923..4508baf 100644 --- a/app/src/main/java/de/jeanlucmakiola/agendula/data/prefs/SettingsPrefs.kt +++ b/app/src/main/java/de/jeanlucmakiola/agendula/data/prefs/SettingsPrefs.kt @@ -12,7 +12,7 @@ import de.jeanlucmakiola.agendula.domain.TaskFormField import de.jeanlucmakiola.floret.reminders.ReminderOverride import de.jeanlucmakiola.floret.reminders.ReminderOverrideCodec import de.jeanlucmakiola.floret.reminders.applyReminderOverride -import de.jeanlucmakiola.floret.reminders.reminderLeadFor +import de.jeanlucmakiola.floret.reminders.reminderLeadsFor import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import javax.inject.Inject @@ -39,15 +39,17 @@ data class Settings( val bottomAddBar: Boolean = false, /** * Per-list overrides of [reminderLeadMinutes]: a list present in the map - * overrides the global default (a null value = no reminder); absent = inherit. + * overrides the global default (an empty list = no reminder); absent = + * inherit. Agendula offers a single reminder, so each override is a + * one-element (or empty) list. */ - val perListReminderOverride: Map = emptyMap(), + val perListReminderOverride: Map> = emptyMap(), /** Optional edit-form fields shown by default; the rest sit behind "More fields". */ val defaultEditFields: Set = emptySet(), ) { /** The lead time for a task in [listId]: its override if set, else the global default. */ fun reminderLeadFor(listId: Long): Int? = - perListReminderOverride.reminderLeadFor(listId, reminderLeadMinutes) + perListReminderOverride.reminderLeadsFor(listId, listOf(reminderLeadMinutes)).firstOrNull() } /** App preferences, backed by DataStore. Mirrors Calendula's prefs shape. */ diff --git a/app/src/main/java/de/jeanlucmakiola/agendula/ui/common/ReminderLeadPicker.kt b/app/src/main/java/de/jeanlucmakiola/agendula/ui/common/ReminderLeadPicker.kt index a4ed218..fe68cac 100644 --- a/app/src/main/java/de/jeanlucmakiola/agendula/ui/common/ReminderLeadPicker.kt +++ b/app/src/main/java/de/jeanlucmakiola/agendula/ui/common/ReminderLeadPicker.kt @@ -54,7 +54,9 @@ fun ReminderLeadPicker( onDismiss: () -> Unit, presets: List = REMINDER_PRESETS, ) { - val selectedMinutes = (selected as? ReminderOverride.Minutes)?.minutes + // Agendula is single-reminder: an override carries a one-element list, so + // take the single value for this single-select picker. + val selectedMinutes = (selected as? ReminderOverride.Minutes)?.minutes?.firstOrNull() val customSelected = selectedMinutes != null && selectedMinutes !in presets val seed = decomposeReminderMinutes(selectedMinutes?.takeIf { customSelected }) @@ -65,7 +67,7 @@ fun ReminderLeadPicker( val options = buildList { if (allowInherit) add(ReminderOverride.Inherit) if (allowNone) add(ReminderOverride.None) - presets.forEach { add(ReminderOverride.Minutes(it)) } + presets.forEach { add(ReminderOverride.Minutes(listOf(it))) } } val rowCount = options.size + 1 // + the custom row @@ -105,7 +107,7 @@ fun ReminderLeadPicker( unit = unit, onUnitChange = { unit = it }, onConfirm = { minutes -> - onSelect(ReminderOverride.Minutes(minutes)) + onSelect(ReminderOverride.Minutes(listOf(minutes))) onDismiss() }, ) @@ -168,5 +170,5 @@ private fun CustomReminderEditor( private fun reminderOverrideLabel(override: ReminderOverride): String = when (override) { ReminderOverride.Inherit -> stringResource(R.string.reminder_use_default) ReminderOverride.None -> stringResource(R.string.reminder_none) - is ReminderOverride.Minutes -> reminderLeadTimeLabel(override.minutes) + is ReminderOverride.Minutes -> reminderLeadTimeLabel(override.minutes.first()) } diff --git a/app/src/main/java/de/jeanlucmakiola/agendula/ui/settings/SettingsScreen.kt b/app/src/main/java/de/jeanlucmakiola/agendula/ui/settings/SettingsScreen.kt index 3f518a4..465f5ba 100644 --- a/app/src/main/java/de/jeanlucmakiola/agendula/ui/settings/SettingsScreen.kt +++ b/app/src/main/java/de/jeanlucmakiola/agendula/ui/settings/SettingsScreen.kt @@ -94,6 +94,7 @@ 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.reminderOverrideFor import de.jeanlucmakiola.agendula.ui.common.reminderLeadTimeLabel /** The settings sub-screens reached from the hub's category rows. */ @@ -483,10 +484,10 @@ private fun RemindersScreen( if (showOffset) { ReminderLeadPicker( title = stringResource(R.string.settings_default_reminder), - selected = ReminderOverride.Minutes(state.settings.reminderLeadMinutes), + selected = ReminderOverride.Minutes(listOf(state.settings.reminderLeadMinutes)), allowInherit = false, allowNone = false, - onSelect = { if (it is ReminderOverride.Minutes) viewModel.setReminderLeadMinutes(it.minutes) }, + onSelect = { if (it is ReminderOverride.Minutes) viewModel.setReminderLeadMinutes(it.minutes.first()) }, onDismiss = { showOffset = false }, ) } @@ -504,14 +505,8 @@ private fun RemindersScreen( } /** The stored override for [listId], as a picker choice (absent → inherit). */ -private fun listOverrideChoice(state: SettingsUiState, listId: Long): ReminderOverride { - val map = state.settings.perListReminderOverride - return when { - !map.containsKey(listId) -> ReminderOverride.Inherit - map[listId] == null -> ReminderOverride.None - else -> ReminderOverride.Minutes(map.getValue(listId)!!) - } -} +private fun listOverrideChoice(state: SettingsUiState, listId: Long): ReminderOverride = + state.settings.perListReminderOverride.reminderOverrideFor(listId) /** Row summary for a list: its override, or the inherited global default. */ @Composable @@ -519,7 +514,7 @@ private fun listOverrideSummary(choice: ReminderOverride, globalDefault: Int): S ReminderOverride.Inherit -> stringResource(R.string.settings_list_reminder_inherits, reminderLeadTimeLabel(globalDefault)) ReminderOverride.None -> stringResource(R.string.reminder_none) - is ReminderOverride.Minutes -> reminderLeadTimeLabel(choice.minutes) + is ReminderOverride.Minutes -> reminderLeadTimeLabel(choice.minutes.first()) } // --------------------------------------------------------------------------- diff --git a/floret-kit b/floret-kit index 566caf4..5a576c4 160000 --- a/floret-kit +++ b/floret-kit @@ -1 +1 @@ -Subproject commit 566caf430537ef1704b1283140b00d0eabe0630e +Subproject commit 5a576c4d288e469a75c396b365e6ace8290aa3d0