Изменённый дизайн.
This commit is contained in:
2025-03-20 07:52:37 +04:00
parent 96f84b9f54
commit dbc1afcf28
15 changed files with 442 additions and 254 deletions

View File

@@ -46,8 +46,8 @@ android {
applicationId = "ru.n08i40k.polytechnic.next" applicationId = "ru.n08i40k.polytechnic.next"
minSdk = 26 minSdk = 26
targetSdk = 35 targetSdk = 35
versionCode = 28 versionCode = 29
versionName = "3.1.1" versionName = "3.2.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
} }
@@ -136,6 +136,7 @@ dependencies {
implementation(libs.kotlinx.datetime) implementation(libs.kotlinx.datetime)
// default // default
implementation(libs.androidx.runtime.tracing)
implementation(libs.androidx.core.ktx) implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx) implementation(libs.androidx.lifecycle.runtime.ktx)
implementation(libs.androidx.activity.compose) implementation(libs.androidx.activity.compose)

View File

@@ -2,9 +2,8 @@ package ru.n08i40k.polytechnic.next.ui.screen.schedule
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -24,6 +23,7 @@ import ru.n08i40k.polytechnic.next.ui.model.GroupUiState
import ru.n08i40k.polytechnic.next.ui.model.GroupViewModel import ru.n08i40k.polytechnic.next.ui.model.GroupViewModel
import ru.n08i40k.polytechnic.next.ui.widgets.LoadingContent import ru.n08i40k.polytechnic.next.ui.widgets.LoadingContent
import ru.n08i40k.polytechnic.next.ui.widgets.schedule.SchedulePager import ru.n08i40k.polytechnic.next.ui.widgets.schedule.SchedulePager
import ru.n08i40k.polytechnic.next.ui.widgets.schedule.UpdateInfo
import ru.n08i40k.polytechnic.next.utils.rememberUpdatedLifecycleOwner import ru.n08i40k.polytechnic.next.utils.rememberUpdatedLifecycleOwner
@Composable @Composable
@@ -62,11 +62,10 @@ fun GroupScheduleScreen(viewModel: GroupViewModel) {
) { ) {
when (uiState) { when (uiState) {
is GroupUiState.HasData -> { is GroupUiState.HasData -> {
Column { Column(Modifier.padding(20.dp), Arrangement.spacedBy(10.dp)) {
val data = uiState as GroupUiState.HasData val data = uiState as GroupUiState.HasData
UpdateInfo(data.lastUpdateAt, data.cacheDate) UpdateInfo(data.lastUpdateAt, data.cacheDate)
Spacer(Modifier.height(10.dp))
SchedulePager(data.group) SchedulePager(data.group)
} }
} }

View File

@@ -2,9 +2,8 @@ package ru.n08i40k.polytechnic.next.ui.screen.schedule
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -24,6 +23,7 @@ import ru.n08i40k.polytechnic.next.ui.model.TeacherUiState
import ru.n08i40k.polytechnic.next.ui.model.TeacherViewModel import ru.n08i40k.polytechnic.next.ui.model.TeacherViewModel
import ru.n08i40k.polytechnic.next.ui.widgets.LoadingContent import ru.n08i40k.polytechnic.next.ui.widgets.LoadingContent
import ru.n08i40k.polytechnic.next.ui.widgets.schedule.SchedulePager import ru.n08i40k.polytechnic.next.ui.widgets.schedule.SchedulePager
import ru.n08i40k.polytechnic.next.ui.widgets.schedule.UpdateInfo
import ru.n08i40k.polytechnic.next.utils.rememberUpdatedLifecycleOwner import ru.n08i40k.polytechnic.next.utils.rememberUpdatedLifecycleOwner
@Composable @Composable
@@ -62,11 +62,10 @@ fun TeacherScheduleScreen(viewModel: TeacherViewModel) {
) { ) {
when (uiState) { when (uiState) {
is TeacherUiState.HasData -> { is TeacherUiState.HasData -> {
Column { Column(Modifier.padding(20.dp), Arrangement.spacedBy(10.dp)) {
val data = uiState as TeacherUiState.HasData val data = uiState as TeacherUiState.HasData
UpdateInfo(data.lastUpdateAt, data.cacheDate) UpdateInfo(data.lastUpdateAt, data.cacheDate)
Spacer(Modifier.height(10.dp))
SchedulePager(data.teacher) SchedulePager(data.teacher)
} }
} }

View File

@@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -28,6 +29,7 @@ import ru.n08i40k.polytechnic.next.ui.model.SearchUiState
import ru.n08i40k.polytechnic.next.ui.model.SearchViewModel import ru.n08i40k.polytechnic.next.ui.model.SearchViewModel
import ru.n08i40k.polytechnic.next.ui.widgets.LoadingContent import ru.n08i40k.polytechnic.next.ui.widgets.LoadingContent
import ru.n08i40k.polytechnic.next.ui.widgets.schedule.SchedulePager import ru.n08i40k.polytechnic.next.ui.widgets.schedule.SchedulePager
import ru.n08i40k.polytechnic.next.ui.widgets.schedule.UpdateInfo
import ru.n08i40k.polytechnic.next.ui.widgets.selector.TeacherNameSelector import ru.n08i40k.polytechnic.next.ui.widgets.selector.TeacherNameSelector
import ru.n08i40k.polytechnic.next.utils.rememberUpdatedLifecycleOwner import ru.n08i40k.polytechnic.next.utils.rememberUpdatedLifecycleOwner
@@ -82,11 +84,10 @@ fun TeacherSearchScreen(viewModel: SearchViewModel) {
when (uiState) { when (uiState) {
is SearchUiState.HasData -> { is SearchUiState.HasData -> {
Column { Column(Modifier.padding(20.dp), Arrangement.spacedBy(10.dp)) {
val data = uiState as SearchUiState.HasData val data = uiState as SearchUiState.HasData
UpdateInfo(data.lastUpdateAt, data.cacheDate) UpdateInfo(data.lastUpdateAt, data.cacheDate)
Spacer(Modifier.height(10.dp))
SchedulePager(data.teacher) SchedulePager(data.teacher)
} }
} }

View File

@@ -10,7 +10,6 @@ import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
@@ -32,17 +31,12 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate import androidx.compose.ui.draw.rotate
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@Composable @Composable
fun ExpandableCard( fun ExpandableCard(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
colors: CardColors = CardDefaults.cardColors(), colors: CardColors = CardDefaults.cardColors(),
border: BorderStroke = BorderStroke(
Dp.Hairline,
MaterialTheme.colorScheme.inverseSurface
),
expanded: Boolean = false, expanded: Boolean = false,
onExpandedChange: () -> Unit, onExpandedChange: () -> Unit,
title: @Composable () -> Unit, title: @Composable () -> Unit,
@@ -61,8 +55,7 @@ fun ExpandableCard(
onExpandedChange() onExpandedChange()
transitionState.targetState = expanded transitionState.targetState = expanded
}, },
colors = colors, colors = colors
border = border
) { ) {
Column { Column {
ExpandableCardHeader(title, transition) ExpandableCardHeader(title, transition)
@@ -76,15 +69,10 @@ fun ExpandableCard(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
title: @Composable () -> Unit, title: @Composable () -> Unit,
colors: CardColors = CardDefaults.cardColors(), colors: CardColors = CardDefaults.cardColors(),
border: BorderStroke = BorderStroke(
Dp.Hairline,
MaterialTheme.colorScheme.inverseSurface
),
) { ) {
Card( Card(
modifier = modifier, modifier = modifier,
colors = colors, colors = colors
border = border
) { ) {
ExpandableCardHeader(title, null) ExpandableCardHeader(title, null)
} }

View File

@@ -1,19 +1,23 @@
package ru.n08i40k.polytechnic.next.ui.widgets.schedule package ru.n08i40k.polytechnic.next.ui.widgets.schedule
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable 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.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeContent
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Card import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults import androidx.compose.material3.CardDefaults
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.derivedStateOf
@@ -21,9 +25,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@@ -33,8 +35,8 @@ import kotlinx.datetime.LocalDateTime
import ru.n08i40k.polytechnic.next.R import ru.n08i40k.polytechnic.next.R
import ru.n08i40k.polytechnic.next.model.Day import ru.n08i40k.polytechnic.next.model.Day
import ru.n08i40k.polytechnic.next.model.Lesson import ru.n08i40k.polytechnic.next.model.Lesson
import ru.n08i40k.polytechnic.next.model.LessonType
import ru.n08i40k.polytechnic.next.repository.schedule.impl.MockScheduleRepository import ru.n08i40k.polytechnic.next.repository.schedule.impl.MockScheduleRepository
import ru.n08i40k.polytechnic.next.ui.theme.AppTheme
import ru.n08i40k.polytechnic.next.utils.dateTime import ru.n08i40k.polytechnic.next.utils.dateTime
import ru.n08i40k.polytechnic.next.utils.now import ru.n08i40k.polytechnic.next.utils.now
@@ -75,82 +77,42 @@ private fun getCurrentLessonIdx(day: Day?): Flow<Int> {
return value return value
} }
@Preview(showBackground = true) @PreviewLightDark
@Composable
private fun DayCardPreview() {
AppTheme {
Surface(
Modifier
.fillMaxSize()
.windowInsetsPadding(WindowInsets.safeContent.only(WindowInsetsSides.Top))
) {
DayCard(Modifier, MockScheduleRepository.exampleTeacher.days[0]) {}
}
}
}
@Composable @Composable
fun DayCard( fun DayCard(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
day: Day = MockScheduleRepository.exampleTeacher.days[0], day: Day,
onLessonClick: (Lesson) -> Unit = {}, onLessonClick: (Lesson) -> Unit,
) { ) {
val offset = remember(day) { getDayOffset(day) } val offset = remember(day) { getDayOffset(day) }
val defaultCardColors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.secondaryContainer,
contentColor = MaterialTheme.colorScheme.onSecondaryContainer,
)
val customCardColors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.tertiaryContainer,
contentColor = MaterialTheme.colorScheme.onTertiaryContainer,
)
val noneCardColors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.primaryContainer,
contentColor = MaterialTheme.colorScheme.onPrimaryContainer,
)
val examCardColors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.errorContainer,
contentColor = MaterialTheme.colorScheme.onErrorContainer,
)
Card( Card(
modifier, modifier,
colors = CardDefaults.cardColors( colors = CardDefaults.cardColors(
containerColor = when (offset) { containerColor = MaterialTheme.colorScheme.surfaceContainerLowest
DayOffset.TODAY -> MaterialTheme.colorScheme.primaryContainer )
else -> MaterialTheme.colorScheme.secondaryContainer
}
),
border = BorderStroke(1.dp, MaterialTheme.colorScheme.inverseSurface)
) { ) {
Text(
day.name,
Modifier.fillMaxWidth(),
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center,
style = MaterialTheme.typography.titleLarge
)
day.street?.let {
Text(
it,
Modifier.fillMaxWidth(),
textAlign = TextAlign.Center,
)
}
if (offset != DayOffset.OTHER) {
Text(
stringResource(
when (offset) {
DayOffset.YESTERDAY -> R.string.yesterday
DayOffset.TODAY -> R.string.today
DayOffset.TOMORROW -> R.string.tomorrow
DayOffset.OTHER -> throw RuntimeException()
}
),
Modifier.fillMaxWidth(),
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center,
style = MaterialTheme.typography.bodyMedium,
)
}
val currentLessonIndex by getCurrentLessonIdx(if (offset == DayOffset.TODAY) day else null) val currentLessonIndex by getCurrentLessonIdx(if (offset == DayOffset.TODAY) day else null)
.collectAsStateWithLifecycle(0) .collectAsStateWithLifecycle(0)
Column( Column(
Modifier Modifier
.fillMaxWidth() .fillMaxWidth()
.verticalScroll(rememberScrollState()), .verticalScroll(rememberScrollState())
.padding(10.dp),
Arrangement.spacedBy(0.5.dp) Arrangement.spacedBy(0.5.dp)
) { ) {
if (day.lessons.isEmpty()) { if (day.lessons.isEmpty()) {
@@ -159,36 +121,10 @@ fun DayCard(
} }
for (lessonIndex in day.lessons.indices) { for (lessonIndex in day.lessons.indices) {
HorizontalDivider(
thickness = 1.dp,
color = MaterialTheme.colorScheme.inversePrimary
)
val lesson = day.lessons[lessonIndex] val lesson = day.lessons[lessonIndex]
val cardColors = when (lesson.type) { Box(Modifier.clickable { onLessonClick(lesson) }) {
LessonType.DEFAULT -> defaultCardColors LessonRow(modifier, lesson, lessonIndex == currentLessonIndex)
LessonType.ADDITIONAL -> noneCardColors
LessonType.BREAK -> noneCardColors
LessonType.CONSULTATION -> customCardColors
LessonType.INDEPENDENT_WORK -> customCardColors
LessonType.EXAM -> examCardColors
LessonType.EXAM_WITH_GRADE -> examCardColors
LessonType.EXAM_DEFAULT -> examCardColors
}
Box(
Modifier
.clickable { onLessonClick(lesson) }
.background(cardColors.containerColor)
) {
val modifier =
if (lessonIndex == currentLessonIndex)
Modifier.border(BorderStroke(1.dp, MaterialTheme.colorScheme.error))
else
Modifier
LessonRow(modifier, lesson, cardColors)
} }
} }
} }

View File

@@ -1,34 +1,47 @@
package ru.n08i40k.polytechnic.next.ui.widgets.schedule package ru.n08i40k.polytechnic.next.ui.widgets.schedule
import androidx.annotation.DrawableRes
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box 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.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeContent
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.text.BasicText import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.CardColors import androidx.compose.material3.Icon
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.VerticalDivider
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.rememberTextMeasurer import androidx.compose.ui.text.rememberTextMeasurer
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import ru.n08i40k.polytechnic.next.R import ru.n08i40k.polytechnic.next.R
import ru.n08i40k.polytechnic.next.model.Lesson import ru.n08i40k.polytechnic.next.model.Lesson
import ru.n08i40k.polytechnic.next.model.LessonType import ru.n08i40k.polytechnic.next.model.LessonType
import ru.n08i40k.polytechnic.next.repository.schedule.impl.MockScheduleRepository import ru.n08i40k.polytechnic.next.repository.schedule.impl.MockScheduleRepository
import ru.n08i40k.polytechnic.next.ui.theme.AppTheme
import ru.n08i40k.polytechnic.next.utils.dayMinutes import ru.n08i40k.polytechnic.next.utils.dayMinutes
import ru.n08i40k.polytechnic.next.utils.fmtAsClock import ru.n08i40k.polytechnic.next.utils.fmtAsClock
@@ -42,31 +55,51 @@ private fun fmtTime(start: Int, end: Int, format: TimeFormat): ArrayList<String>
return when (format) { return when (format) {
TimeFormat.CLOCK -> arrayListOf(start.fmtAsClock(), end.fmtAsClock()) TimeFormat.CLOCK -> arrayListOf(start.fmtAsClock(), end.fmtAsClock())
TimeFormat.DURATION -> arrayListOf( TimeFormat.DURATION -> arrayListOf(
"${end - start} ${stringResource(R.string.minutes)}" "${end - start} ${stringResource(R.string.minutes_full)}"
) )
} }
} }
@Preview(showBackground = true, showSystemUi = true) @PreviewLightDark
@Composable
private fun LessonRowPreview() {
AppTheme {
Surface(
Modifier
.fillMaxSize()
.windowInsetsPadding(WindowInsets.safeContent.only(WindowInsetsSides.Top))
) {
LessonRow(Modifier, MockScheduleRepository.exampleGroup.days[0].lessons[6], true)
}
}
}
@Composable @Composable
fun LessonRow( fun LessonRow(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
lesson: Lesson = MockScheduleRepository.exampleGroup.days[0].lessons[0], lesson: Lesson,
colors: CardColors = CardDefaults.cardColors() current: Boolean
) { ) {
val verticalPadding = when (lesson.type) { var time = fmtTime(
LessonType.BREAK -> 2.5.dp lesson.time.start.dayMinutes,
else -> 5.dp lesson.time.end.dayMinutes,
if (lesson.type == LessonType.BREAK) TimeFormat.DURATION else TimeFormat.CLOCK
)
if (lesson.type == LessonType.BREAK) {
Box(Modifier.fillMaxWidth(), Alignment.Center) {
HorizontalDivider(color = MaterialTheme.colorScheme.surfaceContainerHighest)
Text(
time[0],
Modifier
.background(MaterialTheme.colorScheme.surfaceContainerLowest)
.padding(5.dp, 0.dp),
style = MaterialTheme.typography.titleSmall,
color = MaterialTheme.colorScheme.surfaceContainerHighest,
)
} }
val timeFormat = when (lesson.type) { return
LessonType.BREAK -> TimeFormat.DURATION
else -> TimeFormat.CLOCK
}
val contentColor = when (lesson.type) {
LessonType.BREAK -> colors.disabledContentColor
else -> colors.contentColor
} }
// магические вычисления)) // магические вычисления))
@@ -78,56 +111,73 @@ fun LessonRow(
Box(modifier) { Box(modifier) {
Row( Row(
Modifier.padding(10.dp, verticalPadding * rangeSize), Modifier.padding(10.dp, 5.dp * rangeSize),
verticalAlignment = Alignment.CenterVertically, Arrangement.spacedBy(15.dp),
Alignment.CenterVertically,
) { ) {
Text(
when (range) {
null -> " "
else -> {
if (range[0] == range[1])
" ${range[0]} "
else
"${range[0]}-${range[1]}"
}
},
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Bold,
color = contentColor
)
Spacer(Modifier.width(5.dp))
val textMeasurer = rememberTextMeasurer() val textMeasurer = rememberTextMeasurer()
val timeWidth = textMeasurer.measure( val timeWidth = textMeasurer.measure(
text = "00:00 ", text = "00:00",
style = LocalTextStyle.current.copy(fontFamily = FontFamily.Monospace) style = LocalTextStyle.current.copy(fontFamily = FontFamily.Monospace)
) )
Column( Column(
Modifier.width(with(LocalDensity.current) { timeWidth.size.width.toDp() }), Modifier
horizontalAlignment = Alignment.CenterHorizontally .width(with(LocalDensity.current) { timeWidth.size.width.toDp() + 1.dp }),
Arrangement.spacedBy(5.dp),
Alignment.CenterHorizontally
) { ) {
var time = fmtTime( Column {
lesson.time.start.dayMinutes, Text(
lesson.time.end.dayMinutes, time[0],
timeFormat fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.W600,
style = MaterialTheme.typography.titleSmall
) )
Text(time[0], color = contentColor, fontFamily = FontFamily.Monospace, maxLines = 1)
if (lesson.type != LessonType.BREAK)
Text( Text(
time[1], time[1],
color = contentColor,
fontFamily = FontFamily.Monospace, fontFamily = FontFamily.Monospace,
maxLines = 1 fontWeight = FontWeight.W600,
style = MaterialTheme.typography.titleSmall
) )
} }
Spacer(Modifier.width(5.dp)) if (range != null) {
HorizontalDivider(
Modifier.width(32.dp),
1.dp,
MaterialTheme.colorScheme.inverseSurface
)
Text(
if (range[0] == range[1])
" ${range[0]} "
else
"${range[0]}-${range[1]}",
fontFamily = FontFamily.Monospace,
fontWeight = FontWeight.Bold,
style = MaterialTheme.typography.bodySmall
)
}
}
VerticalDivider(
Modifier.height(42.dp),
1.dp,
if (current)
MaterialTheme.colorScheme.primary
else
MaterialTheme.colorScheme.inverseSurface
)
Row(Modifier.fillMaxWidth(), Arrangement.SpaceBetween, Alignment.CenterVertically) {
Column(Modifier.weight(1f)) { Column(Modifier.weight(1f)) {
Text(
lesson.name!!,
fontWeight = FontWeight.W600,
style = MaterialTheme.typography.titleMedium
)
// FIXME: Очень странный метод отсеивания, может что-нибудь на замену сделать? // FIXME: Очень странный метод отсеивания, может что-нибудь на замену сделать?
if (lesson.type.value > LessonType.BREAK.value) { if (lesson.type.value > LessonType.BREAK.value) {
Text( Text(
@@ -139,59 +189,106 @@ fun LessonRow(
LessonType.EXAM_DEFAULT -> stringResource(R.string.lesson_type_exam_default) LessonType.EXAM_DEFAULT -> stringResource(R.string.lesson_type_exam_default)
else -> throw RuntimeException("Unknown lesson type!") else -> throw RuntimeException("Unknown lesson type!")
}, },
fontWeight = FontWeight.Bold,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
color = contentColor fontWeight = FontWeight.W600,
style = MaterialTheme.typography.titleMedium
) )
} }
Text( @Composable
lesson.name ?: stringResource(R.string.lesson_type_break), fun SmallTextWithIcon(
fontWeight = FontWeight.Medium, @DrawableRes iconId: Int,
maxLines = 1, contentDescription: String,
overflow = TextOverflow.Ellipsis, text: String
color = contentColor ) {
Row(
horizontalArrangement = Arrangement.spacedBy(10.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
painterResource(iconId),
contentDescription,
Modifier.size(12.dp)
) )
Text(
text,
fontWeight = FontWeight.W400,
style = MaterialTheme.typography.titleSmall
)
}
}
if (lesson.group != null) { if (lesson.group != null) {
Text( Row {
lesson.group, Spacer(Modifier.size(5.dp))
color = contentColor,
fontWeight = FontWeight.Medium,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)
}
for (subGroup in lesson.subGroups) { SmallTextWithIcon(
Text( R.drawable.ic_group,
subGroup.teacher, "Group",
color = contentColor, lesson.group
maxLines = 1,
overflow = TextOverflow.Ellipsis
) )
} }
} }
Column(Modifier.wrapContentWidth()) { Row(
if (lesson.subGroups.size != 1) { Modifier
BasicText("") .fillMaxWidth()
.padding(5.dp),
if (lesson.group != null) Arrangement.SpaceBetween,
BasicText("") Alignment.CenterVertically
) {
lesson
.subGroups
.sortedBy { it.number }
.forEachIndexed { subGroupIdx, subGroup ->
if (subGroupIdx > 0) {
VerticalDivider(
Modifier.height(25.dp), 1.dp,
MaterialTheme.colorScheme.inverseSurface
)
} }
for (subGroup in lesson.subGroups) { // FIXME: тупая проверка
if (subGroup.teacher == "Только у другой") {
Text( Text(
subGroup.cabinet, stringResource(
color = contentColor, if (subGroup.number == 1)
maxLines = 1, R.string.only_for_second
fontFamily = FontFamily.Monospace else
R.string.only_for_first
),
fontWeight = FontWeight.W400,
style = MaterialTheme.typography.titleSmall
)
return@forEachIndexed
}
Column {
val cabinet =
if (subGroup.cabinet.toIntOrNull() == null)
subGroup.cabinet
else
"${subGroup.cabinet}"
SmallTextWithIcon(
R.drawable.ic_cabinet,
"Cabinet",
cabinet
)
SmallTextWithIcon(
R.drawable.ic_teacher,
"Teacher",
subGroup.teacher
) )
} }
} }
} }
} }
}
} }
} }

View File

@@ -1,29 +1,53 @@
package ru.n08i40k.polytechnic.next.ui.widgets.schedule package ru.n08i40k.polytechnic.next.ui.widgets.schedule
import androidx.compose.animation.Animatable
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column 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.WindowInsetsSides
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.only
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeContent
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue 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.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.util.lerp import androidx.compose.ui.util.lerp
import kotlinx.coroutines.launch
import kotlinx.datetime.LocalDateTime import kotlinx.datetime.LocalDateTime
import ru.n08i40k.polytechnic.next.R import ru.n08i40k.polytechnic.next.R
import ru.n08i40k.polytechnic.next.model.GroupOrTeacher import ru.n08i40k.polytechnic.next.model.GroupOrTeacher
import ru.n08i40k.polytechnic.next.model.Lesson import ru.n08i40k.polytechnic.next.model.Lesson
import ru.n08i40k.polytechnic.next.model.LessonType import ru.n08i40k.polytechnic.next.model.LessonType
import ru.n08i40k.polytechnic.next.repository.schedule.impl.MockScheduleRepository import ru.n08i40k.polytechnic.next.repository.schedule.impl.MockScheduleRepository
import ru.n08i40k.polytechnic.next.ui.theme.AppTheme
import ru.n08i40k.polytechnic.next.ui.widgets.NotificationCard import ru.n08i40k.polytechnic.next.ui.widgets.NotificationCard
import ru.n08i40k.polytechnic.next.utils.dateTime import ru.n08i40k.polytechnic.next.utils.dateTime
import ru.n08i40k.polytechnic.next.utils.now import ru.n08i40k.polytechnic.next.utils.now
@@ -39,9 +63,31 @@ private fun isScheduleOutdated(schedule: GroupOrTeacher): Boolean {
return nowDateTime > lastLesson.time.end.dateTime return nowDateTime > lastLesson.time.end.dateTime
} }
@Preview(showSystemUi = true) @PreviewLightDark()
@Composable @Composable
fun SchedulePager(schedule: GroupOrTeacher = MockScheduleRepository.exampleTeacher) { private fun SchedulePagerPreview() {
AppTheme {
Surface(
Modifier
.fillMaxSize()
.windowInsetsPadding(WindowInsets.safeContent.only(WindowInsetsSides.Top))
) {
SchedulePager(MockScheduleRepository.exampleTeacher)
}
}
}
val weekList = listOf(
R.string.week_bar_monday,
R.string.week_bar_tuesday,
R.string.week_bar_wednesday,
R.string.week_bar_thursday,
R.string.week_bar_friday,
R.string.week_bar_saturday,
)
@Composable
fun SchedulePager(schedule: GroupOrTeacher) {
val pagerState = rememberPagerState( val pagerState = rememberPagerState(
initialPage = (schedule.currentIdx ?: (schedule.days.size - 1)).coerceAtLeast(0), initialPage = (schedule.currentIdx ?: (schedule.days.size - 1)).coerceAtLeast(0),
pageCount = { schedule.days.size } pageCount = { schedule.days.size }
@@ -49,16 +95,88 @@ fun SchedulePager(schedule: GroupOrTeacher = MockScheduleRepository.exampleTeach
var dialogLesson by remember { mutableStateOf<WeakReference<Lesson>?>(null) } var dialogLesson by remember { mutableStateOf<WeakReference<Lesson>?>(null) }
Column { Column(
Modifier
.fillMaxWidth(),
Arrangement.spacedBy(20.dp)
) {
if (isScheduleOutdated(schedule)) if (isScheduleOutdated(schedule))
NotificationCard(Level.WARNING, stringResource(R.string.outdated_schedule)) NotificationCard(Level.WARNING, stringResource(R.string.outdated_schedule))
Card(
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surfaceContainerLowest
)
) {
Row(Modifier.fillMaxWidth(), Arrangement.spacedBy(5.dp)) {
val coroutineScope = rememberCoroutineScope()
for (i in 0..5) {
val primaryContainerColor = MaterialTheme.colorScheme.primaryContainer
val onPrimaryContainerColor = MaterialTheme.colorScheme.onPrimaryContainer
val onSurfaceColor = MaterialTheme.colorScheme.onSurface
val containerColor = remember {
Animatable(
if (pagerState.currentPage == i) primaryContainerColor
else Color.Transparent
)
}
val contentColor = remember {
Animatable(
if (pagerState.currentPage == i) onPrimaryContainerColor
else onSurfaceColor
)
}
LaunchedEffect(pagerState, pagerState.currentPage) {
containerColor.animateTo(
if (pagerState.currentPage == i) primaryContainerColor
else Color.Transparent
)
contentColor.animateTo(
if (pagerState.currentPage == i) onPrimaryContainerColor
else onSurfaceColor
)
}
Column(
modifier = Modifier
.weight(1f)
.clip(RoundedCornerShape(20))
.background(containerColor.value)
.clickable { coroutineScope.launch { pagerState.animateScrollToPage(i) } },
horizontalAlignment = Alignment.CenterHorizontally
) {
Column(
Modifier
.padding(12.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
stringResource(weekList[i]),
style = MaterialTheme.typography.bodyMedium,
color = contentColor.value
)
Text(
schedule.days[i].date.dateTime.date.dayOfMonth.toString(),
style = MaterialTheme.typography.bodyLarge,
fontWeight = FontWeight.W600,
color = contentColor.value
)
}
}
}
}
}
HorizontalPager( HorizontalPager(
pagerState, pagerState,
Modifier Modifier
.height(600.dp) .height(600.dp),
.padding(top = 5.dp),
PaddingValues(horizontal = 7.dp),
verticalAlignment = Alignment.Top verticalAlignment = Alignment.Top
) { page -> ) { page ->
DayCard( DayCard(
@@ -68,7 +186,7 @@ fun SchedulePager(schedule: GroupOrTeacher = MockScheduleRepository.exampleTeach
).absoluteValue ).absoluteValue
lerp( lerp(
start = 1f, stop = 0.95f, fraction = 1f - offset.coerceIn(0f, 1f) start = 1f, stop = 0.95f, fraction = offset.coerceIn(0f, 1f)
).also { scale -> ).also { scale ->
scaleX = scale scaleX = scale
scaleY = scale scaleY = scale

View File

@@ -1,4 +1,4 @@
package ru.n08i40k.polytechnic.next.ui.screen.schedule package ru.n08i40k.polytechnic.next.ui.widgets.schedule
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@@ -6,6 +6,8 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
@@ -21,20 +23,19 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import ru.n08i40k.polytechnic.next.CacheDate import ru.n08i40k.polytechnic.next.CacheDate
import ru.n08i40k.polytechnic.next.R import ru.n08i40k.polytechnic.next.R
import ru.n08i40k.polytechnic.next.ui.screen.schedule.PaskhalkoDialog
import ru.n08i40k.polytechnic.next.ui.widgets.ExpandableCard import ru.n08i40k.polytechnic.next.ui.widgets.ExpandableCard
import ru.n08i40k.polytechnic.next.ui.widgets.ExpandableCardTitle import ru.n08i40k.polytechnic.next.ui.widgets.ExpandableCardTitle
import ru.n08i40k.polytechnic.next.utils.* import ru.n08i40k.polytechnic.next.utils.*
import java.util.Date import java.util.Date
val expanded = mutableStateOf(false)
@Preview(showBackground = true) @Preview(showBackground = true)
@Composable @Composable
fun UpdateInfo( fun UpdateInfo(
lastUpdateAt: Long = 0, lastUpdateAt: Long = 0,
cacheDate: CacheDate = CacheDate.newBuilder().build() cacheDate: CacheDate = CacheDate.newBuilder().build()
) { ) {
var expanded by remember { expanded } var expanded by remember { mutableStateOf(false) }
val format = "HH:mm:ss dd.MM.yyyy" val format = "HH:mm:ss dd.MM.yyyy"
@@ -44,6 +45,7 @@ fun UpdateInfo(
ExpandableCard( ExpandableCard(
expanded = expanded, expanded = expanded,
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceContainerLowest),
onExpandedChange = { expanded = !expanded }, onExpandedChange = { expanded = !expanded },
title = { ExpandableCardTitle(stringResource(R.string.update_info_header)) } title = { ExpandableCardTitle(stringResource(R.string.update_info_header)) }
) { ) {

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:pathData="M120,840v-80h80v-640h400v40h160v600h80v80L680,840v-600h-80v600L120,840ZM280,200v560,-560ZM440,520q17,0 28.5,-11.5T480,480q0,-17 -11.5,-28.5T440,440q-17,0 -28.5,11.5T400,480q0,17 11.5,28.5T440,520ZM280,760h240v-560L280,200v560Z"
android:fillColor="#e8eaed"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:pathData="M96,768v-92q0,-25.78 12.5,-47.39T143,594q54,-32 114.5,-49T384,528q66,0 126.5,17T625,594q22,13 34.5,34.61T672,676v92L96,768ZM744,768v-92q0,-42 -19.5,-78T672,539q39,8 75.5,21.5T817,594q22,13 34.5,34.67Q864,650.35 864,676v92L744,768ZM384,480q-60,0 -102,-42t-42,-102q0,-60 42,-102t102,-42q60,0 102,42t42,102q0,60 -42,102t-102,42ZM720,336q0,60 -42,102t-102,42q-8,0 -15,-0.5t-15,-2.5q25,-29 39.5,-64.5T600,336q0,-41 -14.5,-76.5T546,195q8,-2 15,-2.5t15,-0.5q60,0 102,42t42,102ZM168,696h432v-20q0,-6.47 -3.03,-11.76 -3.02,-5.3 -7.97,-8.24 -47,-27 -99,-41.5T384,600q-54,0 -106,14t-99,42q-4.95,2.83 -7.98,7.91 -3.02,5.09 -3.02,12L168,696ZM384.21,408Q414,408 435,386.79t21,-51Q456,306 434.79,285t-51,-21Q354,264 333,285.21t-21,51Q312,366 333.21,387t51,21ZM384,696ZM384,336Z"
android:fillColor="#e8eaed"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:pathData="M480,840 L200,688v-240L40,360l440,-240 440,240v320h-80v-276l-80,44v240L480,840ZM480,508 L754,360 480,212 206,360 480,508ZM480,749 L680,641v-151L480,600 280,490v151l200,108ZM480,508ZM480,598ZM480,598Z"
android:fillColor="#e8eaed"/>
</vector>

View File

@@ -67,7 +67,7 @@
<string name="auth_error_disallowed_role">Пожалуйста, используйте другую роль.</string> <string name="auth_error_disallowed_role">Пожалуйста, используйте другую роль.</string>
<string name="sign_in_manual">По имени пользователя</string> <string name="sign_in_manual">По имени пользователя</string>
<string name="updater_support_end">Поддержка версий ниже %1$s прекращена!</string> <string name="updater_support_end">Поддержка версий ниже %1$s прекращена!</string>
<string name="last_server_schedule_update">Последнее обновление расписания</string> <string name="last_server_schedule_update">Расписание</string>
<string name="teacher_name">ФИО преподавателя</string> <string name="teacher_name">ФИО преподавателя</string>
<string name="updater_body">Желаете ли вы обновиться до последней версии?</string> <string name="updater_body">Желаете ли вы обновиться до последней версии?</string>
<string name="updater_new_version">Вышла новая версия приложения!</string> <string name="updater_new_version">Вышла новая версия приложения!</string>
@@ -76,8 +76,8 @@
<string name="updater_update">ОБНОВИТЬ</string> <string name="updater_update">ОБНОВИТЬ</string>
<string name="updater_suppress">ЗАГЛУШИТЬ</string> <string name="updater_suppress">ЗАГЛУШИТЬ</string>
<string name="update_info_header">Дополнительная информация</string> <string name="update_info_header">Дополнительная информация</string>
<string name="last_local_update">Последнее локальное обновление</string> <string name="last_local_update">Локально</string>
<string name="last_server_cache_update">Последнее обновление кеша</string> <string name="last_server_cache_update">Кеш</string>
<string name="download_update">Скачать обновление</string> <string name="download_update">Скачать обновление</string>
<string name="telegram_channel">Телеграм канал</string> <string name="telegram_channel">Телеграм канал</string>
<string name="schedule_update_title">Расписание обновлено!</string> <string name="schedule_update_title">Расписание обновлено!</string>
@@ -107,4 +107,13 @@
<string name="extra_info_duration">"Длительность: "</string> <string name="extra_info_duration">"Длительность: "</string>
<string name="extra_info_duration_second">С %1$s до %2$s (%3$d ч. %4$d мин.)</string> <string name="extra_info_duration_second">С %1$s до %2$s (%3$d ч. %4$d мин.)</string>
<string name="extra_info_type">"Тип: "</string> <string name="extra_info_type">"Тип: "</string>
<string name="minutes_full">минут</string>
<string name="only_for_second">Только у второй</string>
<string name="only_for_first">Только у первой</string>
<string name="week_bar_monday">Пн</string>
<string name="week_bar_tuesday">Вт</string>
<string name="week_bar_wednesday">Ср</string>
<string name="week_bar_thursday">Чт</string>
<string name="week_bar_friday">Пт</string>
<string name="week_bar_saturday">Сб</string>
</resources> </resources>

View File

@@ -107,4 +107,13 @@
<string name="extra_info_duration">"Duration: "</string> <string name="extra_info_duration">"Duration: "</string>
<string name="extra_info_duration_second">From %1$s to %2$s (%3$d h. %4$d min.)</string> <string name="extra_info_duration_second">From %1$s to %2$s (%3$d h. %4$d min.)</string>
<string name="extra_info_type">"Type: "</string> <string name="extra_info_type">"Type: "</string>
<string name="minutes_full">minutes</string>
<string name="only_for_second">Only for second</string>
<string name="only_for_first">Only for first</string>
<string name="week_bar_tuesday">Tue</string>
<string name="week_bar_wednesday">Wed</string>
<string name="week_bar_thursday">Thu</string>
<string name="week_bar_friday">Fri</string>
<string name="week_bar_saturday">Sat</string>
<string name="week_bar_monday">Mon</string>
</resources> </resources>

View File

@@ -16,6 +16,7 @@ hiltAndroidCompiler = "2.55"
hiltNavigationCompose = "1.2.0" hiltNavigationCompose = "1.2.0"
kotlinxSerializationJson = "1.8.0" kotlinxSerializationJson = "1.8.0"
protobufLite = "3.0.1" protobufLite = "3.0.1"
runtimeTracing = "1.7.8"
volley = "1.2.1" volley = "1.2.1"
datastore = "1.1.3" datastore = "1.1.3"
navigationCompose = "2.8.9" navigationCompose = "2.8.9"
@@ -26,6 +27,7 @@ vkid = "2.2.2"
[libraries] [libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
androidx-runtime-tracing = { module = "androidx.compose.runtime:runtime-tracing", version.ref = "runtimeTracing" }
desugar_jdk_libs = { module = "com.android.tools:desugar_jdk_libs", version.ref = "desugar_jdk_libs" } desugar_jdk_libs = { module = "com.android.tools:desugar_jdk_libs", version.ref = "desugar_jdk_libs" }
junit = { group = "junit", name = "junit", version.ref = "junit" } junit = { group = "junit", name = "junit", version.ref = "junit" }
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" } androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }