One rollover-following today flow for the view models
This commit is contained in:
@@ -4,10 +4,14 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import de.jeanlucmakiola.floret.android.broadcastTicks
|
import de.jeanlucmakiola.floret.android.broadcastTicks
|
||||||
|
import de.jeanlucmakiola.floret.android.stateWhileSubscribed
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.flow.transformLatest
|
import kotlinx.coroutines.flow.transformLatest
|
||||||
import kotlinx.datetime.LocalDate
|
import kotlinx.datetime.LocalDate
|
||||||
import kotlinx.datetime.TimeZone
|
import kotlinx.datetime.TimeZone
|
||||||
@@ -43,3 +47,21 @@ class AndroidTodaySource @Inject constructor(
|
|||||||
private const val MINUTE_MILLIS = 60_000L
|
private const val MINUTE_MILLIS = 60_000L
|
||||||
|
|
||||||
fun currentDate(): LocalDate = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()).date
|
fun currentDate(): LocalDate = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()).date
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Today as a hot flow seeded with [initial]. [onRollover] runs with the previous
|
||||||
|
* and the new date each time the day changes while collected, so a screen left
|
||||||
|
* open over midnight can move off yesterday (#373).
|
||||||
|
*/
|
||||||
|
fun Flow<LocalDate>.stateFollowingDays(
|
||||||
|
scope: CoroutineScope,
|
||||||
|
initial: LocalDate,
|
||||||
|
onRollover: (old: LocalDate, new: LocalDate) -> Unit,
|
||||||
|
): StateFlow<LocalDate> {
|
||||||
|
var last = initial
|
||||||
|
return onEach { date ->
|
||||||
|
val old = last
|
||||||
|
last = date
|
||||||
|
if (old != date) onRollover(old, date)
|
||||||
|
}.stateWhileSubscribed(scope, initial)
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import de.jeanlucmakiola.calendula.data.prefs.SettingsPrefs
|
|||||||
import de.jeanlucmakiola.calendula.data.prefs.firstDayOfWeek
|
import de.jeanlucmakiola.calendula.data.prefs.firstDayOfWeek
|
||||||
import de.jeanlucmakiola.calendula.data.time.TodaySource
|
import de.jeanlucmakiola.calendula.data.time.TodaySource
|
||||||
import de.jeanlucmakiola.calendula.data.time.currentDate
|
import de.jeanlucmakiola.calendula.data.time.currentDate
|
||||||
|
import de.jeanlucmakiola.calendula.data.time.stateFollowingDays
|
||||||
import de.jeanlucmakiola.calendula.domain.CalendarSource
|
import de.jeanlucmakiola.calendula.domain.CalendarSource
|
||||||
import de.jeanlucmakiola.calendula.domain.EventInstance
|
import de.jeanlucmakiola.calendula.domain.EventInstance
|
||||||
import de.jeanlucmakiola.calendula.domain.FailureReason
|
import de.jeanlucmakiola.calendula.domain.FailureReason
|
||||||
@@ -26,7 +27,6 @@ import kotlinx.coroutines.flow.combine
|
|||||||
import kotlinx.coroutines.flow.flatMapLatest
|
import kotlinx.coroutines.flow.flatMapLatest
|
||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.flowOn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.datetime.DateTimeUnit
|
import kotlinx.datetime.DateTimeUnit
|
||||||
import kotlinx.datetime.DayOfWeek
|
import kotlinx.datetime.DayOfWeek
|
||||||
@@ -98,21 +98,14 @@ class AgendaViewModel @Inject constructor(
|
|||||||
var lastTopDate: LocalDate? = null
|
var lastTopDate: LocalDate? = null
|
||||||
private set
|
private set
|
||||||
|
|
||||||
private var lastToday = todayDate
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Today, kept current across midnight (#373). An agenda still starting on
|
* Today, kept current across midnight (#373). An agenda still starting on
|
||||||
* yesterday moves on to the new day; one jumped elsewhere stays put.
|
* yesterday moves on to the new day; one jumped elsewhere stays put.
|
||||||
*/
|
*/
|
||||||
private val today: StateFlow<LocalDate> = todaySource.today
|
private val today: StateFlow<LocalDate> =
|
||||||
.onEach { date ->
|
todaySource.today.stateFollowingDays(viewModelScope, todayDate) { old, date ->
|
||||||
val old = lastToday
|
if (_window.value.anchor == old) _window.value = _window.value.copy(anchor = date)
|
||||||
lastToday = date
|
|
||||||
if (old != date && _window.value.anchor == old) {
|
|
||||||
_window.value = _window.value.copy(anchor = date)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.stateWhileSubscribed(viewModelScope, todayDate)
|
|
||||||
|
|
||||||
// A transient, in-view override of the saved agenda range. Held in memory
|
// A transient, in-view override of the saved agenda range. Held in memory
|
||||||
// (not persisted), so it survives view switches and rotation within the
|
// (not persisted), so it survives view switches and rotation within the
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import de.jeanlucmakiola.calendula.data.prefs.SettingsPrefs
|
|||||||
import de.jeanlucmakiola.calendula.data.prefs.firstDayOfWeek
|
import de.jeanlucmakiola.calendula.data.prefs.firstDayOfWeek
|
||||||
import de.jeanlucmakiola.calendula.data.time.TodaySource
|
import de.jeanlucmakiola.calendula.data.time.TodaySource
|
||||||
import de.jeanlucmakiola.calendula.data.time.currentDate
|
import de.jeanlucmakiola.calendula.data.time.currentDate
|
||||||
|
import de.jeanlucmakiola.calendula.data.time.stateFollowingDays
|
||||||
import de.jeanlucmakiola.calendula.domain.CalendarSource
|
import de.jeanlucmakiola.calendula.domain.CalendarSource
|
||||||
import de.jeanlucmakiola.calendula.domain.EventInstance
|
import de.jeanlucmakiola.calendula.domain.EventInstance
|
||||||
import de.jeanlucmakiola.calendula.domain.FailureReason
|
import de.jeanlucmakiola.calendula.domain.FailureReason
|
||||||
@@ -90,16 +91,9 @@ class MonthViewModel @Inject constructor(
|
|||||||
private val todayDate: LocalDate
|
private val todayDate: LocalDate
|
||||||
get() = currentDate()
|
get() = currentDate()
|
||||||
|
|
||||||
private var lastToday = todayDate
|
|
||||||
|
|
||||||
/** Today, kept current across midnight so a grid left open doesn't mark yesterday (#373). */
|
/** Today, kept current across midnight so a grid left open doesn't mark yesterday (#373). */
|
||||||
val today: StateFlow<LocalDate> = todaySource.today
|
val today: StateFlow<LocalDate> =
|
||||||
.onEach { date ->
|
todaySource.today.stateFollowingDays(viewModelScope, todayDate, ::followToday)
|
||||||
val old = lastToday
|
|
||||||
lastToday = date
|
|
||||||
if (old != date) followToday(old, date)
|
|
||||||
}
|
|
||||||
.stateWhileSubscribed(viewModelScope, todayDate)
|
|
||||||
|
|
||||||
private val _month = MutableStateFlow(todayDate.yearMonth)
|
private val _month = MutableStateFlow(todayDate.yearMonth)
|
||||||
val month: StateFlow<YearMonth> = _month
|
val month: StateFlow<YearMonth> = _month
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import de.jeanlucmakiola.calendula.data.prefs.resolveFirstDay
|
|||||||
import de.jeanlucmakiola.calendula.data.time.TodaySource
|
import de.jeanlucmakiola.calendula.data.time.TodaySource
|
||||||
import de.jeanlucmakiola.calendula.data.time.ZoneSource
|
import de.jeanlucmakiola.calendula.data.time.ZoneSource
|
||||||
import de.jeanlucmakiola.calendula.data.time.currentDate
|
import de.jeanlucmakiola.calendula.data.time.currentDate
|
||||||
|
import de.jeanlucmakiola.calendula.data.time.stateFollowingDays
|
||||||
import de.jeanlucmakiola.calendula.domain.CalendarSource
|
import de.jeanlucmakiola.calendula.domain.CalendarSource
|
||||||
import de.jeanlucmakiola.calendula.domain.EventInstance
|
import de.jeanlucmakiola.calendula.domain.EventInstance
|
||||||
import de.jeanlucmakiola.calendula.domain.displayPriority
|
import de.jeanlucmakiola.calendula.domain.displayPriority
|
||||||
@@ -32,7 +33,6 @@ import kotlinx.coroutines.flow.flatMapLatest
|
|||||||
import kotlinx.coroutines.flow.flowOf
|
import kotlinx.coroutines.flow.flowOf
|
||||||
import kotlinx.coroutines.flow.flowOn
|
import kotlinx.coroutines.flow.flowOn
|
||||||
import kotlinx.coroutines.flow.map
|
import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.onEach
|
|
||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.datetime.DateTimeUnit
|
import kotlinx.datetime.DateTimeUnit
|
||||||
import kotlinx.datetime.DayOfWeek
|
import kotlinx.datetime.DayOfWeek
|
||||||
@@ -124,16 +124,9 @@ abstract class PagedTimelineViewModel(
|
|||||||
val rule: StateFlow<(LocalDate) -> PageGrid> =
|
val rule: StateFlow<(LocalDate) -> PageGrid> =
|
||||||
gridRule.stateIn(viewModelScope, SharingStarted.Eagerly, initialRule)
|
gridRule.stateIn(viewModelScope, SharingStarted.Eagerly, initialRule)
|
||||||
|
|
||||||
private var lastToday = todayDate
|
|
||||||
|
|
||||||
/** Today, kept current across midnight so a page left open doesn't mark yesterday (#373). */
|
/** Today, kept current across midnight so a page left open doesn't mark yesterday (#373). */
|
||||||
private val today: StateFlow<LocalDate> = todaySource.today
|
private val today: StateFlow<LocalDate> =
|
||||||
.onEach { date ->
|
todaySource.today.stateFollowingDays(viewModelScope, todayDate, ::followToday)
|
||||||
val old = lastToday
|
|
||||||
lastToday = date
|
|
||||||
if (old != date) followToday(old, date)
|
|
||||||
}
|
|
||||||
.stateWhileSubscribed(viewModelScope, todayDate)
|
|
||||||
|
|
||||||
private val position: StateFlow<PagerPosition> =
|
private val position: StateFlow<PagerPosition> =
|
||||||
combine(_anchor, rule) { anchor, rule -> positionOf(anchor, rule) }
|
combine(_anchor, rule) { anchor, rule -> positionOf(anchor, rule) }
|
||||||
|
|||||||
Reference in New Issue
Block a user