forked from agzam/vyatsu-schedule
feat: department display
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
package agzam.vyatsu.data.local
|
||||
|
||||
import androidx.room.Embedded
|
||||
|
||||
/** Занятие преподавателя + кафедра-источник. Проекция LEFT JOIN, схема Room не меняется. */
|
||||
data class TeacherLessonWithDepartment(
|
||||
@Embedded val lesson: TeacherLessonEntity,
|
||||
val departmentId: String,
|
||||
val departmentName: String?
|
||||
)
|
||||
@@ -61,13 +61,15 @@ interface TeacherScheduleDao {
|
||||
fun observeDaysForPeriod(season: String, weekStart: Long): Flow<List<TeacherDayEntity>>
|
||||
|
||||
@Query(
|
||||
"SELECT teacher_lessons.* FROM teacher_lessons INNER JOIN teacher_days ON teacher_days.id = teacher_lessons.dayId " +
|
||||
"SELECT teacher_lessons.*, teacher_schedules.departmentId AS departmentId, departments.name AS departmentName " +
|
||||
"FROM teacher_lessons INNER JOIN teacher_days ON teacher_days.id = teacher_lessons.dayId " +
|
||||
"INNER JOIN teacher_schedules ON teacher_schedules.id = teacher_days.scheduleId " +
|
||||
"LEFT JOIN departments ON departments.departmentId = teacher_schedules.departmentId " +
|
||||
"WHERE teacher_schedules.season = :season AND teacher_schedules.weekStart <= :weekStart " +
|
||||
"AND teacher_schedules.weekEnd >= :weekStart " +
|
||||
"ORDER BY teacher_lessons.date, teacher_lessons.slotIndex, teacher_lessons.lessonIndex"
|
||||
)
|
||||
fun observeLessonsForPeriod(season: String, weekStart: Long): Flow<List<TeacherLessonEntity>>
|
||||
fun observeLessonsForPeriod(season: String, weekStart: Long): Flow<List<TeacherLessonWithDepartment>>
|
||||
|
||||
@Query(
|
||||
"SELECT DISTINCT teacher FROM teacher_lessons INNER JOIN teacher_days ON teacher_days.id = teacher_lessons.dayId " +
|
||||
|
||||
@@ -4,6 +4,7 @@ import agzam.vyatsu.data.local.DepartmentPeriodEntity
|
||||
import agzam.vyatsu.data.local.TeacherDao
|
||||
import agzam.vyatsu.data.local.TeacherDayEntity
|
||||
import agzam.vyatsu.data.local.TeacherLessonEntity
|
||||
import agzam.vyatsu.data.local.TeacherLessonWithDepartment
|
||||
import agzam.vyatsu.data.local.TeacherScheduleDao
|
||||
import agzam.vyatsu.data.local.TeacherScheduleEntity
|
||||
import agzam.vyatsu.data.remote.TeacherScheduleParser
|
||||
@@ -238,30 +239,30 @@ class TeacherScheduleRepositoryImpl(
|
||||
private fun buildTeacherSchedule(
|
||||
period: SchedulePeriod,
|
||||
dayEntities: List<TeacherDayEntity>,
|
||||
lessonEntities: List<TeacherLessonEntity>
|
||||
lessons: List<TeacherLessonWithDepartment>
|
||||
): TeacherSchedule? {
|
||||
val weekDays = dayEntities
|
||||
.filter {
|
||||
it.date >= period.weekStart.toEpochDay() && it.date <= period.weekEnd.toEpochDay()
|
||||
}
|
||||
if (weekDays.isEmpty()) return null
|
||||
val lessonsByDate = lessonEntities.groupBy { it.date }
|
||||
val lessonsByDate = lessons.groupBy { it.lesson.date }
|
||||
val days = weekDays
|
||||
.sortedBy { it.date }
|
||||
.distinctBy { it.date }
|
||||
.map { day ->
|
||||
val lessons = lessonsByDate[day.date].orEmpty()
|
||||
val dayLessons = lessonsByDate[day.date].orEmpty()
|
||||
Log.d(
|
||||
TAG,
|
||||
"build: date=${day.date} totalLessons=${lessons.size} " +
|
||||
"groupedByStart=${lessons.groupBy { it.start }.keys.sorted()}"
|
||||
"build: date=${day.date} totalLessons=${dayLessons.size} " +
|
||||
"groupedByStart=${dayLessons.groupBy { it.lesson.start }.keys.sorted()}"
|
||||
)
|
||||
val slots = lessons.groupBy { it.start }
|
||||
val slots = dayLessons.groupBy { it.lesson.start }
|
||||
.toSortedMap()
|
||||
.map { (startMin, slotLessons) ->
|
||||
val first = slotLessons.first()
|
||||
val times = slotLessons.map { "${it.start}-${it.end}" }.distinct()
|
||||
val teachers = slotLessons.map { it.teacher }.distinct()
|
||||
val first = slotLessons.first().lesson
|
||||
val times = slotLessons.map { "${it.lesson.start}-${it.lesson.end}" }.distinct()
|
||||
val teachers = slotLessons.map { it.lesson.teacher }.distinct()
|
||||
Log.d(
|
||||
TAG,
|
||||
"build: date=${day.date} start=$startMin firstEnd=$first.end " +
|
||||
@@ -271,7 +272,7 @@ class TeacherScheduleRepositoryImpl(
|
||||
start = LocalTime.of(startMin / 60, startMin % 60),
|
||||
end = LocalTime.of(first.end / 60, first.end % 60),
|
||||
lessons = slotLessons
|
||||
.sortedBy { it.lessonIndex }
|
||||
.sortedBy { it.lesson.lessonIndex }
|
||||
.map { it.toDomain() }
|
||||
)
|
||||
}
|
||||
@@ -280,16 +281,33 @@ class TeacherScheduleRepositoryImpl(
|
||||
return TeacherSchedule(period = period, days = days)
|
||||
}
|
||||
|
||||
private fun TeacherLessonEntity.toDomain(): Lesson = Lesson(
|
||||
raw = raw,
|
||||
room = room,
|
||||
group = groupName,
|
||||
subgroup = subgroup,
|
||||
subject = subject,
|
||||
type = type,
|
||||
teacher = teacher
|
||||
private fun TeacherLessonWithDepartment.toDomain(): Lesson = Lesson(
|
||||
raw = lesson.raw,
|
||||
room = lesson.room,
|
||||
group = lesson.groupName,
|
||||
subgroup = lesson.subgroup,
|
||||
subject = lesson.subject,
|
||||
type = lesson.type,
|
||||
teacher = lesson.teacher,
|
||||
department = departmentLabel(departmentId, departmentName)
|
||||
)
|
||||
|
||||
// Названия, не выводимые акронимом из слов (например «топ-уровня в сфере…»)
|
||||
private val DEPARTMENT_LABELS = mapOf(
|
||||
"974" to "Топ ИИ"
|
||||
)
|
||||
|
||||
private fun departmentLabel(departmentId: String, departmentName: String?): String {
|
||||
DEPARTMENT_LABELS[departmentId]?.let { return it }
|
||||
val name = departmentName ?: return "каф. $departmentId"
|
||||
val words = name.removePrefix("Кафедра ").removePrefix("кафедра ")
|
||||
.substringBefore(" (")
|
||||
.split(" ")
|
||||
.filter { it.isNotBlank() && it != "и" }
|
||||
val acronym = words.joinToString("") { it.first().uppercase().toString() }
|
||||
return acronym.ifBlank { "каф. $departmentId" }
|
||||
}
|
||||
|
||||
private fun LocalTime.toMinutesOfDay(): Int = hour * 60 + minute
|
||||
|
||||
private fun now(): Long = System.currentTimeMillis()
|
||||
|
||||
@@ -26,4 +26,6 @@ data class Lesson(
|
||||
/** Преподаватель **/
|
||||
val teacher: String? = null,
|
||||
|
||||
/** Кафедра-источник (только в расписании преподавателей) **/
|
||||
val department: String? = null,
|
||||
)
|
||||
|
||||
@@ -70,6 +70,16 @@ internal fun LessonSlot(slotIndex: Int, slot: TimeSlot, showTeacher: Boolean = t
|
||||
) {
|
||||
var any = false
|
||||
|
||||
if (lesson.department != null) {
|
||||
Text(
|
||||
lesson.department,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.padding(horizontal = hPadding)
|
||||
)
|
||||
any = true
|
||||
}
|
||||
|
||||
val meta = listOfNotNull(
|
||||
if (lesson.type == LessonType.OTHER) {
|
||||
null
|
||||
|
||||
Reference in New Issue
Block a user