Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5fee57d93a | ||
|
|
36711d1bf3 | ||
|
|
c2a9cfb7e7 | ||
|
|
467c1a735f | ||
|
|
28965e6aed | ||
|
|
181f8b2f2a | ||
|
|
84ae97b906 | ||
|
|
2069ec811a |
@@ -112,9 +112,3 @@ jobs:
|
|||||||
files: ${{ steps.apk.outputs.apk_path }}
|
files: ${{ steps.apk.outputs.apk_path }}
|
||||||
token: ${{ secrets.GITEA_TOKEN }}
|
token: ${{ secrets.GITEA_TOKEN }}
|
||||||
server_url: ${{ gitea.server_url }}
|
server_url: ${{ gitea.server_url }}
|
||||||
|
|
||||||
- name: Upload APK as artifact
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: vyatsu-schedule-${{ steps.version.outputs.version_name }}
|
|
||||||
path: ${{ steps.apk.outputs.apk_path }}
|
|
||||||
|
|||||||
@@ -157,6 +157,7 @@ class ScheduleRepositoryImpl(
|
|||||||
val lessonsByDay = lessonEntities.groupBy { it.dayId }
|
val lessonsByDay = lessonEntities.groupBy { it.dayId }
|
||||||
val days = dayEntities
|
val days = dayEntities
|
||||||
.sortedBy { it.date }
|
.sortedBy { it.date }
|
||||||
|
.distinctBy { it.date }
|
||||||
.map { day ->
|
.map { day ->
|
||||||
val lessons = lessonsByDay[day.id].orEmpty()
|
val lessons = lessonsByDay[day.id].orEmpty()
|
||||||
.groupBy { it.slotIndex }
|
.groupBy { it.slotIndex }
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ package agzam.vyatsu.ui.schedule
|
|||||||
import agzam.vyatsu.domain.model.Day
|
import agzam.vyatsu.domain.model.Day
|
||||||
import agzam.vyatsu.domain.model.SchedulePeriod
|
import agzam.vyatsu.domain.model.SchedulePeriod
|
||||||
import agzam.vyatsu.domain.model.TimeSlot
|
import agzam.vyatsu.domain.model.TimeSlot
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
@@ -12,14 +14,18 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||||||
import androidx.compose.foundation.layout.only
|
import androidx.compose.foundation.layout.only
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.systemBars
|
import androidx.compose.foundation.layout.systemBars
|
||||||
|
import androidx.compose.foundation.layout.widthIn
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.LazyRow
|
import androidx.compose.foundation.lazy.LazyRow
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowDropDown
|
||||||
import androidx.compose.material.icons.filled.Refresh
|
import androidx.compose.material.icons.filled.Refresh
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
import androidx.compose.material3.DropdownMenu
|
||||||
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.FilterChip
|
import androidx.compose.material3.FilterChip
|
||||||
import androidx.compose.material3.FilterChipDefaults
|
import androidx.compose.material3.FilterChipDefaults
|
||||||
@@ -33,8 +39,12 @@ import androidx.compose.material3.TopAppBar
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import java.time.DayOfWeek
|
import java.time.DayOfWeek
|
||||||
import java.time.LocalDate
|
import java.time.LocalDate
|
||||||
@@ -98,10 +108,22 @@ fun ScheduleScreen(viewModel: ScheduleViewModel, onSwitchGroup: () -> Unit) {
|
|||||||
val isTodayDay = day.date == state.todayDate
|
val isTodayDay = day.date == state.todayDate
|
||||||
val dayLabel = if (isTodayDay) "Сегодня " else ""
|
val dayLabel = if (isTodayDay) "Сегодня " else ""
|
||||||
|
|
||||||
Text(
|
Row(
|
||||||
"$dayLabel ${dayName(day.date.dayOfWeek)} · ${day.date.format(FULL_DATE)}",
|
Modifier.fillMaxWidth(),
|
||||||
style = MaterialTheme.typography.titleMedium
|
verticalAlignment = Alignment.CenterVertically
|
||||||
)
|
) {
|
||||||
|
Text(
|
||||||
|
"$dayLabel${dayName(day.date.dayOfWeek)} · ${day.date.format(FULL_DATE)}",
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
)
|
||||||
|
WeekSelector(
|
||||||
|
periods = schedule.periods,
|
||||||
|
selectedWeekStart = state.weekStart,
|
||||||
|
todayWeekStart = state.todayDate?.let { schedule.periodOf(it)?.weekStart },
|
||||||
|
onSelect = viewModel::selectWeek
|
||||||
|
)
|
||||||
|
}
|
||||||
Row(
|
Row(
|
||||||
Modifier.fillMaxWidth(),
|
Modifier.fillMaxWidth(),
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
horizontalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
@@ -115,15 +137,6 @@ fun ScheduleScreen(viewModel: ScheduleViewModel, onSwitchGroup: () -> Unit) {
|
|||||||
}
|
}
|
||||||
HorizontalDivider(Modifier.padding(vertical = 8.dp))
|
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(
|
DayChips(
|
||||||
days = weekDays,
|
days = weekDays,
|
||||||
selectedDate = state.dayDate,
|
selectedDate = state.dayDate,
|
||||||
@@ -152,39 +165,67 @@ fun ScheduleScreen(viewModel: ScheduleViewModel, onSwitchGroup: () -> Unit) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun WeekChips(
|
private fun WeekSelector(
|
||||||
periods: List<SchedulePeriod>,
|
periods: List<SchedulePeriod>,
|
||||||
selectedWeekStart: LocalDate?,
|
selectedWeekStart: LocalDate?,
|
||||||
todayWeekStart: LocalDate?,
|
todayWeekStart: LocalDate?,
|
||||||
onSelect: (LocalDate) -> Unit
|
onSelect: (LocalDate) -> Unit
|
||||||
) {
|
) {
|
||||||
LazyRow(horizontalArrangement = Arrangement.spacedBy(6.dp)) {
|
val selected = periods.firstOrNull { it.weekStart == selectedWeekStart }
|
||||||
items(periods, key = { it.weekStart.toEpochDay() }) { period ->
|
var expanded by remember { mutableStateOf(false) }
|
||||||
val selected = selectedWeekStart == period.weekStart
|
|
||||||
val isTodayWeek = todayWeekStart == period.weekStart
|
Box {
|
||||||
FilterChip(
|
Row(
|
||||||
selected = selected,
|
modifier = Modifier
|
||||||
onClick = { onSelect(period.weekStart) },
|
.clip(MaterialTheme.shapes.small)
|
||||||
label = {
|
.clickable(enabled = true, onClick = { expanded = true })
|
||||||
Text(
|
.padding(horizontal = 10.dp, vertical = 8.dp),
|
||||||
weekLabel(period),
|
verticalAlignment = Alignment.CenterVertically
|
||||||
style = MaterialTheme.typography.labelLarge
|
) {
|
||||||
)
|
Text(
|
||||||
},
|
selected?.let(::weekLabel) ?: "Период",
|
||||||
modifier = Modifier.padding(vertical = 2.dp),
|
style = MaterialTheme.typography.labelLarge,
|
||||||
border = if (isTodayWeek && !selected) {
|
color = MaterialTheme.colorScheme.primary
|
||||||
FilterChipDefaults.filterChipBorder(
|
|
||||||
borderColor = MaterialTheme.colorScheme.primary,
|
|
||||||
borderWidth = 1.dp,
|
|
||||||
enabled = true,
|
|
||||||
selected = false
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
FilterChipDefaults.filterChipBorder(enabled = true, selected = selected)
|
|
||||||
},
|
|
||||||
shape = RoundedCornerShape(8.dp)
|
|
||||||
)
|
)
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.ArrowDropDown,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = MaterialTheme.colorScheme.primary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
DropdownMenu(
|
||||||
|
expanded = expanded,
|
||||||
|
onDismissRequest = { expanded = false },
|
||||||
|
modifier = Modifier.widthIn(min = 220.dp)
|
||||||
|
) {
|
||||||
|
periods.forEach { period ->
|
||||||
|
val isTodayWeek = todayWeekStart == period.weekStart
|
||||||
|
DropdownMenuItem(
|
||||||
|
text = {
|
||||||
|
Text(
|
||||||
|
weekLabel(period),
|
||||||
|
style = MaterialTheme.typography.bodyLarge
|
||||||
|
)
|
||||||
|
},
|
||||||
|
trailingIcon = if (isTodayWeek) {
|
||||||
|
{
|
||||||
|
Text(
|
||||||
|
"сегодня",
|
||||||
|
style = MaterialTheme.typography.labelMedium,
|
||||||
|
color = MaterialTheme.colorScheme.primary
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
},
|
||||||
|
onClick = {
|
||||||
|
expanded = false
|
||||||
|
onSelect(period.weekStart)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user