forked from agzam/vyatsu-schedule
186 lines
6.6 KiB
Kotlin
186 lines
6.6 KiB
Kotlin
package agzam.vyatsu.ui.schedule
|
|
|
|
import agzam.vyatsu.domain.ScheduleDates
|
|
import agzam.vyatsu.domain.model.Schedule
|
|
import agzam.vyatsu.domain.repository.GroupRepository
|
|
import agzam.vyatsu.domain.repository.PreferencesRepository
|
|
import agzam.vyatsu.domain.repository.ScheduleRepository
|
|
import androidx.lifecycle.ViewModel
|
|
import androidx.lifecycle.viewModelScope
|
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|
import kotlinx.coroutines.flow.StateFlow
|
|
import kotlinx.coroutines.flow.asStateFlow
|
|
import kotlinx.coroutines.launch
|
|
import java.time.LocalDate
|
|
|
|
class ScheduleViewModel(
|
|
private val scheduleRepository: ScheduleRepository,
|
|
private val preferencesRepository: PreferencesRepository,
|
|
private val groupRepository: GroupRepository
|
|
) : ViewModel() {
|
|
|
|
private val _uiState = MutableStateFlow(ScheduleUiState())
|
|
val uiState: StateFlow<ScheduleUiState> = _uiState.asStateFlow()
|
|
|
|
private var currentGroupId: String? = null
|
|
|
|
init {
|
|
viewModelScope.launch {
|
|
val groupId = preferencesRepository.selectedGroupId()
|
|
if (groupId != null) {
|
|
selectGroup(groupId)
|
|
} else {
|
|
_uiState.value = _uiState.value.copy(noGroup = true, groupName = null)
|
|
}
|
|
}
|
|
}
|
|
|
|
fun selectGroup(groupId: String) {
|
|
currentGroupId = groupId
|
|
viewModelScope.launch {
|
|
preferencesRepository.setSelectedGroup(groupId)
|
|
val groupName = groupRepository.getGroups().firstOrNull { it.id == groupId }?.name
|
|
|
|
val savedWeekStart = runCatching {
|
|
preferencesRepository.selectedWeekStart()?.let(LocalDate::parse)
|
|
}.getOrNull()
|
|
val savedDayDate = runCatching {
|
|
preferencesRepository.selectedDayDate()?.let(LocalDate::parse)
|
|
}.getOrNull()
|
|
_uiState.value = _uiState.value.copy(
|
|
noGroup = false,
|
|
groupName = groupName,
|
|
weekStart = savedWeekStart,
|
|
dayDate = savedDayDate
|
|
)
|
|
|
|
launch {
|
|
scheduleRepository.observeSchedule(groupId).collect { schedule ->
|
|
currentGroupId?.let { applySchedule(schedule) }
|
|
}
|
|
}
|
|
|
|
launch {
|
|
syncIfMissingToday(groupId)
|
|
}
|
|
}
|
|
}
|
|
|
|
private suspend fun applySchedule(schedule: Schedule?) {
|
|
val current = _uiState.value
|
|
if (schedule == null || schedule.periods.isEmpty()) {
|
|
_uiState.value = current.copy(schedule = schedule, todayDate = null)
|
|
return
|
|
}
|
|
val today = ScheduleDates.moscowToday()
|
|
val todayDate = if (schedule.periodOf(today) != null) today else null
|
|
|
|
val weekStart = when {
|
|
schedule.periods.any { it.weekStart == current.weekStart } -> current.weekStart!!
|
|
todayDate != null -> schedule.periodOf(todayDate)!!.weekStart
|
|
else -> schedule.periods.first().weekStart
|
|
}
|
|
val period = schedule.periods.first { it.weekStart == weekStart }
|
|
val weekDays = schedule.daysOf(period)
|
|
|
|
val dayDate = when {
|
|
weekDays.any { it.date == current.dayDate } -> current.dayDate
|
|
weekDays.any { it.date == todayDate } -> todayDate
|
|
else -> weekDays.firstOrNull()?.date
|
|
}
|
|
|
|
preferencesRepository.setSelectedWeekStart(weekStart.toString())
|
|
dayDate?.let { preferencesRepository.setSelectedDayDate(it.toString()) }
|
|
|
|
_uiState.value = current.copy(
|
|
schedule = schedule,
|
|
weekStart = weekStart,
|
|
dayDate = dayDate,
|
|
todayDate = todayDate
|
|
)
|
|
}
|
|
|
|
fun selectWeek(weekStart: LocalDate) {
|
|
val state = _uiState.value
|
|
val schedule = state.schedule ?: return
|
|
val period = schedule.periods.firstOrNull { it.weekStart == weekStart } ?: return
|
|
viewModelScope.launch {
|
|
val today = ScheduleDates.moscowToday()
|
|
val weekDays = schedule.daysOf(period)
|
|
val dayDate = when {
|
|
weekDays.any { it.date == today } -> today
|
|
else -> weekDays.firstOrNull()?.date
|
|
}
|
|
preferencesRepository.setSelectedWeekStart(weekStart.toString())
|
|
dayDate?.let { preferencesRepository.setSelectedDayDate(it.toString()) }
|
|
_uiState.value = _uiState.value.copy(weekStart = weekStart, dayDate = dayDate)
|
|
}
|
|
}
|
|
|
|
fun selectDay(date: LocalDate) {
|
|
val state = _uiState.value
|
|
val schedule = state.schedule ?: return
|
|
val period = schedule.periodOf(date) ?: return
|
|
viewModelScope.launch {
|
|
preferencesRepository.setSelectedWeekStart(period.weekStart.toString())
|
|
preferencesRepository.setSelectedDayDate(date.toString())
|
|
_uiState.value = _uiState.value.copy(weekStart = period.weekStart, dayDate = date)
|
|
}
|
|
}
|
|
|
|
private suspend fun syncIfMissingToday(groupId: String) {
|
|
val schedule = scheduleRepository.getSchedule(groupId)
|
|
val today = ScheduleDates.moscowToday()
|
|
val hasTodayPeriod = schedule?.periodOf(today) != null
|
|
if (hasTodayPeriod) return
|
|
_uiState.value = _uiState.value.copy(isSyncing = true)
|
|
scheduleRepository.sync(groupId)
|
|
_uiState.value = _uiState.value.copy(isSyncing = false)
|
|
}
|
|
|
|
fun switchGroup() {
|
|
viewModelScope.launch {
|
|
currentGroupId = null
|
|
preferencesRepository.clearSelectedGroup()
|
|
_uiState.value = _uiState.value.copy(noGroup = true)
|
|
}
|
|
}
|
|
|
|
fun refresh() {
|
|
val groupId = currentGroupId ?: return
|
|
viewModelScope.launch {
|
|
_uiState.value = _uiState.value.copy(isRefreshing = true)
|
|
scheduleRepository.sync(groupId)
|
|
_uiState.value = _uiState.value.copy(isRefreshing = false)
|
|
}
|
|
}
|
|
|
|
fun clearAll() {
|
|
val groupId = currentGroupId ?: return
|
|
viewModelScope.launch {
|
|
scheduleRepository.clearAll(groupId)
|
|
}
|
|
}
|
|
|
|
fun clearSelectedPeriod() {
|
|
val state = _uiState.value
|
|
val schedule = state.schedule ?: return
|
|
val weekStart = state.weekStart ?: return
|
|
val period = schedule.periods.firstOrNull { it.weekStart == weekStart } ?: return
|
|
viewModelScope.launch {
|
|
scheduleRepository.clearPeriod(schedule.groupId, period)
|
|
}
|
|
}
|
|
}
|
|
|
|
data class ScheduleUiState(
|
|
val noGroup: Boolean = false,
|
|
val isRefreshing: Boolean = false,
|
|
val isSyncing: Boolean = false,
|
|
val schedule: Schedule? = null,
|
|
val groupName: String? = null,
|
|
val weekStart: LocalDate? = null,
|
|
val dayDate: LocalDate? = null,
|
|
val todayDate: LocalDate? = null
|
|
)
|