diff --git a/app/src/main/java/agzam/vyatsu/AppRoot.kt b/app/src/main/java/agzam/vyatsu/AppRoot.kt index c8b40c0..5b16756 100644 --- a/app/src/main/java/agzam/vyatsu/AppRoot.kt +++ b/app/src/main/java/agzam/vyatsu/AppRoot.kt @@ -23,7 +23,6 @@ fun AppRoot() { val container = app.container val scheduleViewModel: ScheduleViewModel = viewModel(factory = scheduleFactory(container)) - val groupPickerViewModel: GroupPickerViewModel = viewModel(factory = groupPickerFactory(container)) val updateViewModel: UpdateViewModel = viewModel(factory = updateFactory(container)) val state by scheduleViewModel.uiState.collectAsState() @@ -53,6 +52,7 @@ fun AppRoot() { } if (state.noGroup) { + val groupPickerViewModel: GroupPickerViewModel = viewModel(factory = groupPickerFactory(container)) GroupPickerScreen( viewModel = groupPickerViewModel, onGroupPicked = { group -> scheduleViewModel.selectGroup(group.id) } diff --git a/app/src/main/java/agzam/vyatsu/data/remote/GroupsParser.kt b/app/src/main/java/agzam/vyatsu/data/remote/GroupsParser.kt index 3a0578d..01a2be3 100644 --- a/app/src/main/java/agzam/vyatsu/data/remote/GroupsParser.kt +++ b/app/src/main/java/agzam/vyatsu/data/remote/GroupsParser.kt @@ -42,7 +42,6 @@ object GroupsParser { return tables.flatMap { table -> table.select("> tbody > tr, > tr").flatMap { row -> - Log.v("ROW", row.html()); val faculty = shortname(row.selectFirst("div.fak_name")?.text().orEmpty()) // row.select("div.grpPeriod").map { grp -> diff --git a/app/src/main/java/agzam/vyatsu/ui/schedule/ScheduleScreen.kt b/app/src/main/java/agzam/vyatsu/ui/schedule/ScheduleScreen.kt index f699c71..b76c0fa 100644 --- a/app/src/main/java/agzam/vyatsu/ui/schedule/ScheduleScreen.kt +++ b/app/src/main/java/agzam/vyatsu/ui/schedule/ScheduleScreen.kt @@ -18,6 +18,7 @@ import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.statusBars import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.width @@ -75,6 +76,12 @@ fun ScheduleScreen(viewModel: ScheduleViewModel, onSwitchGroup: () -> Unit) { TopAppBar( title = { Text(state.groupName ?: "Расписание", style = MaterialTheme.typography.titleMedium) }, actions = { + if (state.isLoading && state.schedule != null) { + CircularProgressIndicator( + modifier = Modifier.size(24.dp), + strokeWidth = 2.dp + ) + } TextButton(onClick = { onSwitchGroup() }) { Text("Сменить группу") } @@ -86,16 +93,7 @@ fun ScheduleScreen(viewModel: ScheduleViewModel, onSwitchGroup: () -> Unit) { ) Column(Modifier.fillMaxSize().padding(horizontal = 0.dp, vertical = 0.dp)) { when { - state.isSyncing && state.schedule == null -> { - Row( - Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.Center - ) { - CircularProgressIndicator() - } - } - - state.schedule == null -> { + state.schedule == null && state.loadError -> { Column( Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally @@ -110,6 +108,15 @@ fun ScheduleScreen(viewModel: ScheduleViewModel, onSwitchGroup: () -> Unit) { } } + state.schedule == null -> { + Row( + Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.Center + ) { + CircularProgressIndicator() + } + } + else -> { val schedule = state.schedule!! val weekDays = state.weekStart diff --git a/app/src/main/java/agzam/vyatsu/ui/schedule/ScheduleViewModel.kt b/app/src/main/java/agzam/vyatsu/ui/schedule/ScheduleViewModel.kt index 09420ed..404f64a 100644 --- a/app/src/main/java/agzam/vyatsu/ui/schedule/ScheduleViewModel.kt +++ b/app/src/main/java/agzam/vyatsu/ui/schedule/ScheduleViewModel.kt @@ -37,6 +37,7 @@ class ScheduleViewModel( fun selectGroup(groupId: String) { currentGroupId = groupId + _uiState.value = _uiState.value.copy(noGroup = false, isLoading = true, loadError = false) viewModelScope.launch { preferencesRepository.setSelectedGroup(groupId) val groupName = groupRepository.getGroups().firstOrNull { it.id == groupId }?.name @@ -61,7 +62,7 @@ class ScheduleViewModel( } launch { - syncIfMissingToday(groupId) + syncIfMissing(groupId) } } } @@ -96,7 +97,9 @@ class ScheduleViewModel( schedule = schedule, weekStart = weekStart, dayDate = dayDate, - todayDate = todayDate + todayDate = todayDate, + isLoading = false, + loadError = false ) } @@ -128,30 +131,36 @@ class ScheduleViewModel( } } - 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) + private suspend fun syncIfMissing(groupId: String) { + if (scheduleRepository.getSchedule(groupId) != null) { + _uiState.value = _uiState.value.copy(isLoading = false) + return + } + loadSchedule(groupId) + } + + private suspend fun loadSchedule(groupId: String) { + _uiState.value = _uiState.value.copy(isLoading = true, loadError = false) + val schedule = scheduleRepository.sync(groupId) + _uiState.value = if (schedule != null) { + _uiState.value.copy(isLoading = false, loadError = false) + } else { + _uiState.value.copy(isLoading = false, loadError = true) + } } fun switchGroup() { viewModelScope.launch { currentGroupId = null preferencesRepository.clearSelectedGroup() - _uiState.value = _uiState.value.copy(noGroup = true) + _uiState.value = _uiState.value.copy(noGroup = true, isLoading = false, loadError = false) } } 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) + loadSchedule(groupId) } } @@ -175,8 +184,8 @@ class ScheduleViewModel( data class ScheduleUiState( val noGroup: Boolean = false, - val isRefreshing: Boolean = false, - val isSyncing: Boolean = false, + val isLoading: Boolean = false, + val loadError: Boolean = false, val schedule: Schedule? = null, val groupName: String? = null, val weekStart: LocalDate? = null,