diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/settings/SettingsUiState.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/settings/SettingsUiState.kt index f1c1160..5d4dcf1 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/settings/SettingsUiState.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/settings/SettingsUiState.kt @@ -116,7 +116,7 @@ data class SettingsUiState( /** * State for the contact special-dates sub-page (issue #15). Exposed as its own - * flow rather than folded into [SettingsUiState] (whose combine is already full). + * flow rather than folded into [SettingsUiState]. * [titleTemplates] is always populated — a blank stored template resolves to the * localized default so the editor never shows an empty field. */ diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/settings/SettingsViewModel.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/settings/SettingsViewModel.kt index c336a0f..cbbe707 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/settings/SettingsViewModel.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/settings/SettingsViewModel.kt @@ -6,6 +6,7 @@ import android.os.Build import androidx.glance.appwidget.GlanceAppWidgetManager import androidx.glance.appwidget.state.updateAppWidgetState import androidx.glance.appwidget.updateAll +import androidx.datastore.preferences.core.Preferences import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel @@ -23,7 +24,14 @@ import de.jeanlucmakiola.floret.di.IoDispatcher import de.jeanlucmakiola.floret.reminders.ReminderOverride import de.jeanlucmakiola.floret.reminders.reminderOverrideFor import de.jeanlucmakiola.calendula.data.prefs.PastEventDisplay +import de.jeanlucmakiola.calendula.data.prefs.SettingsKeys import de.jeanlucmakiola.calendula.data.prefs.SettingsPrefs +import de.jeanlucmakiola.calendula.data.prefs.specialDatesCalendars +import de.jeanlucmakiola.calendula.data.prefs.specialDatesStatus +import de.jeanlucmakiola.calendula.data.prefs.specialDatesTitleTemplates +import de.jeanlucmakiola.calendula.data.prefs.specialDatesTypes +import de.jeanlucmakiola.calendula.data.prefs.timelineHours +import de.jeanlucmakiola.floret.prefs.get import de.jeanlucmakiola.calendula.data.prefs.SpecialDatesStalledReason import de.jeanlucmakiola.floret.prefs.ThemeMode import de.jeanlucmakiola.calendula.data.prefs.TimeFormatPref @@ -36,7 +44,6 @@ import de.jeanlucmakiola.calendula.domain.contacts.SpecialDateType import de.jeanlucmakiola.calendula.ui.agenda.AgendaRange import de.jeanlucmakiola.calendula.ui.agenda.storageValue import de.jeanlucmakiola.calendula.ui.common.CalendarView -import de.jeanlucmakiola.calendula.ui.common.QuickSwitchConfig import de.jeanlucmakiola.calendula.ui.common.TimelineHours import de.jeanlucmakiola.calendula.ui.common.TimelineScale import de.jeanlucmakiola.calendula.ui.month.MonthViewStyle @@ -89,163 +96,66 @@ class SettingsViewModel @Inject constructor( .catch { emit(emptyList()) } val state: StateFlow = - combine( - // combine() types up to five flows, so the prefs split into two - // groups that fold together in the outer combine. - combine( - prefs.themeMode, - prefs.dynamicColor, - prefs.weekStart, - prefs.defaultFormFields, - prefs.remindersEnabled, - ) { theme, dynamic, weekStart, formFields, reminders -> - SettingsUiState( - themeMode = theme, - dynamicColor = dynamic && dynamicColorAvailable, - dynamicColorAvailable = dynamicColorAvailable, - weekStart = weekStart, - defaultFormFields = formFields, - remindersEnabled = reminders, - ) - }, - combine( - prefs.allowColorOnUnsupportedCalendars, - prefs.defaultReminderMinutes, - prefs.defaultAllDayReminderMinutes, - prefs.allDayReminderTimeMinutes, - prefs.snoozeMinutes, - ) { allowColor, defaultReminder, allDayReminder, allDayReminderTime, snooze -> - ReminderDefaults( - allowColor, defaultReminder, allDayReminder, allDayReminderTime, snooze, - ) - }, - combine( - prefs.perCalendarReminderOverride, - prefs.perCalendarAllDayReminderOverride, - writableCalendars, - prefs.managedCalendarIds, - // The new-event duration defaults (#54) fold into one flow so they - // fit this group — the outer combine is at its five-arg limit. - combine( - prefs.defaultEventDurationMinutes, - prefs.perCalendarEventDuration, - ) { duration, perCalendar -> EventDurations(duration, perCalendar) }, - ) { overrides, allDayOverrides, calendars, managedIds, durations -> - ReminderOverrides(overrides, allDayOverrides, calendars, managedIds, durations) - }, - combine( - prefs.defaultView, - prefs.agendaScreenRange, - prefs.agendaWidgetRange, - prefs.timeFormat, - // Display toggles folded into one flow so they fit this group — - // the outer combine is already at its five-arg limit. - combine( - prefs.showHourGrid, - prefs.showWeekNumbers, - prefs.agendaShowToday, - prefs.softenCalendarColors, - combine( - prefs.todayButtonInToolbar, - combine(prefs.dragToReschedule, prefs.tapOpensEditor, ::Pair), - prefs.multiDayCount, - ::Triple, - ), - ) { hourLines, weekNumbers, showToday, soften, (todayInToolbar, gestures, multiDay) -> - DisplayToggles( - hourLines, weekNumbers, showToday, soften, todayInToolbar, - dragToReschedule = gestures.first, - tapOpensEditor = gestures.second, - multiDayCount = multiDay, - ) - }, - ) { view, screenRange, widgetRange, timeFormat, toggles -> - ViewSettings( - view, screenRange, widgetRange, timeFormat, - showHourGrid = toggles.showHourGrid, - showWeekNumbers = toggles.showWeekNumbers, - agendaShowToday = toggles.agendaShowToday, - softenColors = toggles.softenColors, - todayButtonInToolbar = toggles.todayButtonInToolbar, - dragToReschedule = toggles.dragToReschedule, - tapOpensEditor = toggles.tapOpensEditor, - multiDayCount = toggles.multiDayCount, - ) - }, - combine( - prefs.agendaShowRangeBar, - prefs.autofocusEventTitle, - prefs.pastEventDisplay, - prefs.dimCompletedEvents, - // View customisation (#24) folded into one flow so it fits this - // group — the outer combine is already at its five-arg limit. - combine( - prefs.quickSwitchConfig, - prefs.drawerViewOrder, - prefs.monthViewStyle, - prefs.widgetSize, - combine(prefs.timelineScale, prefs.timelineHours, ::Pair), - ) { quickSwitch, drawer, monthStyle, widgetSize, (timelineScale, timelineHours) -> - ViewCustomization( - quickSwitch, drawer, monthStyle, widgetSize, timelineScale, timelineHours, - ) - }, - ) { showRangeBar, autofocus, pastEvents, dimCompleted, viewCustomization -> - MiscSettings(showRangeBar, autofocus, pastEvents, dimCompleted, viewCustomization) - }, - ) { base, defaults, overrides, views, misc -> - base.copy( - defaultView = views.defaultView, - agendaScreenRange = views.agendaScreenRange, - agendaWidgetRange = views.agendaWidgetRange, - timeFormat = views.timeFormat, - showHourGrid = views.showHourGrid, - showWeekNumbers = views.showWeekNumbers, - agendaShowToday = views.agendaShowToday, - softenColors = views.softenColors, - todayButtonInToolbar = views.todayButtonInToolbar, - dragToReschedule = views.dragToReschedule, - tapOpensEditor = views.tapOpensEditor, - multiDayCount = views.multiDayCount, - agendaShowRangeBar = misc.showRangeBar, - autofocusEventTitle = misc.autofocusEventTitle, - pastEventDisplay = misc.pastEventDisplay, - dimCompletedEvents = misc.dimCompletedEvents, - quickSwitchConfig = misc.viewCustomization.quickSwitch, - drawerViewOrder = misc.viewCustomization.drawerOrder, - monthViewStyle = misc.viewCustomization.monthViewStyle, - widgetSize = misc.viewCustomization.widgetSize, - timelineScale = misc.viewCustomization.timelineScale, - timelineHours = misc.viewCustomization.timelineHours, - allowColorOnUnsupportedCalendars = defaults.allowColor, - defaultReminderMinutes = defaults.defaultReminder, - defaultAllDayReminderMinutes = defaults.allDayReminder, - allDayReminderTimeMinutes = defaults.allDayReminderTime, - snoozeMinutes = defaults.snoozeMinutes, - perCalendarReminderOverride = overrides.timed, - perCalendarAllDayReminderOverride = overrides.allDay, - writableCalendars = overrides.calendars, - managedCalendarIds = overrides.managedIds, - defaultEventDurationMinutes = overrides.durations.default, - perCalendarEventDuration = overrides.durations.perCalendar, + combine(prefs.data, writableCalendars) { stored, calendars -> stored.toUiState(calendars) } + .stateWhileSubscribed( + scope = viewModelScope, + initialValue = SettingsUiState(dynamicColorAvailable = dynamicColorAvailable), ) - }.stateWhileSubscribed( - scope = viewModelScope, - initialValue = SettingsUiState(dynamicColorAvailable = dynamicColorAvailable), - ) + + private fun Preferences.toUiState(calendars: List) = SettingsUiState( + themeMode = this[SettingsKeys.themeMode], + dynamicColor = this[SettingsKeys.dynamicColor] && dynamicColorAvailable, + dynamicColorAvailable = dynamicColorAvailable, + softenColors = this[SettingsKeys.softenCalendarColors], + weekStart = this[SettingsKeys.weekStart], + timeFormat = this[SettingsKeys.timeFormat], + showHourGrid = this[SettingsKeys.showHourGrid], + multiDayCount = this[SettingsKeys.multiDayCount], + pastEventDisplay = this[SettingsKeys.pastEventDisplay], + dimCompletedEvents = this[SettingsKeys.dimCompletedEvents], + showWeekNumbers = this[SettingsKeys.showWeekNumbers], + todayButtonInToolbar = this[SettingsKeys.todayButtonInToolbar], + dragToReschedule = this[SettingsKeys.dragToReschedule], + tapOpensEditor = this[SettingsKeys.tapOpensEditor], + agendaScreenRange = this[SettingsKeys.agendaScreenRange], + agendaWidgetRange = this[SettingsKeys.agendaWidgetRange], + agendaShowToday = this[SettingsKeys.agendaShowToday], + agendaShowRangeBar = this[SettingsKeys.agendaShowRangeBar], + widgetSize = this[SettingsKeys.widgetSize], + defaultView = this[SettingsKeys.defaultView], + quickSwitchConfig = this[SettingsKeys.quickSwitchConfig], + monthViewStyle = this[SettingsKeys.monthViewStyle], + timelineScale = this[SettingsKeys.timelineScale], + timelineHours = timelineHours, + drawerViewOrder = this[SettingsKeys.drawerViewOrder], + defaultFormFields = this[SettingsKeys.defaultFormFields], + autofocusEventTitle = this[SettingsKeys.autofocusEventTitle], + defaultEventDurationMinutes = this[SettingsKeys.defaultEventDurationMinutes], + perCalendarEventDuration = this[SettingsKeys.perCalendarEventDuration], + remindersEnabled = this[SettingsKeys.remindersEnabled], + defaultReminderMinutes = this[SettingsKeys.defaultReminderMinutes], + defaultAllDayReminderMinutes = this[SettingsKeys.defaultAllDayReminderMinutes], + allDayReminderTimeMinutes = this[SettingsKeys.allDayReminderTimeMinutes], + snoozeMinutes = this[SettingsKeys.snoozeMinutes], + perCalendarReminderOverride = this[SettingsKeys.perCalendarReminderOverride], + perCalendarAllDayReminderOverride = this[SettingsKeys.perCalendarAllDayReminderOverride], + writableCalendars = calendars, + allowColorOnUnsupportedCalendars = this[SettingsKeys.allowColorOnUnsupportedCalendars], + managedCalendarIds = specialDatesCalendars.values.toSet(), + ) /** * The app-wide custom-font choice (issue #19). Its own flow — both this * screen and [MainActivity] (which builds the typography) read it - * independently of the main settings combine. + * independently of the main settings state. */ - val fontState: StateFlow = combine( - prefs.brandFont, - prefs.plainFont, - prefs.brandFontStamp, - prefs.plainFontStamp, - ) { brand, plain, brandStamp, plainStamp -> - AppFontSettings(brand = brand, plain = plain, brandStamp = brandStamp, plainStamp = plainStamp) + val fontState: StateFlow = prefs.data.map { + AppFontSettings( + brand = it[SettingsKeys.brandFont], + plain = it[SettingsKeys.plainFont], + brandStamp = it[SettingsKeys.brandFontStamp], + plainStamp = it[SettingsKeys.plainFontStamp], + ) }.stateWhileSubscribed( scope = viewModelScope, initialValue = AppFontSettings(), @@ -275,100 +185,26 @@ class SettingsViewModel @Inject constructor( // stale read and can leave the widget on an intermediate value. private val widgetRefreshMutex = Mutex() - private data class ReminderDefaults( - val allowColor: Boolean, - val defaultReminder: List, - val allDayReminder: List, - val allDayReminderTime: Int, - val snoozeMinutes: Int, - ) - - private data class ReminderOverrides( - val timed: Map>, - val allDay: Map>, - val calendars: List, - val managedIds: Set, - val durations: EventDurations, - ) - - private data class EventDurations( - val default: Int, - val perCalendar: Map, - ) - - private data class ViewSettings( - val defaultView: CalendarView, - val agendaScreenRange: AgendaRange, - val agendaWidgetRange: AgendaRange, - val timeFormat: TimeFormatPref, - val showHourGrid: Boolean, - val showWeekNumbers: Boolean, - val agendaShowToday: Boolean, - val softenColors: Boolean, - val todayButtonInToolbar: Boolean, - val dragToReschedule: Boolean, - val tapOpensEditor: Boolean, - val multiDayCount: Int, - ) - - private data class DisplayToggles( - val showHourGrid: Boolean, - val showWeekNumbers: Boolean, - val agendaShowToday: Boolean, - val softenColors: Boolean, - val todayButtonInToolbar: Boolean, - val dragToReschedule: Boolean, - val tapOpensEditor: Boolean, - val multiDayCount: Int, - ) - - private data class MiscSettings( - val showRangeBar: Boolean, - val autofocusEventTitle: Boolean, - val pastEventDisplay: PastEventDisplay, - val dimCompletedEvents: Boolean, - val viewCustomization: ViewCustomization, - ) - - private data class ViewCustomization( - val quickSwitch: QuickSwitchConfig, - val drawerOrder: List, - val monthViewStyle: MonthViewStyle, - val widgetSize: WidgetSize, - val timelineScale: TimelineScale, - val timelineHours: TimelineHours, - ) - - /** Contact special-dates sub-page (issue #15); its own flow — the main state is full. */ - val specialDatesState: StateFlow = combine( - combine( - prefs.specialDatesEnabled, - prefs.specialDatesTypes, - prefs.specialDatesTitleTemplates, - prefs.specialDatesShowYear, - prefs.specialDatesStatus, - ) { enabled, types, templates, showYear, status -> - SpecialDatesUiState( - enabled = enabled, - types = types, - // A blank stored template resolves to the localized default so the - // editor always shows something sensible. - titleTemplates = SpecialDateType.entries.associateWith { type -> - specialDatesSpec.resolveTitleTemplate(type, templates) - }, - showYear = showYear, - stalledPermission = status.stalled == SpecialDatesStalledReason.PermissionRevoked, - lastRun = status.lastRun, - ) - }, - prefs.specialDatesCalendars, - prefs.perCalendarAllDayReminderOverride, - ) { base, calendars, allDayOverrides -> - base.copy( + /** Contact special-dates sub-page (issue #15). */ + val specialDatesState: StateFlow = prefs.data.map { stored -> + val templates = stored.specialDatesTitleTemplates + val allDayOverrides = stored[SettingsKeys.perCalendarAllDayReminderOverride] + val status = stored.specialDatesStatus + SpecialDatesUiState( + enabled = stored[SettingsKeys.specialDatesEnabled], + types = stored.specialDatesTypes, + // A blank stored template resolves to the localized default so the + // editor always shows something sensible. + titleTemplates = SpecialDateType.entries.associateWith { type -> + specialDatesSpec.resolveTitleTemplate(type, templates) + }, // An override is always seeded on creation; present-empty = None. - reminderChoices = calendars.mapValues { (_, calendarId) -> + reminderChoices = stored.specialDatesCalendars.mapValues { (_, calendarId) -> allDayOverrides.reminderOverrideFor(calendarId) }, + showYear = stored[SettingsKeys.specialDatesShowYear], + stalledPermission = status.stalled == SpecialDatesStalledReason.PermissionRevoked, + lastRun = status.lastRun, ) }.stateWhileSubscribed( scope = viewModelScope, @@ -427,13 +263,9 @@ class SettingsViewModel @Inject constructor( /** Kick off an immediate reconcile (the "Sync now" action). */ fun syncSpecialDatesNow() = SpecialDatesScheduler.runNow(appContext) - fun setThemeMode(mode: ThemeMode) { - viewModelScope.launch { prefs.setThemeMode(mode) } - } + fun setThemeMode(mode: ThemeMode) = save { setThemeMode(mode) } - fun setDynamicColor(enabled: Boolean) { - viewModelScope.launch { prefs.setDynamicColor(enabled) } - } + fun setDynamicColor(enabled: Boolean) = save { setDynamicColor(enabled) } fun setSoftenColors(enabled: Boolean) { viewModelScope.launch { @@ -446,12 +278,10 @@ class SettingsViewModel @Inject constructor( } } - fun setFont(role: FontRole, token: String) { - viewModelScope.launch { - when (role) { - FontRole.BRAND -> prefs.setBrandFont(token) - FontRole.PLAIN -> prefs.setPlainFont(token) - } + fun setFont(role: FontRole, token: String) = save { + when (role) { + FontRole.BRAND -> setBrandFont(token) + FontRole.PLAIN -> setPlainFont(token) } } @@ -486,9 +316,7 @@ class SettingsViewModel @Inject constructor( } } - fun setAgendaScreenRange(range: AgendaRange) { - viewModelScope.launch { prefs.setAgendaScreenRange(range) } - } + fun setAgendaScreenRange(range: AgendaRange) = save { setAgendaScreenRange(range) } fun setAgendaWidgetRange(range: AgendaRange) { viewModelScope.launch { @@ -505,9 +333,7 @@ class SettingsViewModel @Inject constructor( } } - fun setAgendaShowRangeBar(enabled: Boolean) { - viewModelScope.launch { prefs.setAgendaShowRangeBar(enabled) } - } + fun setAgendaShowRangeBar(enabled: Boolean) = save { setAgendaShowRangeBar(enabled) } /** * Set the size the agenda widget draws its text at (#51), via the same @@ -541,33 +367,19 @@ class SettingsViewModel @Inject constructor( } } - fun setTimeFormat(pref: TimeFormatPref) { - viewModelScope.launch { prefs.setTimeFormat(pref) } - } + fun setTimeFormat(pref: TimeFormatPref) = save { setTimeFormat(pref) } - fun setMultiDayCount(count: Int) { - viewModelScope.launch { prefs.setMultiDayCount(count) } - } + fun setMultiDayCount(count: Int) = save { setMultiDayCount(count) } - fun setShowHourGrid(enabled: Boolean) { - viewModelScope.launch { prefs.setShowHourGrid(enabled) } - } + fun setShowHourGrid(enabled: Boolean) = save { setShowHourGrid(enabled) } - fun setShowWeekNumbers(enabled: Boolean) { - viewModelScope.launch { prefs.setShowWeekNumbers(enabled) } - } + fun setShowWeekNumbers(enabled: Boolean) = save { setShowWeekNumbers(enabled) } - fun setTodayButtonInToolbar(enabled: Boolean) { - viewModelScope.launch { prefs.setTodayButtonInToolbar(enabled) } - } + fun setTodayButtonInToolbar(enabled: Boolean) = save { setTodayButtonInToolbar(enabled) } - fun setDragToReschedule(enabled: Boolean) { - viewModelScope.launch { prefs.setDragToReschedule(enabled) } - } + fun setDragToReschedule(enabled: Boolean) = save { setDragToReschedule(enabled) } - fun setTapOpensEditor(enabled: Boolean) { - viewModelScope.launch { prefs.setTapOpensEditor(enabled) } - } + fun setTapOpensEditor(enabled: Boolean) = save { setTapOpensEditor(enabled) } /** * Switch the launcher label (#44). The card highlights at once, then settles @@ -598,53 +410,33 @@ class SettingsViewModel @Inject constructor( } } - fun setDimCompletedEvents(enabled: Boolean) { - viewModelScope.launch { prefs.setDimCompletedEvents(enabled) } - } + fun setDimCompletedEvents(enabled: Boolean) = save { setDimCompletedEvents(enabled) } - fun setDefaultView(view: CalendarView) { - viewModelScope.launch { prefs.setDefaultView(view) } - } + fun setDefaultView(view: CalendarView) = save { setDefaultView(view) } - fun setFormFieldDefault(field: EventFormField, enabled: Boolean) { - viewModelScope.launch { prefs.setFormFieldDefault(field, enabled) } - } + fun setFormFieldDefault(field: EventFormField, enabled: Boolean) = save { setFormFieldDefault(field, enabled) } /** * Enable or disable [view] in the quick-switch cycle, via an atomic * read-modify-write so a concurrent reorder can't clobber it. Any number of * views may be turned off; below two the pill hides itself (#150). */ - fun setQuickSwitchViewEnabled(view: CalendarView, enabled: Boolean) { - viewModelScope.launch { - prefs.updateQuickSwitch { config -> - config.copy( - enabled = if (enabled) config.enabled + view else config.enabled - view, - ) - } + fun setQuickSwitchViewEnabled(view: CalendarView, enabled: Boolean) = save { + updateQuickSwitch { config -> + config.copy(enabled = if (enabled) config.enabled + view else config.enabled - view) } } /** Reorder the quick-switch views (atomic read-modify-write; keeps the enabled set). */ - fun setQuickSwitchOrder(order: List) { - viewModelScope.launch { prefs.updateQuickSwitch { it.copy(order = order) } } - } + fun setQuickSwitchOrder(order: List) = save { updateQuickSwitch { it.copy(order = order) } } - fun setMonthViewStyle(style: MonthViewStyle) { - viewModelScope.launch { prefs.setMonthViewStyle(style) } - } + fun setMonthViewStyle(style: MonthViewStyle) = save { setMonthViewStyle(style) } - fun setTimelineScale(scale: TimelineScale) { - viewModelScope.launch { prefs.setTimelineScale(scale) } - } + fun setTimelineScale(scale: TimelineScale) = save { setTimelineScale(scale) } - fun setTimelineHours(hours: TimelineHours) { - viewModelScope.launch { prefs.setTimelineHours(hours) } - } + fun setTimelineHours(hours: TimelineHours) = save { setTimelineHours(hours) } - fun setDrawerViewOrder(order: List) { - viewModelScope.launch { prefs.setDrawerViewOrder(order) } - } + fun setDrawerViewOrder(order: List) = save { setDrawerViewOrder(order) } /** * A scan follows the write: switching reminders off cancels the scan alarm, @@ -657,26 +449,16 @@ class SettingsViewModel @Inject constructor( } } - fun setAutofocusEventTitle(enabled: Boolean) { - viewModelScope.launch { prefs.setAutofocusEventTitle(enabled) } - } + fun setAutofocusEventTitle(enabled: Boolean) = save { setAutofocusEventTitle(enabled) } - fun setDefaultEventDuration(minutes: Int) { - viewModelScope.launch { prefs.setDefaultEventDurationMinutes(minutes) } - } + fun setDefaultEventDuration(minutes: Int) = save { setDefaultEventDurationMinutes(minutes) } /** [minutes] null clears the override, so the calendar inherits the default. */ - fun setCalendarEventDuration(calendarId: Long, minutes: Int?) { - viewModelScope.launch { prefs.setCalendarEventDuration(calendarId, minutes) } - } + fun setCalendarEventDuration(calendarId: Long, minutes: Int?) = save { setCalendarEventDuration(calendarId, minutes) } - fun setDefaultReminderMinutes(minutes: List) { - viewModelScope.launch { prefs.setDefaultReminderMinutes(minutes) } - } + fun setDefaultReminderMinutes(minutes: List) = save { setDefaultReminderMinutes(minutes) } - fun setDefaultAllDayReminderMinutes(minutes: List) { - viewModelScope.launch { prefs.setDefaultAllDayReminderMinutes(minutes) } - } + fun setDefaultAllDayReminderMinutes(minutes: List) = save { setDefaultAllDayReminderMinutes(minutes) } /** The armed alarm was planned for the old hour, so re-plan against the new one. */ fun setAllDayReminderTimeMinutes(minutesOfDay: Int) { @@ -686,19 +468,15 @@ class SettingsViewModel @Inject constructor( } } - fun setSnoozeMinutes(minutes: Int) { - viewModelScope.launch { prefs.setSnoozeMinutes(minutes) } - } + fun setSnoozeMinutes(minutes: Int) = save { setSnoozeMinutes(minutes) } - fun setCalendarReminderOverride(calendarId: Long, override: ReminderOverride) { - viewModelScope.launch { prefs.setCalendarReminderOverride(calendarId, override) } - } + fun setCalendarReminderOverride(calendarId: Long, override: ReminderOverride) = save { setCalendarReminderOverride(calendarId, override) } - fun setCalendarAllDayReminderOverride(calendarId: Long, override: ReminderOverride) { - viewModelScope.launch { prefs.setCalendarAllDayReminderOverride(calendarId, override) } - } + fun setCalendarAllDayReminderOverride(calendarId: Long, override: ReminderOverride) = save { setCalendarAllDayReminderOverride(calendarId, override) } - fun setAllowColorOnUnsupportedCalendars(enabled: Boolean) { - viewModelScope.launch { prefs.setAllowColorOnUnsupportedCalendars(enabled) } + fun setAllowColorOnUnsupportedCalendars(enabled: Boolean) = save { setAllowColorOnUnsupportedCalendars(enabled) } + + private fun save(write: suspend SettingsPrefs.() -> Unit) { + viewModelScope.launch { prefs.write() } } }