forked from agzam/vyatsu-schedule
init
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
package agzam.vyatsu.domain
|
||||
|
||||
import agzam.vyatsu.domain.model.DateRange
|
||||
import agzam.vyatsu.domain.model.Season
|
||||
import java.time.LocalDate
|
||||
import java.time.ZoneId
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.temporal.ChronoUnit
|
||||
import java.time.temporal.TemporalAdjusters
|
||||
|
||||
object ScheduleDates {
|
||||
private val zone: ZoneId = ZoneId.of("Europe/Moscow")
|
||||
private val format: DateTimeFormatter = DateTimeFormatter.ofPattern("ddMMyyyy")
|
||||
|
||||
fun moscowToday(): LocalDate = LocalDate.now(zone)
|
||||
|
||||
fun asDate(dateStr: String): LocalDate = LocalDate.parse(dateStr, format)
|
||||
|
||||
fun dayIndexes(firstDate: String, today: LocalDate = moscowToday()): Pair<Int, Int> {
|
||||
val begin = asDate(firstDate)
|
||||
val anchor = begin.with(TemporalAdjusters.previousOrSame(java.time.DayOfWeek.MONDAY))
|
||||
val diff = ChronoUnit.DAYS.between(anchor, today)
|
||||
|
||||
var week = Math.floorMod(diff / 7, 2)
|
||||
var day = Math.floorMod(diff, 7)
|
||||
|
||||
if (day == 6) {
|
||||
day = (day + 1) % 7
|
||||
week = (week + 1) % 2
|
||||
}
|
||||
return week to day
|
||||
}
|
||||
|
||||
fun dateByIndexes(firstDate: String, week: Int, day: Int): LocalDate =
|
||||
asDate(firstDate).plusDays((week * 7 + day).toLong())
|
||||
|
||||
fun currentSeason(today: LocalDate = moscowToday()): Season =
|
||||
if (today.monthValue in 8..12) Season.AUTUMN else Season.SPRING
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package agzam.vyatsu.domain.model
|
||||
|
||||
data class DateRange(
|
||||
val first: String,
|
||||
val second: String
|
||||
)
|
||||
@@ -0,0 +1,16 @@
|
||||
package agzam.vyatsu.domain.model
|
||||
|
||||
import java.time.LocalDate
|
||||
|
||||
/**
|
||||
* День
|
||||
* @author Agzam
|
||||
*/
|
||||
data class Day(
|
||||
|
||||
/** Дата, парсится из формата dd.mm.yy из PDF **/
|
||||
val date: LocalDate,
|
||||
/** Список пар **/
|
||||
val intervals: List<TimeSlot>,
|
||||
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
package agzam.vyatsu.domain.model
|
||||
|
||||
/**
|
||||
* Группа студентов ВятГУ.
|
||||
* id — идентификатор группы из data-grp_period_id без последней цифры (как в PDF URL).
|
||||
*/
|
||||
data class Group(
|
||||
val id: String,
|
||||
val name: String,
|
||||
val faculty: String
|
||||
)
|
||||
@@ -0,0 +1,29 @@
|
||||
package agzam.vyatsu.domain.model
|
||||
|
||||
/**
|
||||
* Занятие
|
||||
* @author Agzam
|
||||
*/
|
||||
data class Lesson(
|
||||
|
||||
/** Сырое значение из PDF **/
|
||||
val raw: String,
|
||||
|
||||
/** Кабинет **/
|
||||
val room: String? = null,
|
||||
|
||||
/** Группа, например ИВТб-3304-05-00 **/
|
||||
val group: String? = null,
|
||||
/** Подгруппа, например на физкультуре **/
|
||||
val subgroup: String? = null,
|
||||
|
||||
/** Предмет **/
|
||||
val subject: String? = null,
|
||||
|
||||
/** Тип, например лекция/практика **/
|
||||
val type: LessonType = LessonType.OTHER,
|
||||
|
||||
/** Преподаватель **/
|
||||
val teacher: String? = null,
|
||||
|
||||
)
|
||||
@@ -0,0 +1,18 @@
|
||||
package agzam.vyatsu.domain.model
|
||||
|
||||
enum class LessonType(val label: String) {
|
||||
|
||||
LECTURE("Лекция"),
|
||||
PRACTICE("Практическое занятие"),
|
||||
LABORATORY("Лабораторная работа"),
|
||||
OTHER("Занятие");
|
||||
|
||||
companion object {
|
||||
fun fromRaw(raw: String): LessonType = when (raw.trim()) {
|
||||
"Лекция" -> LECTURE
|
||||
"Практическое занятие" -> PRACTICE
|
||||
"Лабораторная работа" -> LABORATORY
|
||||
else -> OTHER
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package agzam.vyatsu.domain.model
|
||||
|
||||
/**
|
||||
* Расписание группы, как правило содержит 2 недели
|
||||
* @author Agzam
|
||||
*/
|
||||
data class Schedule(
|
||||
|
||||
val groupId: String,
|
||||
val season: Season,
|
||||
|
||||
/** Может содержать более 7 дней */
|
||||
val days: List<Day>
|
||||
|
||||
) {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package agzam.vyatsu.domain.model
|
||||
|
||||
enum class Season {
|
||||
AUTUMN, SPRING;
|
||||
|
||||
val apiKey: String
|
||||
get() = when (this) {
|
||||
AUTUMN -> "1"
|
||||
SPRING -> "2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package agzam.vyatsu.domain.model
|
||||
|
||||
import java.time.LocalTime
|
||||
|
||||
/**
|
||||
* Временной промежуток/пара (например 08:20-09:30 из PDF)
|
||||
*
|
||||
* Может содержать несколько [Lesson], например для разделения на подгруппы
|
||||
* @author Agzam
|
||||
*/
|
||||
data class TimeSlot(
|
||||
|
||||
val start: LocalTime,
|
||||
val end: LocalTime,
|
||||
val lessons: List<Lesson>
|
||||
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
package agzam.vyatsu.domain.repository
|
||||
|
||||
import agzam.vyatsu.domain.model.Group
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface GroupRepository {
|
||||
fun observeGroups(): Flow<List<Group>>
|
||||
suspend fun getGroups(): List<Group>
|
||||
suspend fun getFaculties(): List<String>
|
||||
suspend fun refreshIfStale(): Boolean
|
||||
suspend fun forceRefresh(): Boolean
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package agzam.vyatsu.domain.repository
|
||||
|
||||
interface PreferencesRepository {
|
||||
suspend fun selectedGroupId(): String?
|
||||
suspend fun setSelectedGroup(groupId: String)
|
||||
suspend fun clearSelectedGroup()
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package agzam.vyatsu.domain.repository
|
||||
|
||||
import agzam.vyatsu.domain.model.Schedule
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
interface ScheduleRepository {
|
||||
fun observeSchedule(groupId: String): Flow<Schedule?>
|
||||
suspend fun getSchedule(groupId: String): Schedule?
|
||||
suspend fun sync(groupId: String): Schedule?
|
||||
suspend fun isStale(groupId: String): Boolean
|
||||
suspend fun clear(groupId: String)
|
||||
}
|
||||
Reference in New Issue
Block a user