Stacked on #409 (its commit shows here until it merges). Bumps floret-kit to 5093e1c (floret main, floret-kit#14) and deletes the local copies of what moved there. Widget code untouched. - `GroupedRow(checked)` for the check-mark rows; `GroupedSwitchRow` for 16 switch rows; `OptionRows` in the three settings preview pickers; `CustomExpandRow` for the three "Custom" picker rows - `IconInfoCard` replaces `EditCard` and `DetailCard`; `GroupedHint` replaces `SettingsHint` / `HintText` / `PickerDescription` - Onboarding steps use `OnboardingScaffold(headline, supporting)` and `OnboardingPrimaryButton` - `LanguagePickerRow(header, predictiveBack)` replaces the local `LanguageRow` - `relativeTimeAgo`, `ReminderOverride.minutesOrEmpty()` - New `core-android` dependency: `goAsync { }` in the reminder receivers, `hasPermission` for all non-widget permission checks, `broadcastTicks` behind TodaySource / ZoneSource, `setWakeup` in the reminder and snooze alarms, `stateWhileSubscribed` for the 39 `WhileSubscribed(5_000)` sites One visible change: the expand rows in Event form and Notification settings show floret's rotating chevron instead of swapping ExpandLess/ExpandMore. Kept local on purpose: the Reliable delivery row (no selected highlight today), the Dynamic colour switch (isn't dimmed when unavailable), HiddenCalendarsStep's headline (needs its inset padding) and ViewStep's onboarding block (headlineSmall). Co-authored-by: Jean-Luc Makiola <business@jeanlucmakiola.de> Reviewed-on: https://codeberg.org/jlmakiola/calendula/pulls/410
81 lines
3.2 KiB
Kotlin
81 lines
3.2 KiB
Kotlin
package de.jeanlucmakiola.calendula.ui
|
|
|
|
import androidx.lifecycle.ViewModel
|
|
import androidx.lifecycle.viewModelScope
|
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
|
import de.jeanlucmakiola.calendula.data.prefs.SettingsPrefs
|
|
import de.jeanlucmakiola.calendula.data.time.TodaySource
|
|
import de.jeanlucmakiola.calendula.data.time.currentDate
|
|
import de.jeanlucmakiola.calendula.ui.common.CalendarView
|
|
import de.jeanlucmakiola.calendula.ui.common.IMPLEMENTED_VIEWS
|
|
import de.jeanlucmakiola.floret.android.stateWhileSubscribed
|
|
import kotlinx.coroutines.flow.StateFlow
|
|
import kotlinx.coroutines.flow.map
|
|
import kotlinx.coroutines.flow.first
|
|
import kotlinx.datetime.LocalDate
|
|
import javax.inject.Inject
|
|
|
|
/**
|
|
* Supplies [CalendarHost] with the user's default startup view (M1). Held as a
|
|
* nullable [StateFlow] so the host can wait for DataStore's first emission before
|
|
* seeding its view back stack — rendering nothing for that first frame rather
|
|
* than flashing the old hard-coded Week view and then correcting it.
|
|
*/
|
|
@HiltViewModel
|
|
class CalendarHostViewModel @Inject constructor(
|
|
prefs: SettingsPrefs,
|
|
todaySource: TodaySource,
|
|
) : ViewModel() {
|
|
|
|
/** Today, kept current across midnight so the shared focus can follow it (#373). */
|
|
val today: StateFlow<LocalDate> = todaySource.today.stateWhileSubscribed(
|
|
scope = viewModelScope,
|
|
initialValue = currentDate(),
|
|
)
|
|
|
|
val defaultView: StateFlow<CalendarView?> = prefs.defaultView.stateWhileSubscribed(
|
|
scope = viewModelScope,
|
|
initialValue = null,
|
|
)
|
|
|
|
/** Views the top-bar quick-switch pill cycles through, in the user's order (#24). */
|
|
val quickSwitchViews: StateFlow<List<CalendarView>> = prefs.quickSwitchConfig
|
|
.map { it.cycle }
|
|
.stateWhileSubscribed(
|
|
scope = viewModelScope,
|
|
initialValue = IMPLEMENTED_VIEWS,
|
|
)
|
|
|
|
/** Order of the views in the navigation drawer (#24); every view always shown. */
|
|
val drawerViewOrder: StateFlow<List<CalendarView>> = prefs.drawerViewOrder
|
|
.stateWhileSubscribed(
|
|
scope = viewModelScope,
|
|
initialValue = IMPLEMENTED_VIEWS,
|
|
)
|
|
|
|
/** Whether each view's jump-to-today control lives in the top bar, not the FAB (#60). */
|
|
val todayButtonInToolbar: StateFlow<Boolean> = prefs.todayButtonInToolbar
|
|
.stateWhileSubscribed(
|
|
scope = viewModelScope,
|
|
initialValue = false,
|
|
)
|
|
|
|
/**
|
|
* Whether events may be dragged to another slot to reschedule them (#68, #173).
|
|
* Off until the stored value arrives, even though the preference itself defaults
|
|
* on: the wrong guess costs an enabled user a gesture for the few frames a cold
|
|
* start takes to read DataStore, but re-arms the one thing a disabled user
|
|
* switched off to be rid of.
|
|
*/
|
|
val dragToReschedule: StateFlow<Boolean> = prefs.dragToReschedule
|
|
.stateWhileSubscribed(
|
|
scope = viewModelScope,
|
|
initialValue = false,
|
|
)
|
|
|
|
private val tapOpensEditorPref = prefs.tapOpensEditor
|
|
|
|
/** Whether tapping an event opens the edit form rather than the detail screen (#178). */
|
|
suspend fun tapOpensEditor(): Boolean = tapOpensEditorPref.first()
|
|
}
|