mirror of
https://github.com/n08i40k/polytechnic-android.git
synced 2025-12-06 09:47:48 +03:00
2.0.0
Переход на API v2 Переработано отображение расписания. - Один предмет теперь может занимать несколько пар. - В заголовке дня теперь может писаться "Сегодня", "Завтра", "Вчера". Обновление расписания теперь происходит без отгрузки целой страницы политехникума на сервер. Приложение теперь само находит ссылку с помощью регулярных выражений, что влечёт за собой малый прирост к скорости отправки запроса и его обработки сервером. Пасхалко.
This commit is contained in:
19
.idea/appInsightsSettings.xml
generated
19
.idea/appInsightsSettings.xml
generated
@@ -15,27 +15,8 @@
|
|||||||
<option name="projectNumber" value="946974192625" />
|
<option name="projectNumber" value="946974192625" />
|
||||||
</ConnectionSetting>
|
</ConnectionSetting>
|
||||||
</option>
|
</option>
|
||||||
<option name="devices">
|
|
||||||
<list>
|
|
||||||
<DeviceSetting>
|
|
||||||
<option name="deviceType" value="Phone" />
|
|
||||||
<option name="displayName" value="Xiaomi (2311DRK48G)" />
|
|
||||||
<option name="manufacturer" value="Xiaomi" />
|
|
||||||
<option name="model" value="2311DRK48G" />
|
|
||||||
</DeviceSetting>
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
<option name="signal" value="SIGNAL_UNSPECIFIED" />
|
<option name="signal" value="SIGNAL_UNSPECIFIED" />
|
||||||
<option name="timeIntervalDays" value="THIRTY_DAYS" />
|
<option name="timeIntervalDays" value="THIRTY_DAYS" />
|
||||||
<option name="versions">
|
|
||||||
<list>
|
|
||||||
<VersionSetting>
|
|
||||||
<option name="buildVersion" value="13" />
|
|
||||||
<option name="displayName" value="1.7.1 (13)" />
|
|
||||||
<option name="displayVersion" value="1.7.1" />
|
|
||||||
</VersionSetting>
|
|
||||||
</list>
|
|
||||||
</option>
|
|
||||||
<option name="visibilityType" value="ALL" />
|
<option name="visibilityType" value="ALL" />
|
||||||
</InsightsFilterSettings>
|
</InsightsFilterSettings>
|
||||||
</value>
|
</value>
|
||||||
|
|||||||
@@ -33,13 +33,14 @@ android {
|
|||||||
applicationId = "ru.n08i40k.polytechnic.next"
|
applicationId = "ru.n08i40k.polytechnic.next"
|
||||||
minSdk = 26
|
minSdk = 26
|
||||||
targetSdk = 35
|
targetSdk = 35
|
||||||
versionCode = 15
|
versionCode = 16
|
||||||
versionName = "1.8.0"
|
versionName = "2.0.0"
|
||||||
|
|
||||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
vectorDrawables {
|
vectorDrawables {
|
||||||
useSupportLibrary = true
|
useSupportLibrary = true
|
||||||
}
|
}
|
||||||
|
versionNameSuffix = "prod"
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
@@ -112,7 +113,10 @@ dependencies {
|
|||||||
|
|
||||||
implementation(libs.accompanist.swiperefresh)
|
implementation(libs.accompanist.swiperefresh)
|
||||||
|
|
||||||
|
// json
|
||||||
implementation(libs.kotlinx.serialization.json)
|
implementation(libs.kotlinx.serialization.json)
|
||||||
|
implementation(libs.kotlinx.datetime)
|
||||||
|
|
||||||
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)
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import javax.inject.Inject
|
|||||||
|
|
||||||
@HiltAndroidApp
|
@HiltAndroidApp
|
||||||
class PolytechnicApplication : Application() {
|
class PolytechnicApplication : Application() {
|
||||||
@Suppress("unused")
|
|
||||||
@Inject
|
@Inject
|
||||||
lateinit var container: AppContainer
|
lateinit var container: AppContainer
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import kotlinx.datetime.Instant
|
||||||
|
import kotlinx.datetime.LocalDateTime
|
||||||
|
import kotlinx.datetime.TimeZone
|
||||||
|
import kotlinx.datetime.toInstant
|
||||||
import ru.n08i40k.polytechnic.next.data.MyResult
|
import ru.n08i40k.polytechnic.next.data.MyResult
|
||||||
import ru.n08i40k.polytechnic.next.data.schedule.ScheduleRepository
|
import ru.n08i40k.polytechnic.next.data.schedule.ScheduleRepository
|
||||||
import ru.n08i40k.polytechnic.next.model.Day
|
import ru.n08i40k.polytechnic.next.model.Day
|
||||||
@@ -11,6 +15,25 @@ import ru.n08i40k.polytechnic.next.model.Group
|
|||||||
import ru.n08i40k.polytechnic.next.model.Lesson
|
import ru.n08i40k.polytechnic.next.model.Lesson
|
||||||
import ru.n08i40k.polytechnic.next.model.LessonTime
|
import ru.n08i40k.polytechnic.next.model.LessonTime
|
||||||
import ru.n08i40k.polytechnic.next.model.LessonType
|
import ru.n08i40k.polytechnic.next.model.LessonType
|
||||||
|
import ru.n08i40k.polytechnic.next.model.SubGroup
|
||||||
|
import ru.n08i40k.polytechnic.next.utils.now
|
||||||
|
|
||||||
|
private fun genLocalDateTime(hour: Int, minute: Int): Instant {
|
||||||
|
return LocalDateTime(2024, 1, 1, hour, minute, 0, 0).toInstant(TimeZone.currentSystemDefault())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun genBreak(start: Instant, end: Instant): Lesson {
|
||||||
|
return Lesson(
|
||||||
|
type = LessonType.BREAK,
|
||||||
|
defaultRange = null,
|
||||||
|
name = null,
|
||||||
|
time = LessonTime(
|
||||||
|
start,
|
||||||
|
end
|
||||||
|
),
|
||||||
|
subGroups = listOf()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
class FakeScheduleRepository : ScheduleRepository {
|
class FakeScheduleRepository : ScheduleRepository {
|
||||||
@Suppress("SpellCheckingInspection")
|
@Suppress("SpellCheckingInspection")
|
||||||
@@ -19,132 +42,102 @@ class FakeScheduleRepository : ScheduleRepository {
|
|||||||
name = "ИС-214/23", days = arrayListOf(
|
name = "ИС-214/23", days = arrayListOf(
|
||||||
Day(
|
Day(
|
||||||
name = "Понедельник",
|
name = "Понедельник",
|
||||||
nonNullIndices = arrayListOf(0, 1, 2, 3, 4, 5),
|
date = LocalDateTime.now().toInstant(TimeZone.currentSystemDefault()),
|
||||||
defaultIndices = arrayListOf(2, 3, 4, 5),
|
lessons = listOf(
|
||||||
customIndices = arrayListOf(0, 1),
|
|
||||||
lessons = arrayListOf(
|
|
||||||
Lesson(
|
Lesson(
|
||||||
type = LessonType.CUSTOM,
|
type = LessonType.ADDITIONAL,
|
||||||
defaultIndex = -1,
|
defaultRange = null,
|
||||||
name = "Линейка",
|
name = "Линейка",
|
||||||
time = LessonTime(510, 520),
|
time = LessonTime(
|
||||||
cabinets = arrayListOf(),
|
genLocalDateTime(8, 30),
|
||||||
teacherNames = arrayListOf(),
|
genLocalDateTime(8, 40),
|
||||||
|
),
|
||||||
|
subGroups = listOf()
|
||||||
|
),
|
||||||
|
genBreak(
|
||||||
|
genLocalDateTime(8, 40),
|
||||||
|
genLocalDateTime(8, 45),
|
||||||
),
|
),
|
||||||
Lesson(
|
Lesson(
|
||||||
type = LessonType.CUSTOM,
|
type = LessonType.ADDITIONAL,
|
||||||
defaultIndex = -1,
|
defaultRange = null,
|
||||||
name = "Разговор о важном",
|
name = "Разговор о важном",
|
||||||
time = LessonTime(525, 555),
|
time = LessonTime(
|
||||||
cabinets = arrayListOf(),
|
genLocalDateTime(8, 45),
|
||||||
teacherNames = arrayListOf(),
|
genLocalDateTime(9, 15),
|
||||||
|
),
|
||||||
|
subGroups = listOf()
|
||||||
|
),
|
||||||
|
genBreak(
|
||||||
|
genLocalDateTime(9, 15),
|
||||||
|
genLocalDateTime(9, 25),
|
||||||
),
|
),
|
||||||
Lesson(
|
Lesson(
|
||||||
type = LessonType.DEFAULT,
|
type = LessonType.DEFAULT,
|
||||||
defaultIndex = 1,
|
defaultRange = listOf(1, 1),
|
||||||
name = "Элементы высшей математики",
|
|
||||||
time = LessonTime(565, 645),
|
|
||||||
cabinets = arrayListOf("31", "12"),
|
|
||||||
teacherNames = arrayListOf("Цацаева Т.Н."),
|
|
||||||
),
|
|
||||||
Lesson(
|
|
||||||
type = LessonType.DEFAULT,
|
|
||||||
defaultIndex = 2,
|
|
||||||
name = "Операционные системы и среды",
|
|
||||||
time = LessonTime(655, 735),
|
|
||||||
cabinets = arrayListOf("42", "52"),
|
|
||||||
teacherNames = arrayListOf("Сергачева А.О.", "Не Сергачева А.О."),
|
|
||||||
),
|
|
||||||
Lesson(
|
|
||||||
type = LessonType.DEFAULT,
|
|
||||||
defaultIndex = 3,
|
|
||||||
name = "Физическая культура",
|
|
||||||
time = LessonTime(755, 835),
|
|
||||||
cabinets = arrayListOf("c/3"),
|
|
||||||
teacherNames = arrayListOf("Васюнин В.Г.", "Не Васюнин В.Г."),
|
|
||||||
),
|
|
||||||
Lesson(
|
|
||||||
type = LessonType.DEFAULT,
|
|
||||||
defaultIndex = 4,
|
|
||||||
name = "МДК.05.01 Проектирование и дизайн информационных систем",
|
name = "МДК.05.01 Проектирование и дизайн информационных систем",
|
||||||
time = LessonTime(845, 925),
|
time = LessonTime(
|
||||||
cabinets = arrayListOf("43"),
|
genLocalDateTime(9, 25),
|
||||||
teacherNames = arrayListOf("Ивашова А.Н."),
|
genLocalDateTime(10, 45),
|
||||||
),
|
),
|
||||||
null,
|
subGroups = listOf(
|
||||||
null,
|
SubGroup(
|
||||||
|
teacher = "Ивашова А.Н.",
|
||||||
|
number = 1,
|
||||||
|
cabinet = "43"
|
||||||
)
|
)
|
||||||
), Day(
|
)
|
||||||
name = "Вторник",
|
),
|
||||||
nonNullIndices = arrayListOf(0, 1, 2),
|
genBreak(
|
||||||
defaultIndices = arrayListOf(0, 1, 2),
|
genLocalDateTime(10, 45),
|
||||||
customIndices = arrayListOf(),
|
genLocalDateTime(10, 55),
|
||||||
lessons = arrayListOf(
|
|
||||||
Lesson(
|
|
||||||
type = LessonType.DEFAULT,
|
|
||||||
defaultIndex = 1,
|
|
||||||
name = "Стандартизация, сертификация и техническое документоведение",
|
|
||||||
time = LessonTime(525, 605),
|
|
||||||
cabinets = arrayListOf("42"),
|
|
||||||
teacherNames = arrayListOf("Сергачева А.О."),
|
|
||||||
),
|
),
|
||||||
Lesson(
|
Lesson(
|
||||||
type = LessonType.DEFAULT,
|
type = LessonType.DEFAULT,
|
||||||
defaultIndex = 2,
|
defaultRange = listOf(2, 2),
|
||||||
name = "Элементы высшей математики",
|
|
||||||
time = LessonTime(620, 700),
|
|
||||||
cabinets = arrayListOf("31"),
|
|
||||||
teacherNames = arrayListOf("Цацаева Т.Н."),
|
|
||||||
),
|
|
||||||
Lesson(
|
|
||||||
type = LessonType.DEFAULT,
|
|
||||||
defaultIndex = 3,
|
|
||||||
name = "Основы проектирования баз данных",
|
name = "Основы проектирования баз данных",
|
||||||
time = LessonTime(720, 800),
|
time = LessonTime(
|
||||||
cabinets = arrayListOf("21"),
|
genLocalDateTime(10, 55),
|
||||||
teacherNames = arrayListOf("Чинарева Е.А."),
|
genLocalDateTime(12, 15),
|
||||||
|
),
|
||||||
|
subGroups = listOf(
|
||||||
|
SubGroup(
|
||||||
|
teacher = "Чинарева Е.А.",
|
||||||
|
number = 1,
|
||||||
|
cabinet = "21"
|
||||||
|
),
|
||||||
|
SubGroup(
|
||||||
|
teacher = "Ивашова А.Н.",
|
||||||
|
number = 2,
|
||||||
|
cabinet = "44"
|
||||||
),
|
),
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
)
|
)
|
||||||
), Day(
|
),
|
||||||
name = "Среда",
|
genBreak(
|
||||||
nonNullIndices = arrayListOf(0, 1, 2),
|
genLocalDateTime(12, 15),
|
||||||
defaultIndices = arrayListOf(0, 1, 2),
|
genLocalDateTime(12, 35),
|
||||||
customIndices = arrayListOf(),
|
),
|
||||||
lessons = arrayListOf(
|
|
||||||
Lesson(
|
Lesson(
|
||||||
type = LessonType.DEFAULT,
|
type = LessonType.DEFAULT,
|
||||||
defaultIndex = 1,
|
defaultRange = listOf(3, 3),
|
||||||
name = "Операционные системы и среды",
|
name = "Операционные системы и среды",
|
||||||
time = LessonTime(525, 605),
|
time = LessonTime(
|
||||||
cabinets = arrayListOf("42"),
|
genLocalDateTime(12, 35),
|
||||||
teacherNames = arrayListOf("Сергачева А.О."),
|
genLocalDateTime(13, 55),
|
||||||
),
|
),
|
||||||
Lesson(
|
subGroups = listOf(
|
||||||
type = LessonType.DEFAULT,
|
SubGroup(
|
||||||
defaultIndex = 2,
|
teacher = "Сергачева А.О.",
|
||||||
name = "Элементы высшей математики",
|
number = 1,
|
||||||
time = LessonTime(620, 700),
|
cabinet = "42"
|
||||||
cabinets = arrayListOf("31"),
|
|
||||||
teacherNames = arrayListOf("Цацаева Т.Н."),
|
|
||||||
),
|
),
|
||||||
Lesson(
|
SubGroup(
|
||||||
type = LessonType.DEFAULT,
|
teacher = "Воронцева Н.В.",
|
||||||
defaultIndex = 3,
|
number = 2,
|
||||||
name = "МДК.05.01 Проектирование и дизайн информационных систем",
|
cabinet = "41"
|
||||||
time = LessonTime(720, 800),
|
),
|
||||||
cabinets = arrayListOf("43"),
|
)
|
||||||
teacherNames = arrayListOf("Ивашова А.Н."),
|
|
||||||
),
|
),
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
null,
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -13,7 +13,13 @@ class FakeProfileRepository : ProfileRepository {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val exampleProfile =
|
val exampleProfile =
|
||||||
Profile("66db32d24030a07e02d974c5", "n08i40k", "ИС-214/23", UserRole.STUDENT)
|
Profile(
|
||||||
|
"66db32d24030a07e02d974c5",
|
||||||
|
"128735612876",
|
||||||
|
"n08i40k",
|
||||||
|
"ИС-214/23",
|
||||||
|
UserRole.STUDENT
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getProfile(): MyResult<Profile> {
|
override suspend fun getProfile(): MyResult<Profile> {
|
||||||
|
|||||||
@@ -1,30 +1,33 @@
|
|||||||
package ru.n08i40k.polytechnic.next.model
|
package ru.n08i40k.polytechnic.next.model
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import kotlinx.datetime.Instant
|
||||||
|
import kotlinx.datetime.LocalDateTime
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
import kotlinx.parcelize.RawValue
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import ru.n08i40k.polytechnic.next.utils.getDayMinutes
|
import ru.n08i40k.polytechnic.next.utils.dateTime
|
||||||
import java.util.Calendar
|
import ru.n08i40k.polytechnic.next.utils.dayMinutes
|
||||||
|
import ru.n08i40k.polytechnic.next.utils.now
|
||||||
|
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
@Suppress("unused", "MemberVisibilityCanBePrivate")
|
@Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||||
@Serializable
|
@Serializable
|
||||||
class Day(
|
class Day(
|
||||||
val name: String,
|
val name: String,
|
||||||
val nonNullIndices: ArrayList<Int>,
|
val date: @RawValue Instant,
|
||||||
val defaultIndices: ArrayList<Int>,
|
val lessons: List<Lesson>
|
||||||
val customIndices: ArrayList<Int>,
|
|
||||||
val lessons: ArrayList<Lesson?>
|
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
fun distanceToNextByMinutes(from: Int): Pair<Int, Int>? {
|
fun distanceToNextByLocalDateTime(from: LocalDateTime): Pair<Int, Int>? {
|
||||||
val toIdx = lessons
|
val toIdx = lessons
|
||||||
.map { if (it?.time == null) null else it.time.start }
|
.map { it.time.start }
|
||||||
.indexOfFirst { if (it == null) false else it > from }
|
.indexOfFirst { it.dateTime > from }
|
||||||
|
|
||||||
if (toIdx == -1)
|
if (toIdx == -1)
|
||||||
return null
|
return null
|
||||||
|
|
||||||
return Pair(toIdx, lessons[toIdx]!!.time.start - from)
|
return Pair(toIdx, lessons[toIdx].time.start.dayMinutes - from.dayMinutes)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun distanceToNextByIdx(from: Int? = null): Pair<Int, Int>? {
|
fun distanceToNextByIdx(from: Int? = null): Pair<Int, Int>? {
|
||||||
@@ -35,24 +38,22 @@ class Day(
|
|||||||
|
|
||||||
val fromTime =
|
val fromTime =
|
||||||
if (from != null)
|
if (from != null)
|
||||||
fromLesson!!.time.end
|
fromLesson!!.time.end.dateTime
|
||||||
else
|
else
|
||||||
Calendar.getInstance()
|
LocalDateTime.now()
|
||||||
.get(Calendar.HOUR_OF_DAY) * 60 + Calendar.getInstance()
|
|
||||||
.get(Calendar.MINUTE)
|
|
||||||
|
|
||||||
return distanceToNextByMinutes(fromTime)
|
return distanceToNextByLocalDateTime(fromTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
// current
|
// current
|
||||||
val currentIdx: Int?
|
val currentIdx: Int?
|
||||||
get() {
|
get() {
|
||||||
val minutes = Calendar.getInstance().getDayMinutes()
|
val now = LocalDateTime.now()
|
||||||
|
|
||||||
for (lessonIdx in nonNullIndices) {
|
for (lessonIdx in lessons.indices) {
|
||||||
val lesson = lessons[lessonIdx]!!
|
val lesson = lessons[lessonIdx]
|
||||||
|
|
||||||
if (lesson.time.start <= minutes && minutes < lesson.time.end)
|
if (lesson.time.start.dateTime <= now && now < lesson.time.end.dateTime)
|
||||||
return lessonIdx
|
return lessonIdx
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,36 +68,36 @@ class Day(
|
|||||||
val currentKV: Pair<Int, Lesson>?
|
val currentKV: Pair<Int, Lesson>?
|
||||||
get() {
|
get() {
|
||||||
val idx = currentIdx ?: return null
|
val idx = currentIdx ?: return null
|
||||||
return Pair(idx, lessons[idx]!!)
|
return Pair(idx, lessons[idx])
|
||||||
}
|
}
|
||||||
|
|
||||||
// first
|
// first
|
||||||
val firstIdx: Int?
|
val firstIdx: Int?
|
||||||
get() = nonNullIndices.getOrNull(0)
|
get() = if (lessons.isEmpty()) null else 0
|
||||||
|
|
||||||
val first: Lesson?
|
val first: Lesson?
|
||||||
get() {
|
get() {
|
||||||
return lessons[firstIdx ?: return null]!!
|
return lessons[firstIdx ?: return null]
|
||||||
}
|
}
|
||||||
|
|
||||||
val firstKV: Pair<Int, Lesson>?
|
val firstKV: Pair<Int, Lesson>?
|
||||||
get() {
|
get() {
|
||||||
val idx = firstIdx ?: return null
|
val idx = firstIdx ?: return null
|
||||||
return Pair(idx, lessons[idx]!!)
|
return Pair(idx, lessons[idx])
|
||||||
}
|
}
|
||||||
|
|
||||||
// last
|
// last
|
||||||
val lastIdx: Int?
|
val lastIdx: Int?
|
||||||
get() = nonNullIndices.getOrNull(nonNullIndices.size - 1)
|
get() = if (lessons.isEmpty()) null else lessons.size - 1
|
||||||
|
|
||||||
val last: Lesson?
|
val last: Lesson?
|
||||||
get() {
|
get() {
|
||||||
return lessons[lastIdx ?: return null]!!
|
return lessons[lastIdx ?: return null]
|
||||||
}
|
}
|
||||||
|
|
||||||
val lastKV: Pair<Int, Lesson>?
|
val lastKV: Pair<Int, Lesson>?
|
||||||
get() {
|
get() {
|
||||||
val idx = lastIdx ?: return null
|
val idx = lastIdx ?: return null
|
||||||
return Pair(idx, lessons[idx]!!)
|
return Pair(idx, lessons[idx])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@ import java.util.Calendar
|
|||||||
@Serializable
|
@Serializable
|
||||||
data class Group(
|
data class Group(
|
||||||
val name: String,
|
val name: String,
|
||||||
val days: ArrayList<Day?>
|
val days: List<Day>
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
val currentIdx: Int?
|
val currentIdx: Int?
|
||||||
get() {
|
get() {
|
||||||
@@ -27,7 +27,7 @@ data class Group(
|
|||||||
return days.getOrNull(currentIdx ?: return null)
|
return days.getOrNull(currentIdx ?: return null)
|
||||||
}
|
}
|
||||||
|
|
||||||
val currentKV: Pair<Int, Day?>?
|
val currentKV: Pair<Int, Day>?
|
||||||
get() {
|
get() {
|
||||||
val idx = currentIdx ?: return null
|
val idx = currentIdx ?: return null
|
||||||
return Pair(idx, days[idx])
|
return Pair(idx, days[idx])
|
||||||
|
|||||||
@@ -5,26 +5,30 @@ import android.os.Parcelable
|
|||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import ru.n08i40k.polytechnic.next.R
|
import ru.n08i40k.polytechnic.next.R
|
||||||
|
import ru.n08i40k.polytechnic.next.utils.dayMinutes
|
||||||
import ru.n08i40k.polytechnic.next.utils.limit
|
import ru.n08i40k.polytechnic.next.utils.limit
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Lesson(
|
data class Lesson(
|
||||||
val type: LessonType,
|
val type: LessonType,
|
||||||
val defaultIndex: Int,
|
val defaultRange: List<Int>?,
|
||||||
val name: String,
|
val name: String?,
|
||||||
val time: LessonTime,
|
val time: LessonTime,
|
||||||
val cabinets: ArrayList<String>,
|
val subGroups: List<SubGroup>
|
||||||
val teacherNames: ArrayList<String>
|
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
val duration: Int
|
val duration: Int
|
||||||
get() {
|
get() {
|
||||||
return time.end - time.start
|
val startMinutes = time.start.dayMinutes
|
||||||
|
val endMinutes = time.end.dayMinutes
|
||||||
|
|
||||||
|
return endMinutes - startMinutes
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getNameAndCabinetsShort(context: Context): String {
|
fun getNameAndCabinetsShort(context: Context): String {
|
||||||
val limitedName = name limit 15
|
val limitedName = name!! limit 15
|
||||||
|
|
||||||
|
val cabinets = subGroups.map { it.cabinet }
|
||||||
|
|
||||||
if (cabinets.isEmpty())
|
if (cabinets.isEmpty())
|
||||||
return limitedName
|
return limitedName
|
||||||
|
|||||||
@@ -1,9 +1,24 @@
|
|||||||
package ru.n08i40k.polytechnic.next.model
|
package ru.n08i40k.polytechnic.next.model
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import kotlinx.datetime.Instant
|
||||||
|
import kotlinx.datetime.LocalDateTime
|
||||||
|
import kotlinx.datetime.TimeZone
|
||||||
|
import kotlinx.datetime.toInstant
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
import kotlinx.parcelize.RawValue
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
@Serializable
|
@Serializable
|
||||||
data class LessonTime(val start: Int, val end: Int) : Parcelable
|
data class LessonTime(
|
||||||
|
val start: @RawValue Instant,
|
||||||
|
val end: @RawValue Instant
|
||||||
|
) : Parcelable {
|
||||||
|
companion object {
|
||||||
|
fun fromLocalDateTime(start: LocalDateTime, end: LocalDateTime): LessonTime {
|
||||||
|
val timeZone = TimeZone.currentSystemDefault()
|
||||||
|
return LessonTime(start.toInstant(timeZone), end.toInstant(timeZone))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -11,5 +11,7 @@ private class LessonTypeIntSerializer : EnumAsIntSerializer<LessonType>(
|
|||||||
|
|
||||||
@Serializable(with = LessonTypeIntSerializer::class)
|
@Serializable(with = LessonTypeIntSerializer::class)
|
||||||
enum class LessonType(val value: Int) {
|
enum class LessonType(val value: Int) {
|
||||||
DEFAULT(0), CUSTOM(1)
|
DEFAULT(0),
|
||||||
|
ADDITIONAL(1),
|
||||||
|
BREAK(2)
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,7 @@ import kotlinx.serialization.Serializable
|
|||||||
@Serializable
|
@Serializable
|
||||||
data class Profile(
|
data class Profile(
|
||||||
val id: String,
|
val id: String,
|
||||||
|
val accessToken: String,
|
||||||
val username: String,
|
val username: String,
|
||||||
val group: String,
|
val group: String,
|
||||||
val role: UserRole
|
val role: UserRole
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package ru.n08i40k.polytechnic.next.model
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
@Serializable
|
||||||
|
data class SubGroup(
|
||||||
|
val number: Int,
|
||||||
|
val cabinet: String,
|
||||||
|
val teacher: String
|
||||||
|
) : Parcelable
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
package ru.n08i40k.polytechnic.next.network
|
package ru.n08i40k.polytechnic.next.network
|
||||||
|
|
||||||
object NetworkValues {
|
object NetworkValues {
|
||||||
const val API_HOST = "https://polytechnic.n08i40k.ru:5050/api/v1/"
|
const val API_HOST = "https://192.168.0.103:5050/api/"
|
||||||
}
|
}
|
||||||
@@ -16,8 +16,7 @@ import ru.n08i40k.polytechnic.next.network.request.schedule.ScheduleUpdate
|
|||||||
import ru.n08i40k.polytechnic.next.network.tryFuture
|
import ru.n08i40k.polytechnic.next.network.tryFuture
|
||||||
import ru.n08i40k.polytechnic.next.network.tryGet
|
import ru.n08i40k.polytechnic.next.network.tryGet
|
||||||
import java.util.logging.Logger
|
import java.util.logging.Logger
|
||||||
import kotlin.io.encoding.Base64
|
import java.util.regex.Pattern
|
||||||
import kotlin.io.encoding.ExperimentalEncodingApi
|
|
||||||
|
|
||||||
open class CachedRequest(
|
open class CachedRequest(
|
||||||
context: Context,
|
context: Context,
|
||||||
@@ -34,9 +33,12 @@ open class CachedRequest(
|
|||||||
}, errorListener) {
|
}, errorListener) {
|
||||||
private val appContainer: AppContainer = (context as PolytechnicApplication).container
|
private val appContainer: AppContainer = (context as PolytechnicApplication).container
|
||||||
|
|
||||||
@OptIn(ExperimentalEncodingApi::class)
|
companion object {
|
||||||
suspend fun getMainPage(): MyResult<String> {
|
private const val REGEX: String = "<a href=\"(/\\d{4}/[\\w\\-_]+\\.xls)\">"
|
||||||
return withContext(Dispatchers.IO) {
|
val pattern: Pattern = Pattern.compile(REGEX, Pattern.MULTILINE)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun getXlsUrl(): MyResult<String> = withContext(Dispatchers.IO) {
|
||||||
val mainPageFuture = RequestFuture.newFuture<String>()
|
val mainPageFuture = RequestFuture.newFuture<String>()
|
||||||
val request = StringRequest(
|
val request = StringRequest(
|
||||||
Method.GET,
|
Method.GET,
|
||||||
@@ -46,24 +48,28 @@ open class CachedRequest(
|
|||||||
)
|
)
|
||||||
NetworkConnection.getInstance(context).addToRequestQueue(request)
|
NetworkConnection.getInstance(context).addToRequestQueue(request)
|
||||||
|
|
||||||
when (val response = tryGet(mainPageFuture)) {
|
val response = tryGet(mainPageFuture)
|
||||||
is MyResult.Failure -> response
|
if (response is MyResult.Failure)
|
||||||
is MyResult.Success -> {
|
return@withContext response
|
||||||
val encodedMainPage = Base64.Default.encode(response.data.encodeToByteArray())
|
|
||||||
MyResult.Success(encodedMainPage)
|
val pageData = (response as MyResult.Success).data
|
||||||
}
|
|
||||||
}
|
val matcher = pattern.matcher(pageData)
|
||||||
}
|
if (!matcher.find())
|
||||||
|
return@withContext MyResult.Failure(RuntimeException("Required url not found!"))
|
||||||
|
|
||||||
|
MyResult.Success("https://politehnikum-eng.ru" + matcher.group(1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private suspend fun updateMainPage(): MyResult<ScheduleGetCacheStatus.ResponseDto> {
|
private suspend fun updateMainPage(): MyResult<ScheduleGetCacheStatus.ResponseDto> {
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
when (val mainPage = getMainPage()) {
|
when (val xlsUrl = getXlsUrl()) {
|
||||||
is MyResult.Failure -> mainPage
|
is MyResult.Failure -> xlsUrl
|
||||||
is MyResult.Success -> {
|
is MyResult.Success -> {
|
||||||
tryFuture {
|
tryFuture {
|
||||||
ScheduleUpdate(
|
ScheduleUpdate(
|
||||||
ScheduleUpdate.RequestDto(mainPage.data),
|
ScheduleUpdate.RequestDto(xlsUrl.data),
|
||||||
context,
|
context,
|
||||||
it,
|
it,
|
||||||
it
|
it
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class AuthChangePassword(
|
|||||||
) : AuthorizedRequest(
|
) : AuthorizedRequest(
|
||||||
context,
|
context,
|
||||||
Method.POST,
|
Method.POST,
|
||||||
"auth/change-password",
|
"v1/auth/change-password",
|
||||||
{ listener.onResponse(null) },
|
{ listener.onResponse(null) },
|
||||||
errorListener,
|
errorListener,
|
||||||
canBeUnauthorized = true
|
canBeUnauthorized = true
|
||||||
|
|||||||
@@ -5,34 +5,25 @@ import com.android.volley.Response
|
|||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
import ru.n08i40k.polytechnic.next.model.Profile
|
||||||
import ru.n08i40k.polytechnic.next.network.RequestBase
|
import ru.n08i40k.polytechnic.next.network.RequestBase
|
||||||
|
|
||||||
class AuthSignIn(
|
class AuthSignIn(
|
||||||
private val data: RequestDto,
|
private val data: RequestDto,
|
||||||
context: Context,
|
context: Context,
|
||||||
listener: Response.Listener<ResponseDto>,
|
listener: Response.Listener<Profile>,
|
||||||
errorListener: Response.ErrorListener?
|
errorListener: Response.ErrorListener?
|
||||||
) : RequestBase(
|
) : RequestBase(
|
||||||
context,
|
context,
|
||||||
Method.POST,
|
Method.POST,
|
||||||
"auth/sign-in",
|
"v2/auth/sign-in",
|
||||||
{ listener.onResponse(Json.decodeFromString(it)) },
|
{ listener.onResponse(Json.decodeFromString(it)) },
|
||||||
errorListener
|
errorListener
|
||||||
) {
|
) {
|
||||||
@Serializable
|
@Serializable
|
||||||
data class RequestDto(val username: String, val password: String)
|
data class RequestDto(val username: String, val password: String)
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class ResponseDto(val id: String, val accessToken: String, val group: String)
|
|
||||||
|
|
||||||
override fun getBody(): ByteArray {
|
override fun getBody(): ByteArray {
|
||||||
return Json.encodeToString(data).toByteArray()
|
return Json.encodeToString(data).toByteArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getHeaders(): MutableMap<String, String> {
|
|
||||||
val headers = super.getHeaders()
|
|
||||||
headers["version"] = "2"
|
|
||||||
|
|
||||||
return headers
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -5,18 +5,19 @@ import com.android.volley.Response
|
|||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.encodeToString
|
import kotlinx.serialization.encodeToString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
import ru.n08i40k.polytechnic.next.model.Profile
|
||||||
import ru.n08i40k.polytechnic.next.model.UserRole
|
import ru.n08i40k.polytechnic.next.model.UserRole
|
||||||
import ru.n08i40k.polytechnic.next.network.RequestBase
|
import ru.n08i40k.polytechnic.next.network.RequestBase
|
||||||
|
|
||||||
class AuthSignUp(
|
class AuthSignUp(
|
||||||
private val data: RequestDto,
|
private val data: RequestDto,
|
||||||
context: Context,
|
context: Context,
|
||||||
listener: Response.Listener<ResponseDto>,
|
listener: Response.Listener<Profile>,
|
||||||
errorListener: Response.ErrorListener?
|
errorListener: Response.ErrorListener?
|
||||||
) : RequestBase(
|
) : RequestBase(
|
||||||
context,
|
context,
|
||||||
Method.POST,
|
Method.POST,
|
||||||
"auth/sign-up",
|
"v2/auth/sign-up",
|
||||||
{ listener.onResponse(Json.decodeFromString(it)) },
|
{ listener.onResponse(Json.decodeFromString(it)) },
|
||||||
errorListener
|
errorListener
|
||||||
) {
|
) {
|
||||||
@@ -28,9 +29,6 @@ class AuthSignUp(
|
|||||||
val role: UserRole
|
val role: UserRole
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class ResponseDto(val id: String, val accessToken: String)
|
|
||||||
|
|
||||||
override fun getBody(): ByteArray {
|
override fun getBody(): ByteArray {
|
||||||
return Json.encodeToString(data).toByteArray()
|
return Json.encodeToString(data).toByteArray()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class FcmSetToken(
|
|||||||
errorListener: Response.ErrorListener?,
|
errorListener: Response.ErrorListener?,
|
||||||
) : AuthorizedRequest(
|
) : AuthorizedRequest(
|
||||||
context, Method.POST,
|
context, Method.POST,
|
||||||
"fcm/set-token/$token",
|
"v1/fcm/set-token/$token",
|
||||||
{ listener.onResponse(Unit) },
|
{ listener.onResponse(Unit) },
|
||||||
errorListener,
|
errorListener,
|
||||||
true
|
true
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class FcmUpdateCallback(
|
|||||||
errorListener: Response.ErrorListener?,
|
errorListener: Response.ErrorListener?,
|
||||||
) : AuthorizedRequest(
|
) : AuthorizedRequest(
|
||||||
context, Method.POST,
|
context, Method.POST,
|
||||||
"fcm/update-callback/$version",
|
"v1/fcm/update-callback/$version",
|
||||||
{ listener.onResponse(Unit) },
|
{ listener.onResponse(Unit) },
|
||||||
errorListener,
|
errorListener,
|
||||||
true
|
true
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class ProfileChangeGroup(
|
|||||||
) : AuthorizedRequest(
|
) : AuthorizedRequest(
|
||||||
context,
|
context,
|
||||||
Method.POST,
|
Method.POST,
|
||||||
"users/change-group",
|
"v1/users/change-group",
|
||||||
{ listener.onResponse(null) },
|
{ listener.onResponse(null) },
|
||||||
errorListener
|
errorListener
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ class ProfileChangeUsername(
|
|||||||
) : AuthorizedRequest(
|
) : AuthorizedRequest(
|
||||||
context,
|
context,
|
||||||
Method.POST,
|
Method.POST,
|
||||||
"users/change-username",
|
"v1/users/change-username",
|
||||||
{ listener.onResponse(null) },
|
{ listener.onResponse(null) },
|
||||||
errorListener
|
errorListener
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class ProfileMe(
|
|||||||
) : AuthorizedRequest(
|
) : AuthorizedRequest(
|
||||||
context,
|
context,
|
||||||
Method.GET,
|
Method.GET,
|
||||||
"users/me",
|
"v2/users/me",
|
||||||
{ listener.onResponse(Json.decodeFromString(it)) },
|
{ listener.onResponse(Json.decodeFromString(it)) },
|
||||||
errorListener
|
errorListener
|
||||||
)
|
)
|
||||||
@@ -13,8 +13,8 @@ class ScheduleGet(
|
|||||||
errorListener: Response.ErrorListener? = null
|
errorListener: Response.ErrorListener? = null
|
||||||
) : CachedRequest(
|
) : CachedRequest(
|
||||||
context,
|
context,
|
||||||
Method.POST,
|
Method.GET,
|
||||||
"schedule/get-group",
|
"v2/schedule/group",
|
||||||
{ listener.onResponse(Json.decodeFromString(it)) },
|
{ listener.onResponse(Json.decodeFromString(it)) },
|
||||||
errorListener
|
errorListener
|
||||||
) {
|
) {
|
||||||
@@ -25,6 +25,6 @@ class ScheduleGet(
|
|||||||
data class ResponseDto(
|
data class ResponseDto(
|
||||||
val updatedAt: String,
|
val updatedAt: String,
|
||||||
val group: Group,
|
val group: Group,
|
||||||
val lastChangedDays: ArrayList<Int>,
|
val updated: ArrayList<Int>,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@ class ScheduleGetCacheStatus(
|
|||||||
) : AuthorizedRequest(
|
) : AuthorizedRequest(
|
||||||
context,
|
context,
|
||||||
Method.GET,
|
Method.GET,
|
||||||
"schedule/cache-status",
|
"v2/schedule/cache-status",
|
||||||
{ listener.onResponse(Json.decodeFromString(it)) },
|
{ listener.onResponse(Json.decodeFromString(it)) },
|
||||||
errorListener
|
errorListener
|
||||||
) {
|
) {
|
||||||
@@ -24,11 +24,4 @@ class ScheduleGetCacheStatus(
|
|||||||
val lastCacheUpdate: Long,
|
val lastCacheUpdate: Long,
|
||||||
val lastScheduleUpdate: Long,
|
val lastScheduleUpdate: Long,
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun getHeaders(): MutableMap<String, String> {
|
|
||||||
val headers = super.getHeaders()
|
|
||||||
headers["version"] = "1"
|
|
||||||
|
|
||||||
return headers
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@ class ScheduleGetGroupNames(
|
|||||||
) : RequestBase(
|
) : RequestBase(
|
||||||
context,
|
context,
|
||||||
Method.GET,
|
Method.GET,
|
||||||
"schedule/get-group-names",
|
"v2/schedule/group-names",
|
||||||
{ listener.onResponse(Json.decodeFromString(it)) },
|
{ listener.onResponse(Json.decodeFromString(it)) },
|
||||||
errorListener
|
errorListener
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -14,22 +14,13 @@ class ScheduleUpdate(
|
|||||||
errorListener: Response.ErrorListener? = null
|
errorListener: Response.ErrorListener? = null
|
||||||
) : AuthorizedRequest(
|
) : AuthorizedRequest(
|
||||||
context,
|
context,
|
||||||
Method.POST,
|
Method.PATCH,
|
||||||
"schedule/update-site-main-page",
|
"v2/schedule/update-download-url",
|
||||||
{ listener.onResponse(Json.decodeFromString(it)) },
|
{ listener.onResponse(Json.decodeFromString(it)) },
|
||||||
errorListener
|
errorListener
|
||||||
) {
|
) {
|
||||||
@Serializable
|
@Serializable
|
||||||
data class RequestDto(val mainPage: String)
|
data class RequestDto(val url: String)
|
||||||
|
|
||||||
override fun getBody(): ByteArray {
|
override fun getBody(): ByteArray = Json.encodeToString(data).toByteArray()
|
||||||
return Json.encodeToString(data).toByteArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getHeaders(): MutableMap<String, String> {
|
|
||||||
val headers = super.getHeaders()
|
|
||||||
headers["version"] = "1"
|
|
||||||
|
|
||||||
return headers
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@ class ScheduleReplacerClear(
|
|||||||
) : AuthorizedRequest(
|
) : AuthorizedRequest(
|
||||||
context,
|
context,
|
||||||
Method.POST,
|
Method.POST,
|
||||||
"schedule-replacer/clear",
|
"v1/schedule-replacer/clear",
|
||||||
{ listener.onResponse(Json.decodeFromString(it)) },
|
{ listener.onResponse(Json.decodeFromString(it)) },
|
||||||
errorListener
|
errorListener
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ class ScheduleReplacerGet(
|
|||||||
) : AuthorizedRequest(
|
) : AuthorizedRequest(
|
||||||
context,
|
context,
|
||||||
Method.GET,
|
Method.GET,
|
||||||
"schedule-replacer/get",
|
"v1/schedule-replacer/get",
|
||||||
{ listener.onResponse(Json.decodeFromString(it)) },
|
{ listener.onResponse(Json.decodeFromString(it)) },
|
||||||
errorListener
|
errorListener
|
||||||
)
|
)
|
||||||
@@ -14,7 +14,7 @@ class ScheduleReplacerSet(
|
|||||||
) : AuthorizedMultipartRequest(
|
) : AuthorizedMultipartRequest(
|
||||||
context,
|
context,
|
||||||
Method.POST,
|
Method.POST,
|
||||||
"schedule-replacer/set",
|
"v1/schedule-replacer/set",
|
||||||
{ listener.onResponse(null) },
|
{ listener.onResponse(null) },
|
||||||
errorListener
|
errorListener
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import android.os.IBinder
|
|||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.content.ContextCompat.startForegroundService
|
import androidx.core.content.ContextCompat.startForegroundService
|
||||||
|
import kotlinx.datetime.LocalDateTime
|
||||||
import ru.n08i40k.polytechnic.next.NotificationChannels
|
import ru.n08i40k.polytechnic.next.NotificationChannels
|
||||||
import ru.n08i40k.polytechnic.next.PolytechnicApplication
|
import ru.n08i40k.polytechnic.next.PolytechnicApplication
|
||||||
import ru.n08i40k.polytechnic.next.R
|
import ru.n08i40k.polytechnic.next.R
|
||||||
@@ -17,6 +18,7 @@ import ru.n08i40k.polytechnic.next.data.MyResult
|
|||||||
import ru.n08i40k.polytechnic.next.model.Day
|
import ru.n08i40k.polytechnic.next.model.Day
|
||||||
import ru.n08i40k.polytechnic.next.model.Group
|
import ru.n08i40k.polytechnic.next.model.Group
|
||||||
import ru.n08i40k.polytechnic.next.model.Lesson
|
import ru.n08i40k.polytechnic.next.model.Lesson
|
||||||
|
import ru.n08i40k.polytechnic.next.utils.dayMinutes
|
||||||
import ru.n08i40k.polytechnic.next.utils.fmtAsClock
|
import ru.n08i40k.polytechnic.next.utils.fmtAsClock
|
||||||
import ru.n08i40k.polytechnic.next.utils.getDayMinutes
|
import ru.n08i40k.polytechnic.next.utils.getDayMinutes
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
@@ -64,7 +66,7 @@ class CurrentLessonViewService : Service() {
|
|||||||
override fun run() {
|
override fun run() {
|
||||||
val logger = Logger.getLogger("CLV.updateRunnable")
|
val logger = Logger.getLogger("CLV.updateRunnable")
|
||||||
|
|
||||||
if (day == null || day!!.nonNullIndices.isEmpty()) {
|
if (day == null || day!!.lessons.isEmpty()) {
|
||||||
logger.warning("Stopping, because day is null or empty!")
|
logger.warning("Stopping, because day is null or empty!")
|
||||||
stopSelf()
|
stopSelf()
|
||||||
return
|
return
|
||||||
@@ -99,15 +101,16 @@ class CurrentLessonViewService : Service() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val firstLessonIdx = day!!.distanceToNextByMinutes(0)?.first
|
val firstLessonIdx =
|
||||||
|
day!!.distanceToNextByLocalDateTime(LocalDateTime(0, 0, 0, 0, 0))?.first
|
||||||
?: throw NullPointerException("Is this even real?")
|
?: throw NullPointerException("Is this even real?")
|
||||||
val distanceToFirst = day!!.lessons[firstLessonIdx]!!.time!!.start - currentMinutes
|
val distanceToFirst = day!!.lessons[firstLessonIdx]!!.time!!.start.dayMinutes - currentMinutes
|
||||||
|
|
||||||
val currentLessonDelay =
|
val currentLessonDelay =
|
||||||
if (currentLesson == null) // Если эта пара - перемена, то конец перемены через (результат getDistanceToNext)
|
if (currentLesson == null) // Если эта пара - перемена, то конец перемены через (результат getDistanceToNext)
|
||||||
nextLessonEntry!!.second
|
nextLessonEntry!!.second
|
||||||
else // Если эта пара - обычная пара, то конец пары через (конец этой пары - текущее кол-во минут)
|
else // Если эта пара - обычная пара, то конец пары через (конец этой пары - текущее кол-во минут)
|
||||||
currentLesson.time!!.end - currentMinutes
|
currentLesson.time!!.end.dayMinutes - currentMinutes
|
||||||
|
|
||||||
val currentLessonName =
|
val currentLessonName =
|
||||||
currentLesson?.getNameAndCabinetsShort(this@CurrentLessonViewService)
|
currentLesson?.getNameAndCabinetsShort(this@CurrentLessonViewService)
|
||||||
@@ -144,7 +147,7 @@ class CurrentLessonViewService : Service() {
|
|||||||
getString(
|
getString(
|
||||||
R.string.lesson_going_notification_description,
|
R.string.lesson_going_notification_description,
|
||||||
currentLessonName,
|
currentLessonName,
|
||||||
nextLessonTotal.fmtAsClock(),
|
nextLessonTotal.dayMinutes.fmtAsClock(),
|
||||||
nextLessonName,
|
nextLessonName,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -183,7 +186,7 @@ class CurrentLessonViewService : Service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val currentDay = group.current
|
val currentDay = group.current
|
||||||
if (currentDay == null || currentDay.nonNullIndices.isEmpty()) {
|
if (currentDay == null || currentDay.lessons.isEmpty()) {
|
||||||
logger.warning("Stopping, because current day is null or empty")
|
logger.warning("Stopping, because current day is null or empty")
|
||||||
stopSelf()
|
stopSelf()
|
||||||
return
|
return
|
||||||
@@ -191,7 +194,7 @@ class CurrentLessonViewService : Service() {
|
|||||||
|
|
||||||
val nowMinutes = Calendar.getInstance().getDayMinutes()
|
val nowMinutes = Calendar.getInstance().getDayMinutes()
|
||||||
if (nowMinutes < ((5 * 60) + 30)
|
if (nowMinutes < ((5 * 60) + 30)
|
||||||
|| currentDay.last!!.time.end < nowMinutes
|
|| currentDay.last!!.time.end.dayMinutes < nowMinutes
|
||||||
) {
|
) {
|
||||||
logger.warning("Stopping, because service started outside of acceptable time range!")
|
logger.warning("Stopping, because service started outside of acceptable time range!")
|
||||||
stopSelf()
|
stopSelf()
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import ru.n08i40k.polytechnic.next.work.FcmSetTokenWorker
|
|||||||
import java.time.Duration
|
import java.time.Duration
|
||||||
|
|
||||||
class MyFirebaseMessagingService : FirebaseMessagingService() {
|
class MyFirebaseMessagingService : FirebaseMessagingService() {
|
||||||
val scope = CoroutineScope(Job() + Dispatchers.Main)
|
private val scope = CoroutineScope(Job() + Dispatchers.Main)
|
||||||
|
|
||||||
override fun onNewToken(token: String) {
|
override fun onNewToken(token: String) {
|
||||||
super.onNewToken(token)
|
super.onNewToken(token)
|
||||||
@@ -53,7 +53,6 @@ class MyFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
@DrawableRes iconId: Int,
|
@DrawableRes iconId: Int,
|
||||||
title: String,
|
title: String,
|
||||||
contentText: String,
|
contentText: String,
|
||||||
priority: Int,
|
|
||||||
id: Any?,
|
id: Any?,
|
||||||
intent: Intent? = null
|
intent: Intent? = null
|
||||||
) {
|
) {
|
||||||
@@ -70,7 +69,7 @@ class MyFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
.setSmallIcon(iconId)
|
.setSmallIcon(iconId)
|
||||||
.setContentTitle(title)
|
.setContentTitle(title)
|
||||||
.setContentText(contentText)
|
.setContentText(contentText)
|
||||||
.setPriority(priority)
|
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||||
.setAutoCancel(true)
|
.setAutoCancel(true)
|
||||||
.setContentIntent(pendingIntent)
|
.setContentIntent(pendingIntent)
|
||||||
.build()
|
.build()
|
||||||
@@ -103,7 +102,6 @@ class MyFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
else
|
else
|
||||||
R.string.schedule_update_default
|
R.string.schedule_update_default
|
||||||
),
|
),
|
||||||
NotificationCompat.PRIORITY_DEFAULT,
|
|
||||||
message.data["etag"]
|
message.data["etag"]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -121,7 +119,6 @@ class MyFirebaseMessagingService : FirebaseMessagingService() {
|
|||||||
R.drawable.download,
|
R.drawable.download,
|
||||||
getString(R.string.app_update_title, message.data["version"]),
|
getString(R.string.app_update_title, message.data["version"]),
|
||||||
getString(R.string.app_update_description),
|
getString(R.string.app_update_description),
|
||||||
NotificationCompat.PRIORITY_DEFAULT,
|
|
||||||
message.data["version"],
|
message.data["version"],
|
||||||
Intent(Intent.ACTION_VIEW, Uri.parse(message.data["downloadLink"]))
|
Intent(Intent.ACTION_VIEW, Uri.parse(message.data["downloadLink"]))
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -29,7 +29,12 @@ val FilledGroup.Download: ImageVector
|
|||||||
) {
|
) {
|
||||||
moveTo(3.0f, 12.3f)
|
moveTo(3.0f, 12.3f)
|
||||||
verticalLineToRelative(7.0f)
|
verticalLineToRelative(7.0f)
|
||||||
arcToRelative(2.0f, 2.0f, 0.0f, false, false, 2.0f, 2.0f)
|
arcToRelative(2.0f, 2.0f, 0.0f,
|
||||||
|
isMoreThanHalf = false,
|
||||||
|
isPositiveArc = false,
|
||||||
|
dx1 = 2.0f,
|
||||||
|
dy1 = 2.0f
|
||||||
|
)
|
||||||
horizontalLineTo(19.0f)
|
horizontalLineTo(19.0f)
|
||||||
arcToRelative(2.0f, 2.0f, 0.0f, false, false, 2.0f, -2.0f)
|
arcToRelative(2.0f, 2.0f, 0.0f, false, false, 2.0f, -2.0f)
|
||||||
verticalLineToRelative(-7.0f)
|
verticalLineToRelative(-7.0f)
|
||||||
|
|||||||
@@ -2,14 +2,11 @@ package ru.n08i40k.polytechnic.next.ui.main.schedule
|
|||||||
|
|
||||||
import androidx.compose.foundation.BorderStroke
|
import androidx.compose.foundation.BorderStroke
|
||||||
import androidx.compose.foundation.background
|
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.PaddingValues
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.CardDefaults
|
import androidx.compose.material3.CardDefaults
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
@@ -20,7 +17,6 @@ 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.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
@@ -56,7 +52,7 @@ private fun getCurrentLessonIdx(day: Day?): Flow<Int> {
|
|||||||
fun DayCard(
|
fun DayCard(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
day: Day? = FakeScheduleRepository.exampleGroup.days[0],
|
day: Day? = FakeScheduleRepository.exampleGroup.days[0],
|
||||||
current: Boolean = true
|
distance: Int = 0
|
||||||
) {
|
) {
|
||||||
val defaultCardColors = CardDefaults.cardColors(
|
val defaultCardColors = CardDefaults.cardColors(
|
||||||
containerColor = MaterialTheme.colorScheme.secondaryContainer,
|
containerColor = MaterialTheme.colorScheme.secondaryContainer,
|
||||||
@@ -75,7 +71,7 @@ fun DayCard(
|
|||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
colors = CardDefaults.cardColors(
|
colors = CardDefaults.cardColors(
|
||||||
containerColor =
|
containerColor =
|
||||||
if (current) MaterialTheme.colorScheme.primaryContainer
|
if (distance == 0) MaterialTheme.colorScheme.primaryContainer
|
||||||
else MaterialTheme.colorScheme.secondaryContainer
|
else MaterialTheme.colorScheme.secondaryContainer
|
||||||
),
|
),
|
||||||
border = BorderStroke(1.dp, MaterialTheme.colorScheme.inverseSurface)
|
border = BorderStroke(1.dp, MaterialTheme.colorScheme.inverseSurface)
|
||||||
@@ -85,6 +81,7 @@ fun DayCard(
|
|||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
|
style = MaterialTheme.typography.titleLarge,
|
||||||
text = stringResource(R.string.day_null)
|
text = stringResource(R.string.day_null)
|
||||||
)
|
)
|
||||||
return@Card
|
return@Card
|
||||||
@@ -96,66 +93,55 @@ fun DayCard(
|
|||||||
text = day.name,
|
text = day.name,
|
||||||
)
|
)
|
||||||
|
|
||||||
val currentLessonIdx by getCurrentLessonIdx(if (current) day else null)
|
if (distance >= -1 && distance <= 1) {
|
||||||
|
Text(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
text = stringResource(when (distance) {
|
||||||
|
-1 -> R.string.yesterday
|
||||||
|
0 -> R.string.today
|
||||||
|
1 -> R.string.tommorow
|
||||||
|
else -> throw RuntimeException()
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val currentLessonIdx by getCurrentLessonIdx(if (distance == 0) day else null)
|
||||||
.collectAsStateWithLifecycle(0)
|
.collectAsStateWithLifecycle(0)
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
verticalArrangement = Arrangement.spacedBy(0.5.dp)
|
verticalArrangement = Arrangement.spacedBy(0.5.dp)
|
||||||
) {
|
) {
|
||||||
if (day.nonNullIndices.isEmpty()) {
|
if (day.lessons.isEmpty()) {
|
||||||
Text("Can't get schedule!")
|
Text("Can't get schedule!")
|
||||||
return@Column
|
return@Column
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i in day.nonNullIndices.first()..day.nonNullIndices.last()) {
|
for (lessonIdx in day.lessons.indices) {
|
||||||
val lesson = day.lessons[i]!!
|
val lesson = day.lessons[lessonIdx]
|
||||||
|
|
||||||
val cardColors = when (lesson.type) {
|
val cardColors = when (lesson.type) {
|
||||||
LessonType.DEFAULT -> defaultCardColors
|
LessonType.DEFAULT -> defaultCardColors
|
||||||
LessonType.CUSTOM -> customCardColors
|
LessonType.ADDITIONAL -> customCardColors
|
||||||
|
LessonType.BREAK -> noneCardColors
|
||||||
}
|
}
|
||||||
|
|
||||||
val mutableExpanded = remember { mutableStateOf(false) }
|
val mutableExpanded = remember { mutableStateOf(false) }
|
||||||
|
|
||||||
val lessonBoxModifier = remember {
|
Box(
|
||||||
Modifier
|
Modifier
|
||||||
.padding(PaddingValues(2.5.dp, 0.dp))
|
|
||||||
.clickable { mutableExpanded.value = true }
|
.clickable { mutableExpanded.value = true }
|
||||||
.background(cardColors.containerColor)
|
.background(cardColors.containerColor)
|
||||||
}
|
) {
|
||||||
|
val now = lessonIdx == currentLessonIdx
|
||||||
|
|
||||||
Box(
|
if (lesson.type === LessonType.BREAK)
|
||||||
modifier =
|
FreeLessonRow(lesson, lesson, cardColors, now)
|
||||||
if (i == currentLessonIdx) lessonBoxModifier.border(
|
else
|
||||||
border = BorderStroke(
|
LessonRow(day, lesson, cardColors, now)
|
||||||
3.5.dp,
|
|
||||||
Color(
|
|
||||||
cardColors.containerColor.red * 0.5F,
|
|
||||||
cardColors.containerColor.green * 0.5F,
|
|
||||||
cardColors.containerColor.blue * 0.5F,
|
|
||||||
1F
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else lessonBoxModifier
|
|
||||||
) {
|
|
||||||
LessonRow(
|
|
||||||
day, lesson, cardColors
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (i != day.nonNullIndices.last()) {
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(PaddingValues(2.5.dp, 0.dp))
|
|
||||||
.background(noneCardColors.containerColor)
|
|
||||||
) {
|
|
||||||
FreeLessonRow(
|
|
||||||
lesson,
|
|
||||||
day.lessons[day.nonNullIndices[day.nonNullIndices.indexOf(i) + 1]]!!,
|
|
||||||
noneCardColors
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mutableExpanded.value)
|
if (mutableExpanded.value)
|
||||||
|
|||||||
@@ -27,10 +27,10 @@ import java.util.logging.Level
|
|||||||
import kotlin.math.absoluteValue
|
import kotlin.math.absoluteValue
|
||||||
|
|
||||||
private fun isCurrentWeek(group: Group): Boolean {
|
private fun isCurrentWeek(group: Group): Boolean {
|
||||||
if (group.days.size == 0 || group.days[0] == null)
|
if (group.days.isEmpty())
|
||||||
return true
|
return true
|
||||||
|
|
||||||
val dateString = group.days[0]!!.name
|
val dateString = group.days[0].name
|
||||||
|
|
||||||
val formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy", Locale("ru"))
|
val formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy", Locale("ru"))
|
||||||
val datePart = dateString.split(" ").getOrNull(1) ?: return true
|
val datePart = dateString.split(" ").getOrNull(1) ?: return true
|
||||||
@@ -49,10 +49,12 @@ private fun isCurrentWeek(group: Group): Boolean {
|
|||||||
@Composable
|
@Composable
|
||||||
fun DayPager(group: Group = FakeScheduleRepository.exampleGroup) {
|
fun DayPager(group: Group = FakeScheduleRepository.exampleGroup) {
|
||||||
val currentDay = (Calendar.getInstance().get(Calendar.DAY_OF_WEEK) - 2)
|
val currentDay = (Calendar.getInstance().get(Calendar.DAY_OF_WEEK) - 2)
|
||||||
val calendarDay = currentDay
|
val calendarDay = if (currentDay == -1) 6 else currentDay
|
||||||
.coerceAtLeast(0)
|
|
||||||
.coerceAtMost(group.days.size - 1)
|
val pagerState = rememberPagerState(
|
||||||
val pagerState = rememberPagerState(initialPage = calendarDay, pageCount = { group.days.size })
|
initialPage = calendarDay
|
||||||
|
.coerceAtMost(group.days.size - 1),
|
||||||
|
pageCount = { group.days.size })
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
if (!isCurrentWeek(group)) {
|
if (!isCurrentWeek(group)) {
|
||||||
@@ -65,7 +67,9 @@ fun DayPager(group: Group = FakeScheduleRepository.exampleGroup) {
|
|||||||
state = pagerState,
|
state = pagerState,
|
||||||
contentPadding = PaddingValues(horizontal = 20.dp),
|
contentPadding = PaddingValues(horizontal = 20.dp),
|
||||||
verticalAlignment = Alignment.Top,
|
verticalAlignment = Alignment.Top,
|
||||||
modifier = Modifier.height(600.dp).padding(top = 5.dp)
|
modifier = Modifier
|
||||||
|
.height(600.dp)
|
||||||
|
.padding(top = 5.dp)
|
||||||
) { page ->
|
) { page ->
|
||||||
DayCard(
|
DayCard(
|
||||||
modifier = Modifier.graphicsLayer {
|
modifier = Modifier.graphicsLayer {
|
||||||
@@ -82,7 +86,7 @@ fun DayPager(group: Group = FakeScheduleRepository.exampleGroup) {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
day = group.days[page],
|
day = group.days[page],
|
||||||
current = currentDay == page
|
distance = page - currentDay
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
package ru.n08i40k.polytechnic.next.ui.main.schedule
|
package ru.n08i40k.polytechnic.next.ui.main.schedule
|
||||||
|
|
||||||
|
import androidx.compose.foundation.BorderStroke
|
||||||
|
import androidx.compose.foundation.border
|
||||||
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.Spacer
|
|
||||||
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.foundation.layout.width
|
|
||||||
import androidx.compose.foundation.layout.wrapContentWidth
|
import androidx.compose.foundation.layout.wrapContentWidth
|
||||||
import androidx.compose.material3.Card
|
import androidx.compose.material3.Card
|
||||||
import androidx.compose.material3.CardColors
|
import androidx.compose.material3.CardColors
|
||||||
@@ -26,11 +27,15 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.window.Dialog
|
import androidx.compose.ui.window.Dialog
|
||||||
|
import kotlinx.datetime.LocalDateTime
|
||||||
import ru.n08i40k.polytechnic.next.R
|
import ru.n08i40k.polytechnic.next.R
|
||||||
import ru.n08i40k.polytechnic.next.data.schedule.impl.FakeScheduleRepository
|
import ru.n08i40k.polytechnic.next.data.schedule.impl.FakeScheduleRepository
|
||||||
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.LessonTime
|
import ru.n08i40k.polytechnic.next.model.LessonTime
|
||||||
|
import ru.n08i40k.polytechnic.next.model.LessonType
|
||||||
|
import ru.n08i40k.polytechnic.next.model.SubGroup
|
||||||
|
import ru.n08i40k.polytechnic.next.utils.dayMinutes
|
||||||
import ru.n08i40k.polytechnic.next.utils.fmtAsClock
|
import ru.n08i40k.polytechnic.next.utils.fmtAsClock
|
||||||
|
|
||||||
private enum class LessonTimeFormat {
|
private enum class LessonTimeFormat {
|
||||||
@@ -58,28 +63,36 @@ private fun fmtTime(start: Int, end: Int, format: LessonTimeFormat): ArrayList<S
|
|||||||
@Preview(showBackground = true)
|
@Preview(showBackground = true)
|
||||||
@Composable
|
@Composable
|
||||||
fun LessonExtraInfo(
|
fun LessonExtraInfo(
|
||||||
lesson: Lesson = FakeScheduleRepository.exampleGroup.days[0]!!.lessons[0]!!,
|
lesson: Lesson = FakeScheduleRepository.exampleGroup.days[0].lessons[0],
|
||||||
mutableExpanded: MutableState<Boolean> = mutableStateOf(true)
|
mutableExpanded: MutableState<Boolean> = mutableStateOf(true)
|
||||||
) {
|
) {
|
||||||
Dialog(onDismissRequest = { mutableExpanded.value = false }) {
|
Dialog(onDismissRequest = { mutableExpanded.value = false }) {
|
||||||
|
if (lesson.type === LessonType.BREAK) {
|
||||||
|
mutableExpanded.value = false
|
||||||
|
return@Dialog
|
||||||
|
}
|
||||||
|
|
||||||
Card {
|
Card {
|
||||||
Column(Modifier.padding(10.dp)) {
|
Column(Modifier.padding(10.dp)) {
|
||||||
Text(lesson.name)
|
Text(lesson.name!!)
|
||||||
|
|
||||||
if (lesson.teacherNames.isNotEmpty()) {
|
for (subGroup in lesson.subGroups) {
|
||||||
val teachers = buildString {
|
val subGroups = buildString {
|
||||||
append(stringResource(if (lesson.teacherNames.count() > 1) R.string.lesson_teachers else R.string.lesson_teacher))
|
append("[")
|
||||||
|
append(subGroup.number)
|
||||||
|
append("] ")
|
||||||
|
append(subGroup.teacher)
|
||||||
append(" - ")
|
append(" - ")
|
||||||
append(lesson.teacherNames.joinToString(", "))
|
append(subGroup.cabinet)
|
||||||
}
|
}
|
||||||
Text(teachers)
|
Text(subGroups)
|
||||||
}
|
}
|
||||||
|
|
||||||
val duration = buildString {
|
val duration = buildString {
|
||||||
append(stringResource(R.string.lesson_duration))
|
append(stringResource(R.string.lesson_duration))
|
||||||
append(" - ")
|
append(" - ")
|
||||||
val duration =
|
val duration =
|
||||||
lesson.time.end - lesson.time.start
|
lesson.time.end.dayMinutes - lesson.time.start.dayMinutes
|
||||||
|
|
||||||
append(duration / 60)
|
append(duration / 60)
|
||||||
append(stringResource(R.string.hours))
|
append(stringResource(R.string.hours))
|
||||||
@@ -88,15 +101,6 @@ fun LessonExtraInfo(
|
|||||||
append(stringResource(R.string.minutes))
|
append(stringResource(R.string.minutes))
|
||||||
}
|
}
|
||||||
Text(duration)
|
Text(duration)
|
||||||
|
|
||||||
if (lesson.cabinets.isNotEmpty()) {
|
|
||||||
val cabinets = buildString {
|
|
||||||
append(stringResource(R.string.cabinets))
|
|
||||||
append(" - ")
|
|
||||||
append(lesson.cabinets.joinToString(", "))
|
|
||||||
}
|
|
||||||
Text(cabinets)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -105,47 +109,74 @@ fun LessonExtraInfo(
|
|||||||
@Preview(showBackground = true)
|
@Preview(showBackground = true)
|
||||||
@Composable
|
@Composable
|
||||||
private fun LessonViewRow(
|
private fun LessonViewRow(
|
||||||
idx: Int = 1,
|
range: List<Int>? = listOf(1, 3),
|
||||||
time: LessonTime? = LessonTime(0, 60),
|
time: LessonTime = LessonTime.fromLocalDateTime(
|
||||||
|
LocalDateTime(2024, 1, 1, 0, 0),
|
||||||
|
LocalDateTime(2024, 1, 1, 1, 0),
|
||||||
|
),
|
||||||
timeFormat: LessonTimeFormat = LessonTimeFormat.FROM_TO,
|
timeFormat: LessonTimeFormat = LessonTimeFormat.FROM_TO,
|
||||||
name: String = "Test",
|
name: String = "Test",
|
||||||
teacherNames: ArrayList<String> = arrayListOf(
|
subGroups: List<SubGroup> = listOf(),
|
||||||
"Хомченко Н.Е. (1 подggggggggggggggggggggggggggggggggggggggгруппа)",
|
|
||||||
"Хомченко Н.Е. (2 подгруппа)"
|
|
||||||
),
|
|
||||||
cabinets: ArrayList<String> = arrayListOf("14", "31"),
|
|
||||||
cardColors: CardColors = CardDefaults.cardColors(),
|
cardColors: CardColors = CardDefaults.cardColors(),
|
||||||
verticalPadding: Dp = 10.dp
|
verticalPadding: Dp = 10.dp,
|
||||||
|
now: Boolean = true,
|
||||||
) {
|
) {
|
||||||
val contentColor =
|
val contentColor =
|
||||||
if (timeFormat == LessonTimeFormat.FROM_TO) cardColors.contentColor else cardColors.disabledContentColor
|
if (timeFormat == LessonTimeFormat.FROM_TO) cardColors.contentColor
|
||||||
|
else cardColors.disabledContentColor
|
||||||
|
|
||||||
val teacherNamesRepl = teacherNames.map { it.replace("подгруппа", "подгр.") }
|
val rangeSize = if (range == null) 1 else (range[1] - range[0] + 1) * 2
|
||||||
|
|
||||||
|
Box(
|
||||||
|
if (now) Modifier.border(
|
||||||
|
BorderStroke(
|
||||||
|
3.5.dp,
|
||||||
|
Color(
|
||||||
|
cardColors.containerColor.red * 0.5F,
|
||||||
|
cardColors.containerColor.green * 0.5F,
|
||||||
|
cardColors.containerColor.blue * 0.5F,
|
||||||
|
1F
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) else Modifier
|
||||||
|
) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.padding(10.dp, verticalPadding),
|
modifier = Modifier.padding(10.dp, verticalPadding * rangeSize),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
) {
|
) {
|
||||||
|
val rangeString = run {
|
||||||
|
if (range == null)
|
||||||
|
" "
|
||||||
|
else
|
||||||
|
buildString {
|
||||||
|
val same = range[0] == range[1]
|
||||||
|
|
||||||
|
append(if (same) " " else range[0])
|
||||||
|
append(if (same) range[0] else "-")
|
||||||
|
append(if (same) " " else range[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
Text(
|
Text(
|
||||||
text = if (idx == -1) "1" else idx.toString(),
|
text = rangeString,
|
||||||
fontFamily = FontFamily.Monospace,
|
fontFamily = FontFamily.Monospace,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
color = if (idx == -1) Color(0) else contentColor
|
color = contentColor
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(Modifier.width(7.5.dp))
|
|
||||||
|
|
||||||
if (time != null) {
|
|
||||||
val formattedTime: ArrayList<String> = fmtTime(time.start, time.end, timeFormat)
|
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth(0.25f),
|
modifier = Modifier.fillMaxWidth(0.20f),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.Center
|
verticalArrangement = Arrangement.Center
|
||||||
) {
|
) {
|
||||||
|
val formattedTime: ArrayList<String> =
|
||||||
|
fmtTime(time.start.dayMinutes, time.end.dayMinutes, timeFormat)
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = formattedTime[0], fontFamily = FontFamily.Monospace, color = contentColor
|
text = formattedTime[0],
|
||||||
|
fontFamily = FontFamily.Monospace,
|
||||||
|
color = contentColor
|
||||||
)
|
)
|
||||||
|
|
||||||
if (formattedTime.count() > 1) {
|
if (formattedTime.count() > 1) {
|
||||||
Text(
|
Text(
|
||||||
text = formattedTime[1],
|
text = formattedTime[1],
|
||||||
@@ -154,16 +185,12 @@ private fun LessonViewRow(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(Modifier.width(7.5.dp))
|
Column(verticalArrangement = Arrangement.Center) {
|
||||||
|
|
||||||
Column(
|
|
||||||
verticalArrangement = Arrangement.Center
|
|
||||||
) {
|
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
horizontalArrangement = Arrangement.SpaceBetween
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
Column(modifier = Modifier.weight(1f)) {
|
Column(modifier = Modifier.weight(1f)) {
|
||||||
Text(
|
Text(
|
||||||
@@ -174,9 +201,9 @@ private fun LessonViewRow(
|
|||||||
color = contentColor
|
color = contentColor
|
||||||
)
|
)
|
||||||
|
|
||||||
for (teacherName in teacherNamesRepl) {
|
for (subGroup in subGroups) {
|
||||||
Text(
|
Text(
|
||||||
text = teacherName,
|
text = subGroup.teacher,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
color = contentColor
|
color = contentColor
|
||||||
@@ -185,17 +212,13 @@ private fun LessonViewRow(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Column(modifier = Modifier.wrapContentWidth()) {
|
Column(modifier = Modifier.wrapContentWidth()) {
|
||||||
if (cabinets.size <= teacherNamesRepl.size) {
|
if (subGroups.size != 1)
|
||||||
|
Text(text = "")
|
||||||
|
for (subGroup in subGroups) {
|
||||||
Text(
|
Text(
|
||||||
text = "",
|
text = subGroup.cabinet,
|
||||||
maxLines = 1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
for (listIdx: Int in 0..<cabinets.size) {
|
|
||||||
Text(
|
|
||||||
text = cabinets[listIdx],
|
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
fontFamily = FontFamily.Monospace,
|
||||||
color = contentColor
|
color = contentColor
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -205,41 +228,44 @@ private fun LessonViewRow(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Preview(showBackground = true)
|
@Preview(showBackground = true)
|
||||||
@Composable
|
@Composable
|
||||||
fun FreeLessonRow(
|
fun FreeLessonRow(
|
||||||
lesson: Lesson = FakeScheduleRepository.exampleGroup.days[0]!!.lessons[0]!!,
|
lesson: Lesson = FakeScheduleRepository.exampleGroup.days[0].lessons[0],
|
||||||
nextLesson: Lesson = FakeScheduleRepository.exampleGroup.days[0]!!.lessons[1]!!,
|
nextLesson: Lesson = FakeScheduleRepository.exampleGroup.days[0].lessons[1],
|
||||||
cardColors: CardColors = CardDefaults.cardColors()
|
cardColors: CardColors = CardDefaults.cardColors(),
|
||||||
|
now: Boolean = true
|
||||||
) {
|
) {
|
||||||
LessonViewRow(
|
LessonViewRow(
|
||||||
-1,
|
lesson.defaultRange,
|
||||||
LessonTime(lesson.time.end, nextLesson.time.start),
|
LessonTime(lesson.time.start, nextLesson.time.end),
|
||||||
LessonTimeFormat.ONLY_MINUTES_DURATION,
|
LessonTimeFormat.ONLY_MINUTES_DURATION,
|
||||||
stringResource(R.string.lesson_break),
|
stringResource(R.string.lesson_break),
|
||||||
arrayListOf(),
|
lesson.subGroups,
|
||||||
arrayListOf(),
|
|
||||||
cardColors,
|
cardColors,
|
||||||
2.5.dp
|
2.5.dp,
|
||||||
|
now
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview(showBackground = true)
|
@Preview(showBackground = true)
|
||||||
@Composable
|
@Composable
|
||||||
fun LessonRow(
|
fun LessonRow(
|
||||||
day: Day = FakeScheduleRepository.exampleGroup.days[0]!!,
|
day: Day = FakeScheduleRepository.exampleGroup.days[0],
|
||||||
lesson: Lesson = FakeScheduleRepository.exampleGroup.days[0]!!.lessons[0]!!,
|
lesson: Lesson = FakeScheduleRepository.exampleGroup.days[0].lessons[0],
|
||||||
cardColors: CardColors = CardDefaults.cardColors()
|
cardColors: CardColors = CardDefaults.cardColors(),
|
||||||
|
now: Boolean = true,
|
||||||
) {
|
) {
|
||||||
LessonViewRow(
|
LessonViewRow(
|
||||||
lesson.defaultIndex,
|
lesson.defaultRange,
|
||||||
lesson.time,
|
lesson.time,
|
||||||
LessonTimeFormat.FROM_TO,
|
LessonTimeFormat.FROM_TO,
|
||||||
lesson.name,
|
lesson.name!!,
|
||||||
lesson.teacherNames,
|
lesson.subGroups,
|
||||||
lesson.cabinets,
|
|
||||||
cardColors,
|
cardColors,
|
||||||
5.dp
|
5.dp,
|
||||||
|
now
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package ru.n08i40k.polytechnic.next.ui.main.schedule
|
||||||
|
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
|
import ru.n08i40k.polytechnic.next.R
|
||||||
|
|
||||||
|
@Preview(showSystemUi = true, showBackground = true)
|
||||||
|
@Composable
|
||||||
|
internal fun PaskhalkoDialog() {
|
||||||
|
Dialog(onDismissRequest = {}) {
|
||||||
|
Image(painterResource(R.drawable.paskhalko), contentDescription = "Paskhalko")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package ru.n08i40k.polytechnic.next.ui.main.schedule
|
package ru.n08i40k.polytechnic.next.ui.main.schedule
|
||||||
|
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
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.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
@@ -8,6 +9,7 @@ import androidx.compose.foundation.layout.padding
|
|||||||
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
|
||||||
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
@@ -52,10 +54,16 @@ fun UpdateInfo(
|
|||||||
onExpandedChange = { expanded = !expanded },
|
onExpandedChange = { expanded = !expanded },
|
||||||
title = { ExpandableCardTitle(stringResource(R.string.update_info_header)) }
|
title = { ExpandableCardTitle(stringResource(R.string.update_info_header)) }
|
||||||
) {
|
) {
|
||||||
|
var paskhalkoCounter by remember { mutableIntStateOf(0) }
|
||||||
|
|
||||||
|
if (paskhalkoCounter >= 10)
|
||||||
|
PaskhalkoDialog()
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(10.dp)
|
.padding(10.dp)
|
||||||
|
.clickable { ++paskhalkoCounter }
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
|||||||
@@ -323,7 +323,7 @@ fun AppTheme(
|
|||||||
darkTheme: Boolean = isSystemInDarkTheme(),
|
darkTheme: Boolean = isSystemInDarkTheme(),
|
||||||
// Dynamic color is available on Android 12+
|
// Dynamic color is available on Android 12+
|
||||||
dynamicColor: Boolean = true,
|
dynamicColor: Boolean = true,
|
||||||
content: @Composable() () -> Unit
|
content: @Composable () -> Unit
|
||||||
) {
|
) {
|
||||||
val colorScheme = when {
|
val colorScheme = when {
|
||||||
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
package ru.n08i40k.polytechnic.next.utils
|
package ru.n08i40k.polytechnic.next.utils
|
||||||
|
|
||||||
|
import kotlinx.datetime.Clock
|
||||||
|
import kotlinx.datetime.Instant
|
||||||
|
import kotlinx.datetime.LocalDateTime
|
||||||
|
import kotlinx.datetime.TimeZone
|
||||||
|
import kotlinx.datetime.toLocalDateTime
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
|
|
||||||
infix fun <T> T?.or(data: T): T {
|
infix fun <T> T?.or(data: T): T {
|
||||||
@@ -31,3 +36,17 @@ infix fun String.limit(count: Int): String {
|
|||||||
|
|
||||||
fun Calendar.getDayMinutes(): Int =
|
fun Calendar.getDayMinutes(): Int =
|
||||||
this.get(Calendar.HOUR_OF_DAY) * 60 + this.get(Calendar.MINUTE)
|
this.get(Calendar.HOUR_OF_DAY) * 60 + this.get(Calendar.MINUTE)
|
||||||
|
|
||||||
|
val Instant.dayMinutes: Int
|
||||||
|
get() = this.toLocalDateTime(TimeZone.currentSystemDefault()).dayMinutes
|
||||||
|
|
||||||
|
val LocalDateTime.dayMinutes: Int
|
||||||
|
get() = this.hour * 60 + this.minute
|
||||||
|
|
||||||
|
val Instant.dateTime: LocalDateTime
|
||||||
|
get() = this.toLocalDateTime(TimeZone.currentSystemDefault())
|
||||||
|
|
||||||
|
fun LocalDateTime.Companion.now(): LocalDateTime {
|
||||||
|
val clock = Clock.System.now()
|
||||||
|
return clock.toLocalDateTime(TimeZone.currentSystemDefault())
|
||||||
|
}
|
||||||
@@ -5,7 +5,6 @@ import androidx.work.Worker
|
|||||||
import androidx.work.WorkerParameters
|
import androidx.work.WorkerParameters
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import ru.n08i40k.polytechnic.next.PolytechnicApplication
|
import ru.n08i40k.polytechnic.next.PolytechnicApplication
|
||||||
import ru.n08i40k.polytechnic.next.service.CurrentLessonViewService
|
|
||||||
|
|
||||||
class LinkUpdateWorker(context: Context, params: WorkerParameters) :
|
class LinkUpdateWorker(context: Context, params: WorkerParameters) :
|
||||||
Worker(context, params) {
|
Worker(context, params) {
|
||||||
|
|||||||
BIN
app/src/main/res/drawable-mdpi/paskhalko.jpg
Normal file
BIN
app/src/main/res/drawable-mdpi/paskhalko.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 134 KiB |
@@ -73,4 +73,7 @@
|
|||||||
<string name="already_exists">Пользователь с таким именем уже зарегистрирован!</string>
|
<string name="already_exists">Пользователь с таким именем уже зарегистрирован!</string>
|
||||||
<string name="group_does_not_exists">Группа с таким названием не существует!</string>
|
<string name="group_does_not_exists">Группа с таким названием не существует!</string>
|
||||||
<string name="no_connection">Нет подключения к интернету!</string>
|
<string name="no_connection">Нет подключения к интернету!</string>
|
||||||
|
<string name="today">Сегодня</string>
|
||||||
|
<string name="yesterday">Вчера</string>
|
||||||
|
<string name="tommorow">Завтра</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -73,4 +73,7 @@
|
|||||||
<string name="already_exists">A user with this name is already registered!</string>
|
<string name="already_exists">A user with this name is already registered!</string>
|
||||||
<string name="group_does_not_exists">A group with this name does not exist!</string>
|
<string name="group_does_not_exists">A group with this name does not exist!</string>
|
||||||
<string name="no_connection">No internet connection!</string>
|
<string name="no_connection">No internet connection!</string>
|
||||||
|
<string name="today">Today</string>
|
||||||
|
<string name="yesterday">Yesterday</string>
|
||||||
|
<string name="tommorow">Tommorow</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[versions]
|
[versions]
|
||||||
accompanistSwiperefresh = "0.36.0"
|
accompanistSwiperefresh = "0.36.0"
|
||||||
agp = "8.7.0"
|
agp = "8.7.1"
|
||||||
firebaseBom = "33.4.0"
|
firebaseBom = "33.4.0"
|
||||||
hiltAndroid = "2.52"
|
hiltAndroid = "2.52"
|
||||||
hiltAndroidCompiler = "2.52"
|
hiltAndroidCompiler = "2.52"
|
||||||
@@ -12,12 +12,12 @@ junitVersion = "1.2.1"
|
|||||||
espressoCore = "3.6.1"
|
espressoCore = "3.6.1"
|
||||||
kotlinxSerializationJson = "1.7.3"
|
kotlinxSerializationJson = "1.7.3"
|
||||||
lifecycleRuntimeKtx = "2.8.6"
|
lifecycleRuntimeKtx = "2.8.6"
|
||||||
activityCompose = "1.9.2"
|
activityCompose = "1.9.3"
|
||||||
composeBom = "2024.09.03"
|
composeBom = "2024.10.00"
|
||||||
protobufLite = "3.0.1"
|
protobufLite = "3.0.1"
|
||||||
volley = "1.2.1"
|
volley = "1.2.1"
|
||||||
datastore = "1.1.1"
|
datastore = "1.1.1"
|
||||||
navigationCompose = "2.8.2"
|
navigationCompose = "2.8.3"
|
||||||
googleFirebaseCrashlytics = "3.0.2"
|
googleFirebaseCrashlytics = "3.0.2"
|
||||||
workRuntime = "2.9.1"
|
workRuntime = "2.9.1"
|
||||||
|
|
||||||
@@ -40,9 +40,10 @@ androidx-ui = { group = "androidx.compose.ui", name = "ui" }
|
|||||||
androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
|
androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
|
||||||
androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
|
androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
|
||||||
androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
|
androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
|
||||||
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest", version = "1.7.3" }
|
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest", version = "1.7.4" }
|
||||||
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
||||||
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
|
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
|
||||||
|
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version = "0.6.1" }
|
||||||
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
|
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
|
||||||
protobuf-lite = { module = "com.google.protobuf:protobuf-lite", version.ref = "protobufLite" }
|
protobuf-lite = { module = "com.google.protobuf:protobuf-lite", version.ref = "protobufLite" }
|
||||||
volley = { group = "com.android.volley", name = "volley", version.ref = "volley" }
|
volley = { group = "com.android.volley", name = "volley", version.ref = "volley" }
|
||||||
|
|||||||
Reference in New Issue
Block a user