diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Regexes.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Regexes.kt
index 5d847e3f..2bbf1894 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Regexes.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/Regexes.kt
@@ -117,6 +117,17 @@ object Regexes {
}
+ val MOBIDZIENNIK_TIMETABLE_TOP by lazy {
+ """
.+?
""".toRegex(DOT_MATCHES_ALL)
+ }
+ val MOBIDZIENNIK_TIMETABLE_CELL by lazy {
+ """.+?style="(.+?)".+?title="(.+?)".+?>\s+(.+?)\s+
""".toRegex(DOT_MATCHES_ALL)
+ }
+ val MOBIDZIENNIK_TIMETABLE_LEFT by lazy {
+ """.+?
""".toRegex(DOT_MATCHES_ALL)
+ }
+
+
val IDZIENNIK_LOGIN_HIDDEN_FIELDS by lazy {
"""""".toRegex(DOT_MATCHES_ALL)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/DataEdudziennik.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/DataEdudziennik.kt
index 40601249..49a9d4a0 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/DataEdudziennik.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/DataEdudziennik.kt
@@ -111,37 +111,6 @@ class DataEdudziennik(app: App, profile: Profile?, loginStore: LoginStore) : Dat
val courseStudentEndpoint: String
get() = "Course/$studentId/"
- fun getSubject(longId: String, name: String): Subject {
- val id = longId.crc32()
- return subjectList.singleOrNull { it.id == id } ?: run {
- val subject = Subject(profileId, id, name, name)
- subjectList.put(id, subject)
- subject
- }
- }
-
- fun getTeacher(firstName: String, lastName: String, longId: String? = null): Teacher {
- val name = "$firstName $lastName".fixName()
- val id = name.crc32()
- return teacherList.singleOrNull { it.id == id }?.also {
- if (longId != null && it.loginId == null) it.loginId = longId
- } ?: run {
- val teacher = Teacher(profileId, id, firstName, lastName, longId)
- teacherList.put(id, teacher)
- teacher
- }
- }
-
- fun getTeacherByFirstLast(nameFirstLast: String, longId: String? = null): Teacher {
- val nameParts = nameFirstLast.split(" ")
- return getTeacher(nameParts[0], nameParts[1], longId)
- }
-
- fun getTeacherByLastFirst(nameLastFirst: String, longId: String? = null): Teacher {
- val nameParts = nameLastFirst.split(" ")
- return getTeacher(nameParts[1], nameParts[0], longId)
- }
-
fun getEventType(longId: String, name: String): EventType {
val id = longId.crc16().toLong()
return eventTypes.singleOrNull { it.id == id } ?: run {
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebExams.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebExams.kt
index f6abf637..c700100c 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebExams.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebExams.kt
@@ -40,7 +40,7 @@ class EdudziennikWebExams(override val data: DataEdudziennik,
val subjectId = EDUDZIENNIK_SUBJECT_ID.find(subjectElement.attr("href"))?.get(1)
?: return@forEach
val subjectName = subjectElement.text().trim()
- val subject = data.getSubject(subjectId, subjectName)
+ val subject = data.getSubject(subjectId.crc32(), subjectName)
val dateString = examElement.child(2).text().trim()
if (dateString.isBlank()) return@forEach
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebGrades.kt
index 459f13aa..6a247290 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebGrades.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebGrades.kt
@@ -53,7 +53,7 @@ class EdudziennikWebGrades(override val data: DataEdudziennik,
val subjectId = subjectElement.id().trim()
val subjectName = subjectElement.child(0).text().trim()
- val subject = data.getSubject(subjectId, subjectName)
+ val subject = data.getSubject(subjectId.crc32(), subjectName)
val gradeType = when {
subjectElement.select("#sum").text().isNotBlank() -> TYPE_POINT_SUM
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebHomework.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebHomework.kt
index 169a5127..b843abe9 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebHomework.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebHomework.kt
@@ -41,7 +41,7 @@ class EdudziennikWebHomework(override val data: DataEdudziennik,
val subjectId = EDUDZIENNIK_SUBJECT_ID.find(subjectElement.attr("href"))?.get(1)
?: return@forEach
val subjectName = subjectElement.text()
- val subject = data.getSubject(subjectId, subjectName)
+ val subject = data.getSubject(subjectId.crc32(), subjectName)
val lessons = data.app.db.timetableDao().getAllForDateNow(profileId, date)
val startTime = lessons.firstOrNull { it.subjectId == subject.id }?.displayStartTime
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebStart.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebStart.kt
index 66cb7a59..3fdd6e0e 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebStart.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebStart.kt
@@ -73,7 +73,7 @@ class EdudziennikWebStart(override val data: DataEdudziennik,
EDUDZIENNIK_SUBJECTS_START.findAll(text).forEach {
val id = it[1].trim()
val name = it[2].trim()
- data.getSubject(id, name)
+ data.getSubject(id.crc32(), name)
}
}
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebTimetable.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebTimetable.kt
index 94db15ef..33feb75e 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebTimetable.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebTimetable.kt
@@ -5,6 +5,7 @@
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
import org.jsoup.Jsoup
+import pl.szczodrzynski.edziennik.crc32
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_SUBJECT_ID
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_TEACHER_ID
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
@@ -89,7 +90,7 @@ class EdudziennikWebTimetable(override val data: DataEdudziennik,
val subjectId = EDUDZIENNIK_SUBJECT_ID.find(subjectElement.attr("href"))?.get(1)
?: return@forEachIndexed
val subjectName = subjectElement.text().trim()
- val subject = data.getSubject(subjectId, subjectName)
+ val subject = data.getSubject(subjectId.crc32(), subjectName)
/* Getting teacher */
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/MobidziennikFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/MobidziennikFeatures.kt
index 7396ac52..7b39e455 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/MobidziennikFeatures.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/MobidziennikFeatures.kt
@@ -18,6 +18,7 @@ const val ENDPOINT_MOBIDZIENNIK_WEB_ATTENDANCE = 2050
const val ENDPOINT_MOBIDZIENNIK_WEB_MANUALS = 2100
const val ENDPOINT_MOBIDZIENNIK_WEB_ACCOUNT_EMAIL = 2200
const val ENDPOINT_MOBIDZIENNIK_WEB_HOMEWORK = 2300 // not used as an endpoint
+const val ENDPOINT_MOBIDZIENNIK_WEB_TIMETABLE = 2400
const val ENDPOINT_MOBIDZIENNIK_API2_MAIN = 3000
val MobidziennikFeatures = listOf(
@@ -38,6 +39,12 @@ val MobidziennikFeatures = listOf(
+ /**
+ * Timetable - web scraping - does nothing if the API_MAIN timetable is enough.
+ */
+ Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_TIMETABLE, listOf(
+ ENDPOINT_MOBIDZIENNIK_WEB_TIMETABLE to LOGIN_METHOD_MOBIDZIENNIK_WEB
+ ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB, LOGIN_METHOD_MOBIDZIENNIK_WEB)),
/**
* Agenda - "API" + web scraping.
*/
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/MobidziennikData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/MobidziennikData.kt
index 09e1e9fb..b82f6355 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/MobidziennikData.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/MobidziennikData.kt
@@ -84,6 +84,10 @@ class MobidziennikData(val data: DataMobidziennik, val onSuccess: () -> Unit) {
data.startProgress(R.string.edziennik_progress_endpoint_lucky_number)
MobidziennikWebManuals(data, lastSync, onSuccess)
}*/
+ ENDPOINT_MOBIDZIENNIK_WEB_TIMETABLE-> {
+ data.startProgress(R.string.edziennik_progress_endpoint_timetable)
+ MobidziennikWebTimetable(data, lastSync, onSuccess)
+ }
else -> onSuccess(endpointId)
}
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebTimetable.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebTimetable.kt
new file mode 100644
index 00000000..221c50aa
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebTimetable.kt
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2021-9-8.
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.web
+
+import android.annotation.SuppressLint
+import org.jsoup.Jsoup
+import pl.szczodrzynski.edziennik.*
+import pl.szczodrzynski.edziennik.data.api.Regexes
+import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.ENDPOINT_MOBIDZIENNIK_WEB_TIMETABLE
+import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.MobidziennikWeb
+import pl.szczodrzynski.edziennik.data.db.entity.Lesson
+import pl.szczodrzynski.edziennik.data.db.entity.Metadata
+import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
+import pl.szczodrzynski.edziennik.utils.models.Date
+import pl.szczodrzynski.edziennik.utils.models.Time
+import pl.szczodrzynski.edziennik.utils.models.Week
+import kotlin.collections.set
+import kotlin.text.replace
+
+class MobidziennikWebTimetable(
+ override val data: DataMobidziennik,
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit
+) : MobidziennikWeb(data, lastSync) {
+ companion object {
+ private const val TAG = "MobidziennikWebTimetable"
+ }
+
+ private val rangesH = mutableMapOf, Date>()
+ private val hoursV = mutableMapOf>()
+ private var startDate: Date
+
+ private fun parseCss(css: String): Map {
+ return css.split(";").mapNotNull {
+ val spl = it.split(":")
+ if (spl.size != 2)
+ return@mapNotNull null
+ return@mapNotNull spl[0].trim() to spl[1].trim()
+ }.toMap()
+ }
+
+ private fun getRangeH(h: Float): Date? {
+ return rangesH.entries.firstOrNull {
+ h in it.key
+ }?.value
+ }
+
+ private fun stringToDate(date: String): Date? {
+ val items = date.split(" ")
+ val day = items.getOrNull(0)?.toIntOrNull() ?: return null
+ val year = items.getOrNull(2)?.toIntOrNull() ?: return null
+ val month = when (items.getOrNull(1)) {
+ "stycznia" -> 1
+ "lutego" -> 2
+ "marca" -> 3
+ "kwietnia" -> 4
+ "maja" -> 5
+ "czerwca" -> 6
+ "lipca" -> 7
+ "sierpnia" -> 8
+ "września" -> 9
+ "października" -> 10
+ "listopada" -> 11
+ "grudnia" -> 12
+ else -> return null
+ }
+ return Date(year, month, day)
+ }
+
+ init {
+ val currentWeekStart = Week.getWeekStart()
+ val nextWeekEnd = Week.getWeekEnd().stepForward(0, 0, 7)
+ if (Date.getToday().weekDay > 4) {
+ currentWeekStart.stepForward(0, 0, 7)
+ }
+ startDate = data.arguments?.getString("weekStart")?.let {
+ Date.fromY_m_d(it)
+ } ?: currentWeekStart
+
+ val syncFutureDate = startDate > nextWeekEnd
+ // TODO: 2021-09-09 make DataRemoveModel keep extra lessons
+ val syncExtraLessons = false && System.currentTimeMillis() - (lastSync ?: 0) > 2 * DAY * MS
+ if (!syncFutureDate && !syncExtraLessons) {
+ onSuccess(ENDPOINT_MOBIDZIENNIK_WEB_TIMETABLE)
+ }
+ else {
+ val types = when {
+ syncFutureDate -> mutableListOf("podstawowy")//, "pozalekcyjny")
+ syncExtraLessons -> mutableListOf("pozalekcyjny")
+ else -> mutableListOf()
+ }
+
+ syncTypes(types, startDate) {
+ // set as synced now only when not syncing future date
+ // (to avoid waiting 2 days for normal sync after future sync)
+ if (syncExtraLessons)
+ data.setSyncNext(ENDPOINT_MOBIDZIENNIK_WEB_TIMETABLE, SYNC_ALWAYS)
+ onSuccess(ENDPOINT_MOBIDZIENNIK_WEB_TIMETABLE)
+ }
+ }
+ }
+
+ private fun syncTypes(types: MutableList, startDate: Date, onSuccess: () -> Unit) {
+ if (types.isEmpty()) {
+ onSuccess()
+ return
+ }
+ val type = types.removeAt(0)
+ webGet(TAG, "/dziennik/planlekcji?typ=$type&tydzien=${startDate.stringY_m_d}") { html ->
+ MobidziennikLuckyNumberExtractor(data, html)
+ readRangesH(html)
+ readRangesV(html)
+ readLessons(html)
+ syncTypes(types, startDate, onSuccess)
+ }
+ }
+
+ private fun readRangesH(html: String) {
+ val htmlH = Regexes.MOBIDZIENNIK_TIMETABLE_TOP.find(html) ?: return
+ val docH = Jsoup.parse(htmlH.value)
+
+ var posH = 0f
+ for (el in docH.select("div > div")) {
+ val css = parseCss(el.attr("style"))
+ val width = css["width"]
+ ?.trimEnd('%')
+ ?.toFloatOrNull()
+ ?: continue
+ val value = stringToDate(el.attr("title"))
+ ?: continue
+
+ val range = posH.rangeTo(posH + width)
+ posH += width
+
+ rangesH[range] = value
+ }
+ }
+
+ private fun readRangesV(html: String) {
+ val htmlV = Regexes.MOBIDZIENNIK_TIMETABLE_LEFT.find(html) ?: return
+ val docV = Jsoup.parse(htmlV.value)
+
+ for (el in docV.select("div > div")) {
+ val css = parseCss(el.attr("style"))
+ val top = css["top"]
+ ?.trimEnd('%')
+ ?.toFloatOrNull()
+ ?: continue
+ val values = el.text().split(" ")
+
+ val time = values.getOrNull(0)?.let {
+ Time.fromH_m(it)
+ } ?: continue
+ val num = values.getOrNull(1)?.toIntOrNull()
+
+ hoursV[(top * 100).toInt()] = time to num
+ }
+ }
+
+ private val whitespaceRegex = "\\s+".toRegex()
+ private val classroomRegex = "\\((.*)\\)".toRegex()
+ private fun cleanup(str: String): List {
+ return str
+ .replace(whitespaceRegex, " ")
+ .replace("\n", "")
+ .replace("<small>", "$")
+ .replace("</small>", "$")
+ .replace("<br />", "\n")
+ .replace("<br/>", "\n")
+ .replace("<br>", "\n")
+ .replace("
", "\n")
+ .replace("
", "\n")
+ .replace("
", "\n")
+ .replace("", "%")
+ .replace("", "%")
+ .replace("", "")
+ .replace("", "")
+ .split("\n")
+ .map { it.trim() }
+ }
+
+ @SuppressLint("LongLogTag", "LogNotTimber")
+ private fun readLessons(html: String) {
+ val matches = Regexes.MOBIDZIENNIK_TIMETABLE_CELL.findAll(html)
+
+ val noLessonDays = mutableListOf()
+ for (i in 0..6) {
+ noLessonDays.add(startDate.clone().stepForward(0, 0, i))
+ }
+
+ for (match in matches) {
+ val css = parseCss("${match[1]};${match[2]}")
+ val left = css["left"]?.trimEnd('%')?.toFloatOrNull() ?: continue
+ val top = css["top"]?.trimEnd('%')?.toFloatOrNull() ?: continue
+ val width = css["width"]?.trimEnd('%')?.toFloatOrNull() ?: continue
+ val height = css["height"]?.trimEnd('%')?.toFloatOrNull() ?: continue
+
+ val posH = left + width / 2f
+ val topInt = (top * 100).toInt()
+ val bottomInt = ((top + height) * 100).toInt()
+
+ val lessonDate = getRangeH(posH) ?: continue
+ val (startTime, lessonNumber) = hoursV[topInt] ?: continue
+ val endTime = hoursV[bottomInt]?.first ?: continue
+
+ noLessonDays.remove(lessonDate)
+
+ var typeName: String? = null
+ var subjectName: String? = null
+ var teacherName: String? = null
+ var classroomName: String? = null
+ var teamName: String? = null
+ val items = (cleanup(match[3]) + cleanup(match[4])).toMutableList()
+
+ var length = 0
+ while (items.isNotEmpty() && length != items.size) {
+ length = items.size
+ val toRemove = mutableListOf()
+ items.forEachIndexed { i, item ->
+ when {
+ item.isEmpty() ->
+ toRemove.add(item)
+ item.contains(":") && item.contains(" - ") ->
+ toRemove.add(item)
+
+ item.startsWith("%") -> {
+ subjectName = item.trim('%')
+ toRemove.add(item)
+ toRemove.add(items[0])
+ }
+
+ item.startsWith("&") -> {
+ typeName = item.trim('&')
+ toRemove.add(item)
+ }
+ typeName != null && (item.contains(typeName!!) || item.contains("")) -> {
+ toRemove.add(item)
+ }
+
+ item.contains("(") && item.contains(")") -> {
+ classroomName = classroomRegex.find(item)?.get(1)
+ items[i] = item.replace("($classroomName)", "").trim()
+ }
+ classroomName != null && item.contains(classroomName!!) -> {
+ items[i] = item.replace("($classroomName)", "").trim()
+ }
+
+ item.contains("class=\"wyjatek tooltip\"") ->
+ toRemove.add(item)
+ }
+ }
+ items.removeAll(toRemove)
+ }
+
+ if (items.size == 2 && items[0].contains(" - ")) {
+ val parts = items[0].split(" - ")
+ teamName = parts[0]
+ teacherName = parts[1]
+ }
+ else if (items.size == 2 && typeName?.contains("odwołana") == true) {
+ teamName = items[0]
+ }
+ else if (items.size == 4) {
+ teamName = items[0]
+ teacherName = items[1]
+ }
+
+ val type = when (typeName) {
+ "zastępstwo" -> Lesson.TYPE_CHANGE
+ "lekcja odwołana", "odwołana" -> Lesson.TYPE_CANCELLED
+ else -> Lesson.TYPE_NORMAL
+ }
+ val subject = subjectName?.let { data.getSubject(null, it) }
+ val teacher = teacherName?.let { data.getTeacherByLastFirst(it) }
+ val team = teamName?.let { data.getTeam(
+ id = null,
+ name = it,
+ schoolCode = data.loginServerName ?: return@let null,
+ isTeamClass = false
+ ) }
+
+ Lesson(data.profileId, -1).also {
+ it.type = type
+ if (type == Lesson.TYPE_CANCELLED) {
+ it.oldDate = lessonDate
+ it.oldLessonNumber = lessonNumber
+ it.oldStartTime = startTime
+ it.oldEndTime = endTime
+ it.oldSubjectId = subject?.id ?: -1
+ it.oldTeamId = team?.id ?: -1
+ }
+ else {
+ it.date = lessonDate
+ it.lessonNumber = lessonNumber
+ it.startTime = startTime
+ it.endTime = endTime
+ it.subjectId = subject?.id ?: -1
+ it.teacherId = teacher?.id ?: -1
+ it.teamId = team?.id ?: -1
+ it.classroom = classroomName
+ }
+
+ it.id = it.buildId()
+
+ val seen = profile?.empty == false || lessonDate < Date.getToday()
+
+ if (it.type != Lesson.TYPE_NORMAL) {
+ data.metadataList.add(
+ Metadata(
+ data.profileId,
+ Metadata.TYPE_LESSON_CHANGE,
+ it.id,
+ seen,
+ seen
+ )
+ )
+ }
+ data.lessonList += it
+ }
+ }
+
+ for (date in noLessonDays) {
+ data.lessonList += Lesson(data.profileId, date.value.toLong()).also {
+ it.type = Lesson.TYPE_NO_LESSONS
+ it.date = date
+ }
+ }
+ }
+}
+
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/DataPodlasie.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/DataPodlasie.kt
index d117c139..7962de7e 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/DataPodlasie.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/DataPodlasie.kt
@@ -81,39 +81,4 @@ class DataPodlasie(app: App, profile: Profile?, loginStore: LoginStore) : Data(a
val loginShort: String?
get() = studentLogin?.split('@')?.get(0)
-
- fun getSubject(name: String): Subject {
- val id = name.crc32()
- return subjectList.singleOrNull { it.id == id } ?: run {
- val subject = Subject(profileId, id, name, name)
- subjectList.put(id, subject)
- subject
- }
- }
-
- fun getTeacher(firstName: String, lastName: String): Teacher {
- val name = "$firstName $lastName".fixName()
- return teacherList.singleOrNull { it.fullName == name } ?: run {
- val id = name.crc32()
- val teacher = Teacher(profileId, id, firstName, lastName)
- teacherList.put(id, teacher)
- teacher
- }
- }
-
- fun getTeam(name: String? = null): Team {
- if (name == "cała klasa" || name == null) return teamClass ?: run {
- val id = className!!.crc32()
- val teamCode = "$schoolShortName:$className"
- val team = Team(profileId, id, className, Team.TYPE_CLASS, teamCode, -1)
- teamList.put(id, team)
- return team
- } else {
- val id = name.crc32()
- val teamCode = "$schoolShortName:$name"
- val team = Team(profileId, id, name, Team.TYPE_VIRTUAL, teamCode, -1)
- teamList.put(id, team)
- return team
- }
- }
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiFinalGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiFinalGrades.kt
index 7c4575aa..bb4f696c 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiFinalGrades.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiFinalGrades.kt
@@ -36,7 +36,7 @@ class PodlasieApiFinalGrades(val data: DataPodlasie, val rows: List)
}
val subjectName = grade.getString("SchoolSubject") ?: return@forEach
- val subject = data.getSubject(subjectName)
+ val subject = data.getSubject(null, subjectName)
val addedDate = if (profile.empty) profile.getSemesterStart(semester).inMillis
else System.currentTimeMillis()
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiGrades.kt
index d5696567..c3946c76 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiGrades.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiGrades.kt
@@ -34,7 +34,7 @@ class PodlasieApiGrades(val data: DataPodlasie, val rows: List) {
val teacher = data.getTeacher(teacherFirstName, teacherLastName)
val subjectName = grade.getString("SchoolSubject") ?: return@forEach
- val subject = data.getSubject(subjectName)
+ val subject = data.getSubject(null, subjectName)
val addedDate = grade.getString("ReceivedDate")?.let { Date.fromY_m_d(it).inMillis }
?: System.currentTimeMillis()
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiMain.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiMain.kt
index 6fe77b5c..f108d35e 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiMain.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiMain.kt
@@ -22,7 +22,13 @@ class PodlasieApiMain(override val data: DataPodlasie,
init {
apiGet(TAG, PODLASIE_API_USER_ENDPOINT) { json ->
- data.getTeam() // Save the class team when it doesn't exist.
+ // Save the class team when it doesn't exist.
+ data.getTeam(
+ id = null,
+ name = data.className ?: "",
+ schoolCode = data.schoolShortName ?: "",
+ isTeamClass = true
+ )
json.getInt("LuckyNumber")?.let { PodlasieApiLuckyNumber(data, it) }
json.getJsonArray("Teacher")?.asJsonObjectList()?.let { PodlasieApiTeachers(data, it) }
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiTimetable.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiTimetable.kt
index a9a12d5d..13cff861 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiTimetable.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/podlasie/data/api/PodlasieApiTimetable.kt
@@ -43,14 +43,21 @@ class PodlasieApiTimetable(val data: DataPodlasie, rows: List) {
val startTime = lesson.getString("TimeFrom")?.let { Time.fromH_m_s(it) }
?: return@forEach
val endTime = lesson.getString("TimeTo")?.let { Time.fromH_m_s(it) } ?: return@forEach
- val subject = lesson.getString("SchoolSubject")?.let { data.getSubject(it) }
+ val subject = lesson.getString("SchoolSubject")?.let { data.getSubject(null, it) }
?: return@forEach
val teacherFirstName = lesson.getString("TeacherFirstName") ?: return@forEach
val teacherLastName = lesson.getString("TeacherLastName") ?: return@forEach
val teacher = data.getTeacher(teacherFirstName, teacherLastName)
- val team = lesson.getString("Group")?.let { data.getTeam(it) } ?: return@forEach
+ val team = lesson.getString("Group")?.let {
+ data.getTeam(
+ id = null,
+ name = it,
+ schoolCode = data.schoolShortName ?: "",
+ isTeamClass = it == "cała klasa"
+ )
+ } ?: return@forEach
val classroom = lesson.getString("Room")
Lesson(data.profileId, -1).also {
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/Data.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/Data.kt
index 8dda9543..2b7bdf1a 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/Data.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/models/Data.kt
@@ -2,6 +2,7 @@ package pl.szczodrzynski.edziennik.data.api.models
import android.util.LongSparseArray
import android.util.SparseArray
+import androidx.core.util.set
import androidx.core.util.size
import androidx.room.OnConflictStrategy
import com.google.gson.JsonObject
@@ -376,4 +377,108 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
fun startProgress(stringRes: Int) {
callback.onStartProgress(stringRes)
}
+
+ /* _ _ _ _ _
+ | | | | | (_) |
+ | | | | |_ _| |___
+ | | | | __| | / __|
+ | |__| | |_| | \__ \
+ \____/ \__|_|_|__*/
+ fun getSubject(id: Long?, name: String, shortName: String = name): Subject {
+ var subject = subjectList.singleOrNull { it.id == id }
+ if (subject == null)
+ subject = subjectList.singleOrNull { it.longName == name }
+ if (subject == null)
+ subject = subjectList.singleOrNull { it.shortName == name }
+
+ if (subject == null) {
+ subject = Subject(
+ profileId,
+ id ?: name.crc32(),
+ name,
+ shortName
+ )
+ subjectList[subject.id] = subject
+ }
+ return subject
+ }
+
+ fun getTeam(id: Long?, name: String, schoolCode: String, isTeamClass: Boolean = false): Team {
+ if (isTeamClass && teamClass != null)
+ return teamClass as Team
+ var team = teamList.singleOrNull { it.id == id }
+
+ val namePlain = name.replace(" ", "")
+ if (team == null)
+ team = teamList.singleOrNull { it.name.replace(" ", "") == namePlain }
+
+ if (team == null) {
+ team = Team(
+ profileId,
+ id ?: name.crc32(),
+ name,
+ if (isTeamClass) Team.TYPE_CLASS else Team.TYPE_VIRTUAL,
+ "$schoolCode:$name",
+ -1
+ )
+ teamList[team.id] = team
+ }
+ return team
+ }
+
+ fun getTeacher(firstName: String, lastName: String, loginId: String? = null): Teacher {
+ val teacher = teacherList.singleOrNull { it.fullName == "$firstName $lastName" }
+ return validateTeacher(teacher, firstName, lastName, loginId)
+ }
+
+ fun getTeacher(firstNameChar: Char, lastName: String, loginId: String? = null): Teacher {
+ val teacher = teacherList.singleOrNull { it.shortName == "$firstNameChar.$lastName" }
+ return validateTeacher(teacher, firstNameChar.toString(), lastName, loginId)
+ }
+
+ fun getTeacherByLastFirst(nameLastFirst: String, loginId: String? = null): Teacher {
+ val nameParts = nameLastFirst.split(" ")
+ return if (nameParts.size == 1)
+ getTeacher(nameParts[0], "", loginId)
+ else
+ getTeacher(nameParts[1], nameParts[0], loginId)
+ }
+
+ fun getTeacherByFirstLast(nameFirstLast: String, loginId: String? = null): Teacher {
+ val nameParts = nameFirstLast.split(" ")
+ return if (nameParts.size == 1)
+ getTeacher(nameParts[0], "", loginId)
+ else
+ getTeacher(nameParts[0], nameParts[1], loginId)
+ }
+
+ fun getTeacherByFDotLast(nameFDotLast: String, loginId: String? = null): Teacher {
+ val nameParts = nameFDotLast.split(".")
+ return if (nameParts.size == 1)
+ getTeacher(nameParts[0], "", loginId)
+ else
+ getTeacher(nameParts[0][0], nameParts[1], loginId)
+ }
+
+ fun getTeacherByFDotSpaceLast(nameFDotSpaceLast: String, loginId: String? = null): Teacher {
+ val nameParts = nameFDotSpaceLast.split(".")
+ return if (nameParts.size == 1)
+ getTeacher(nameParts[0], "", loginId)
+ else
+ getTeacher(nameParts[0][0], nameParts[1], loginId)
+ }
+
+ private fun validateTeacher(teacher: Teacher?, firstName: String, lastName: String, loginId: String?): Teacher {
+ val obj = teacher ?: Teacher(profileId, -1, firstName, lastName, loginId).apply {
+ id = fullName.crc32()
+ teacherList[id] = this
+ }
+ return obj.also {
+ if (loginId != null && it.loginId != null)
+ it.loginId = loginId
+ if (firstName.length > 1)
+ it.name = firstName
+ it.surname = lastName
+ }
+ }
}