Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96161d6844 | ||
|
|
1fc43bb8fc | ||
|
|
32f93197ab | ||
|
|
32d0cec8ce | ||
|
|
72e63addb2 |
@@ -15,4 +15,16 @@ interface PreferencesDao {
|
||||
|
||||
@Query("DELETE FROM preferences WHERE key = 'selectedGroupId'")
|
||||
suspend fun clearSelectedGroup()
|
||||
|
||||
@Query("SELECT value FROM preferences WHERE key = 'selectedWeekStart'")
|
||||
suspend fun selectedWeekStart(): String?
|
||||
|
||||
@Query("INSERT OR REPLACE INTO preferences(key, value) VALUES('selectedWeekStart', :weekStart)")
|
||||
suspend fun setSelectedWeekStart(weekStart: String)
|
||||
|
||||
@Query("SELECT value FROM preferences WHERE key = 'selectedDayDate'")
|
||||
suspend fun selectedDayDate(): String?
|
||||
|
||||
@Query("INSERT OR REPLACE INTO preferences(key, value) VALUES('selectedDayDate', :date)")
|
||||
suspend fun setSelectedDayDate(date: String)
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ interface ScheduleDao {
|
||||
suspend fun trim(groupId: String, keep: Int)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertDays(days: List<DayEntity>)
|
||||
suspend fun insertDays(days: List<DayEntity>): List<Long>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertLessons(lessons: List<LessonEntity>)
|
||||
|
||||
@@ -9,4 +9,8 @@ class PreferencesRepositoryImpl(
|
||||
override suspend fun selectedGroupId(): String? = dao.selectedGroupId()
|
||||
override suspend fun setSelectedGroup(groupId: String) = dao.setSelectedGroup(groupId)
|
||||
override suspend fun clearSelectedGroup() = dao.clearSelectedGroup()
|
||||
override suspend fun selectedWeekStart(): String? = dao.selectedWeekStart()
|
||||
override suspend fun setSelectedWeekStart(weekStart: String) = dao.setSelectedWeekStart(weekStart)
|
||||
override suspend fun selectedDayDate(): String? = dao.selectedDayDate()
|
||||
override suspend fun setSelectedDayDate(date: String) = dao.setSelectedDayDate(date)
|
||||
}
|
||||
|
||||
@@ -112,11 +112,8 @@ class ScheduleRepositoryImpl(
|
||||
private suspend fun replaceDays(scheduleId: Long, days: List<Day>) {
|
||||
scheduleDao.deleteDaysForSchedule(scheduleId)
|
||||
val dayEntities = days.map { DayEntity(scheduleId = scheduleId, date = it.date.toEpochDay()) }
|
||||
val dayIdByDate = mutableMapOf<LocalDate, Long>()
|
||||
scheduleDao.insertDays(dayEntities)
|
||||
for (day in dayEntities) {
|
||||
dayIdByDate[LocalDate.ofEpochDay(day.date)] = day.id
|
||||
}
|
||||
val dayIds = scheduleDao.insertDays(dayEntities)
|
||||
val dayIdByDate = dayEntities.zip(dayIds).associate { (day, id) -> LocalDate.ofEpochDay(day.date) to id }
|
||||
val lessons = days.flatMap { day ->
|
||||
day.intervals.flatMapIndexed { slotIndex, slot ->
|
||||
slot.lessons.mapIndexed { lessonIndex, lesson ->
|
||||
|
||||
@@ -15,4 +15,7 @@ data class Schedule(
|
||||
) {
|
||||
fun periodOf(date: LocalDate): SchedulePeriod? =
|
||||
periods.firstOrNull { !date.isBefore(it.weekStart) && !date.isAfter(it.weekEnd) }
|
||||
|
||||
fun daysOf(period: SchedulePeriod): List<Day> =
|
||||
days.filter { !it.date.isBefore(period.weekStart) && !it.date.isAfter(period.weekEnd) }
|
||||
}
|
||||
|
||||
@@ -4,4 +4,8 @@ interface PreferencesRepository {
|
||||
suspend fun selectedGroupId(): String?
|
||||
suspend fun setSelectedGroup(groupId: String)
|
||||
suspend fun clearSelectedGroup()
|
||||
suspend fun selectedWeekStart(): String?
|
||||
suspend fun setSelectedWeekStart(weekStart: String)
|
||||
suspend fun selectedDayDate(): String?
|
||||
suspend fun setSelectedDayDate(date: String)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package agzam.vyatsu.ui.schedule
|
||||
|
||||
import agzam.vyatsu.domain.model.Day
|
||||
import agzam.vyatsu.domain.model.SchedulePeriod
|
||||
import agzam.vyatsu.domain.model.TimeSlot
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -13,6 +14,7 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.systemBars
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
@@ -35,6 +37,7 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import java.time.DayOfWeek
|
||||
import java.time.LocalDate
|
||||
import java.time.format.DateTimeFormatter
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@@ -55,7 +58,7 @@ fun ScheduleScreen(viewModel: ScheduleViewModel, onSwitchGroup: () -> Unit) {
|
||||
},
|
||||
windowInsets = WindowInsets(0.dp)
|
||||
)
|
||||
Column(Modifier.fillMaxSize().padding(horizontal = 16.dp, vertical = 0.dp)) {
|
||||
Column(Modifier.fillMaxSize().padding(horizontal = 16.dp, vertical = 0.dp)) {
|
||||
when {
|
||||
state.isSyncing && state.schedule == null -> {
|
||||
Row(
|
||||
@@ -83,12 +86,17 @@ fun ScheduleScreen(viewModel: ScheduleViewModel, onSwitchGroup: () -> Unit) {
|
||||
|
||||
else -> {
|
||||
val schedule = state.schedule!!
|
||||
val day = schedule.days.getOrNull(state.selectedIndex)
|
||||
val weekDays = state.weekStart
|
||||
?.let { ws -> schedule.periods.firstOrNull { it.weekStart == ws } }
|
||||
?.let { schedule.daysOf(it) }
|
||||
.orEmpty()
|
||||
val day = schedule.days.firstOrNull { it.date == state.dayDate }
|
||||
|
||||
if (day == null) {
|
||||
Text("Занятий нет", style = MaterialTheme.typography.bodyLarge)
|
||||
} else {
|
||||
val isToday = state.selectedIndex == state.todayIndex
|
||||
val dayLabel = if (isToday) "Сегодня " else ""
|
||||
val isTodayDay = day.date == state.todayDate
|
||||
val dayLabel = if (isTodayDay) "Сегодня " else ""
|
||||
|
||||
Text(
|
||||
"$dayLabel ${dayName(day.date.dayOfWeek)} · ${day.date.format(FULL_DATE)}",
|
||||
@@ -99,7 +107,7 @@ fun ScheduleScreen(viewModel: ScheduleViewModel, onSwitchGroup: () -> Unit) {
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||
) {
|
||||
TextButton(onClick = { viewModel.clearSelectedPeriod() }) {
|
||||
Text("Очистить неделю")
|
||||
Text("Очистить эту неделю")
|
||||
}
|
||||
TextButton(onClick = { viewModel.clearAll() }) {
|
||||
Text("Очистить всё")
|
||||
@@ -107,10 +115,19 @@ fun ScheduleScreen(viewModel: ScheduleViewModel, onSwitchGroup: () -> Unit) {
|
||||
}
|
||||
HorizontalDivider(Modifier.padding(vertical = 8.dp))
|
||||
|
||||
WeekChips(
|
||||
periods = schedule.periods,
|
||||
selectedWeekStart = state.weekStart,
|
||||
todayWeekStart = state.todayDate?.let { schedule.periodOf(it)?.weekStart },
|
||||
onSelect = viewModel::selectWeek
|
||||
)
|
||||
|
||||
HorizontalDivider(Modifier.padding(vertical = 8.dp))
|
||||
|
||||
DayChips(
|
||||
days = schedule.days,
|
||||
selectedIndex = state.selectedIndex,
|
||||
todayIndex = state.todayIndex,
|
||||
days = weekDays,
|
||||
selectedDate = state.dayDate,
|
||||
todayDate = state.todayDate,
|
||||
onSelect = viewModel::selectDay
|
||||
)
|
||||
|
||||
@@ -136,19 +153,56 @@ fun ScheduleScreen(viewModel: ScheduleViewModel, onSwitchGroup: () -> Unit) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DayChips(
|
||||
days: List<Day>,
|
||||
selectedIndex: Int,
|
||||
todayIndex: Int,
|
||||
onSelect: (Int) -> Unit
|
||||
private fun WeekChips(
|
||||
periods: List<SchedulePeriod>,
|
||||
selectedWeekStart: LocalDate?,
|
||||
todayWeekStart: LocalDate?,
|
||||
onSelect: (LocalDate) -> Unit
|
||||
) {
|
||||
LazyRow(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||
itemsIndexed(days) { index, day ->
|
||||
val selected = selectedIndex == index
|
||||
val isTodayChip = todayIndex == index
|
||||
items(periods, key = { it.weekStart.toEpochDay() }) { period ->
|
||||
val selected = selectedWeekStart == period.weekStart
|
||||
val isTodayWeek = todayWeekStart == period.weekStart
|
||||
FilterChip(
|
||||
selected = selected,
|
||||
onClick = { onSelect(index) },
|
||||
onClick = { onSelect(period.weekStart) },
|
||||
label = {
|
||||
Text(
|
||||
weekLabel(period),
|
||||
style = MaterialTheme.typography.labelLarge
|
||||
)
|
||||
},
|
||||
modifier = Modifier.padding(vertical = 2.dp),
|
||||
border = if (isTodayWeek && !selected) {
|
||||
FilterChipDefaults.filterChipBorder(
|
||||
borderColor = MaterialTheme.colorScheme.primary,
|
||||
borderWidth = 1.dp,
|
||||
enabled = true,
|
||||
selected = false
|
||||
)
|
||||
} else {
|
||||
FilterChipDefaults.filterChipBorder(enabled = true, selected = selected)
|
||||
},
|
||||
shape = RoundedCornerShape(8.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DayChips(
|
||||
days: List<Day>,
|
||||
selectedDate: LocalDate?,
|
||||
todayDate: LocalDate?,
|
||||
onSelect: (LocalDate) -> Unit
|
||||
) {
|
||||
LazyRow(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
|
||||
items(days, key = { it.date.toEpochDay() }) { day ->
|
||||
val selected = selectedDate == day.date
|
||||
val isTodayChip = todayDate == day.date
|
||||
FilterChip(
|
||||
selected = selected,
|
||||
onClick = { onSelect(day.date) },
|
||||
label = {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Text(
|
||||
@@ -183,6 +237,11 @@ private fun DayChips(
|
||||
}
|
||||
}
|
||||
|
||||
private fun weekLabel(period: SchedulePeriod): String {
|
||||
val first = period.weekStart
|
||||
return "с ${first.format(CHIP_DATE)}"
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun LessonSlot(slotIndex: Int, slot: TimeSlot) {
|
||||
Column(Modifier.fillMaxWidth()) {
|
||||
@@ -201,8 +260,12 @@ private fun LessonSlot(slotIndex: Int, slot: TimeSlot) {
|
||||
style = MaterialTheme.typography.bodyLarge
|
||||
)
|
||||
Text(
|
||||
listOf(lesson.type.label, lesson.subgroup, lesson.teacher, lesson.room)
|
||||
.filterNotNull()
|
||||
listOfNotNull(
|
||||
lesson.type.label,
|
||||
lesson.subgroup,
|
||||
lesson.teacher,
|
||||
lesson.room
|
||||
)
|
||||
.filter { it.isNotBlank() }
|
||||
.joinToString(" · "),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
|
||||
Reference in New Issue
Block a user