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 8d178a9..ec69449 100644 --- a/app/src/main/java/agzam/vyatsu/ui/schedule/ScheduleScreen.kt +++ b/app/src/main/java/agzam/vyatsu/ui/schedule/ScheduleScreen.kt @@ -4,24 +4,31 @@ import agzam.vyatsu.domain.model.Day import agzam.vyatsu.domain.model.LessonType import agzam.vyatsu.domain.model.SchedulePeriod import agzam.vyatsu.domain.model.TimeSlot +import android.widget.Toast +import androidx.compose.foundation.background import androidx.compose.foundation.clickable +import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.WindowInsets 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.statusBars import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.layout.windowInsetsPadding 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.foundation.text.selection.SelectionContainer import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowDropDown import androidx.compose.material.icons.filled.Refresh @@ -47,14 +54,19 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.unit.dp import java.time.DayOfWeek import java.time.LocalDate import java.time.format.DateTimeFormatter + +val hPadding = 16.dp + @OptIn(ExperimentalMaterial3Api::class) @Composable fun ScheduleScreen(viewModel: ScheduleViewModel, onSwitchGroup: () -> Unit) { + val state by viewModel.uiState.collectAsState() Column(Modifier.fillMaxSize()) { @@ -70,7 +82,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 = 0.dp, vertical = 0.dp)) { when { state.isSyncing && state.schedule == null -> { Row( @@ -111,7 +123,7 @@ fun ScheduleScreen(viewModel: ScheduleViewModel, onSwitchGroup: () -> Unit) { val dayLabel = if (isTodayDay) "Сегодня " else "" Row( - Modifier.fillMaxWidth(), + Modifier.fillMaxWidth().padding(horizontal = hPadding), verticalAlignment = Alignment.CenterVertically ) { Text( @@ -126,7 +138,7 @@ fun ScheduleScreen(viewModel: ScheduleViewModel, onSwitchGroup: () -> Unit) { onSelect = viewModel::selectWeek ) } - HorizontalDivider(Modifier.padding(top = 8.dp, bottom = 0.dp)) + HorizontalDivider(Modifier.padding(top = 8.dp, bottom = 0.dp, start = hPadding, end = hPadding)) DayChips( days = weekDays, @@ -135,14 +147,15 @@ fun ScheduleScreen(viewModel: ScheduleViewModel, onSwitchGroup: () -> Unit) { onSelect = viewModel::selectDay ) - HorizontalDivider(Modifier.padding(top=0.dp, bottom = 8.dp)) + HorizontalDivider(Modifier.padding(top=0.dp, start = hPadding, end = hPadding)) if (day.intervals.all { it.lessons.isEmpty() }) { Text("Занятий нет", style = MaterialTheme.typography.bodyLarge) } else { LazyColumn( modifier = Modifier.weight(1f), - verticalArrangement = Arrangement.spacedBy(8.dp) + verticalArrangement = Arrangement.spacedBy(8.dp), + contentPadding = PaddingValues(vertical = 8.dp) ) { itemsIndexed(day.intervals) { slotIndex, slot -> LessonSlot(slotIndex = slotIndex, slot = slot) @@ -228,7 +241,7 @@ private fun DayChips( todayDate: LocalDate?, onSelect: (LocalDate) -> Unit ) { - LazyRow(horizontalArrangement = Arrangement.spacedBy(6.dp)) { + LazyRow(horizontalArrangement = Arrangement.spacedBy(6.dp), contentPadding = PaddingValues(horizontal = hPadding, vertical = 2.dp),) { items(days, key = { it.date.toEpochDay() }) { day -> val selected = selectedDate == day.date val isTodayChip = todayDate == day.date @@ -276,10 +289,12 @@ private fun weekLabel(period: SchedulePeriod): String { @Composable private fun LessonSlot(slotIndex: Int, slot: TimeSlot) { + val context = LocalContext.current + var indexColor = 0 Column(Modifier.fillMaxWidth()) { Row(modifier = Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { HorizontalDivider( - modifier = Modifier.width(10.dp), + modifier = Modifier.width(10.dp + hPadding).padding(start = hPadding), color = MaterialTheme.colorScheme.primary ) Text( @@ -288,48 +303,82 @@ private fun LessonSlot(slotIndex: Int, slot: TimeSlot) { color = MaterialTheme.colorScheme.primary, modifier = Modifier.padding(horizontal = 4.dp) ) - HorizontalDivider(color = MaterialTheme.colorScheme.primary, modifier = Modifier.weight(1f)) + HorizontalDivider(color = MaterialTheme.colorScheme.primary, modifier = Modifier.weight(1f).padding(end = hPadding)) } if (slot.lessons.isEmpty()) { Text("—", style = MaterialTheme.typography.bodyMedium) } else { - slot.lessons.forEach { lesson -> - Column(Modifier.fillMaxWidth().padding(vertical = 2.dp)) { - var any = false + slot.lessons.forEachIndexed { index, lesson -> + val backgroundColor = if (indexColor % 2 == 0) { + MaterialTheme.colorScheme.surfaceBright + } else { + MaterialTheme.colorScheme.surfaceVariant + } + indexColor++ + // XXX: + // Убрать SelectionContainer? + // Режим редактирования расписания? + // Меню на onClick? + // Меню на onLongClick? + SelectionContainer() { + Column( + Modifier.fillMaxWidth().padding(vertical = 2.dp).background(backgroundColor) + // XXX: combinedClickable? + //.combinedClickable( + // onClick = { + // Toast.makeText( + // context, + // lesson.raw, + // Toast.LENGTH_SHORT + // ).show() + // }, + // onLongClick = {}, + // // TODO: onLongClickLabel = "(Accessibility)" + //), + ) { + var any = false - val meta = listOfNotNull( - if(lesson.type == LessonType.OTHER) { null } else { lesson.type.label}, - lesson.subgroup, - lesson.teacher, - lesson.room - ).filter { it.isNotBlank() }.joinToString(" · ") + val meta = listOfNotNull( + if (lesson.type == LessonType.OTHER) { + null + } else { + lesson.type.label + }, + lesson.subgroup, + lesson.teacher, + lesson.room + ).filter { it.isNotBlank() }.joinToString(" · ") + + if (meta.isNotEmpty()) { + Text( + meta, + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(horizontal = hPadding) + ) + any = true + } + + val subject = lesson.subject?.takeIf { it.isNotBlank() } ?: lesson.raw + if (subject.isNotEmpty()) { + Text( + subject, + style = MaterialTheme.typography.bodyLarge, + modifier = Modifier.padding(horizontal = hPadding) + ) + any = true + } + + if (!any) { + Text( + "пусто", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(horizontal = hPadding) + ) + } - if(meta.isNotEmpty()) { - Text( - meta, - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onSurfaceVariant - ) - any = true } - - val subject = lesson.subject?.takeIf { it.isNotBlank() } ?: lesson.raw - if(subject.isNotEmpty()) { - Text( - subject, - style = MaterialTheme.typography.bodyLarge - ) - any = true - } - - if(!any) { - Text( - "-", - style = MaterialTheme.typography.bodySmall, - color = MaterialTheme.colorScheme.onSurfaceVariant - ) - } - } } }