diff --git a/app/src/main/java/agzam/vyatsu/data/remote/VyatsuUrls.kt b/app/src/main/java/agzam/vyatsu/data/remote/VyatsuUrls.kt index aa63b9f..8513865 100644 --- a/app/src/main/java/agzam/vyatsu/data/remote/VyatsuUrls.kt +++ b/app/src/main/java/agzam/vyatsu/data/remote/VyatsuUrls.kt @@ -10,4 +10,9 @@ object VyatsuUrls { fun groupPdfUrl(groupId: String, season: Season, range: DateRange): String = "$PDF_BASEURL/${groupId}_${season.apiKey}_${range.first}_${range.second}.pdf" + const val TEACHER_PAGE = "https://www.vyatsu.ru/studentu-1/spravochnaya-informatsiya/teacher.html" + const val PREPOD_BASEURL = "https://www.vyatsu.ru/reports/schedule/prepod" + + fun teacherPrepodUrl(departmentId: String, season: Season, range: DateRange): String = "$PREPOD_BASEURL/${departmentId}_${season.apiKey}_${range.first}_${range.second}.html" + } diff --git a/app/src/main/java/agzam/vyatsu/data/repository/TeacherRepositoryImpl.kt b/app/src/main/java/agzam/vyatsu/data/repository/TeacherRepositoryImpl.kt new file mode 100644 index 0000000..f7eb365 --- /dev/null +++ b/app/src/main/java/agzam/vyatsu/data/repository/TeacherRepositoryImpl.kt @@ -0,0 +1,86 @@ +package agzam.vyatsu.data.repository + +import agzam.vyatsu.data.local.DepartmentEntity +import agzam.vyatsu.data.local.DepartmentPeriodEntity +import agzam.vyatsu.data.local.TeacherDao +import agzam.vyatsu.data.remote.TeachersParser +import agzam.vyatsu.data.remote.VyatsuHttpClient +import agzam.vyatsu.data.remote.VyatsuUrls +import agzam.vyatsu.domain.ScheduleDates +import agzam.vyatsu.domain.model.Department +import agzam.vyatsu.domain.repository.TeacherRepository +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.withContext + +class TeacherRepositoryImpl( + private val teacherDao: TeacherDao, +) : TeacherRepository { + + override fun observeDepartments(): Flow> = + teacherDao.observeDepartments().map { list -> list.map { it.toDomain() } } + + override suspend fun getDepartments(): List = + teacherDao.observeDepartments().first().map { it.toDomain() } + + override suspend fun getFaculties(): List = teacherDao.getFaculties() + + override suspend fun refreshIfStale(): Boolean { + val last = teacherDao.maxSyncedAt() + if (last != null && now() - last < STALE_WINDOW_MS) { + return true + } + refresh() + return true + } + + override suspend fun forceRefresh(): Boolean { + refresh() + return true + } + + private suspend fun refresh() { + val parsed = withContext(Dispatchers.IO) { + VyatsuHttpClient.openStream(VyatsuUrls.TEACHER_PAGE).use(TeachersParser::parseStream) + } + val now = now() + teacherDao.insertAll( + parsed.departments.map { department -> + DepartmentEntity( + departmentId = department.departmentId, + name = department.name, + faculty = department.faculty, + lastSyncedAt = now + ) + } + ) + val periods = parsed.departments.flatMap { department -> + parsed.dateRanges[department.departmentId].orEmpty().flatMap { (season, ranges) -> + ranges.map { range -> + DepartmentPeriodEntity( + departmentId = department.departmentId, + season = season, + weekStart = ScheduleDates.asDate(range.first).toEpochDay(), + weekEnd = ScheduleDates.asDate(range.second).toEpochDay() + ) + } + } + } + teacherDao.deleteAllPeriods() + teacherDao.insertPeriods(periods) + } + + private fun now(): Long = System.currentTimeMillis() + + private fun DepartmentEntity.toDomain(): Department = Department( + departmentId = departmentId, + name = name, + faculty = faculty + ) + + companion object { + private const val STALE_WINDOW_MS = 12 * 60 * 60 * 1000L + } +} \ No newline at end of file