diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Regexes.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Regexes.kt index 532d021b..e6025f9d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Regexes.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Regexes.kt @@ -60,4 +60,8 @@ object Regexes { val IDZIENNIK_LOGIN_FIRST_STUDENT by lazy { """(.+?)\s(.+?)\s*\((.+?),\s*(.+?)\)""".toRegex(RegexOption.DOT_MATCHES_ALL) } + + val VULCAN_SHITFT_ANNOTATION by lazy { + """\(przeniesiona (z|na) lekcj[ię] ([0-9]+), (.+)\)""".toRegex() + } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/data/api/LibrusApiTimetables.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/data/api/LibrusApiTimetables.kt index 9b49190c..15865a2f 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/data/api/LibrusApiTimetables.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/data/api/LibrusApiTimetables.kt @@ -44,16 +44,16 @@ class LibrusApiTimetables(override val data: DataLibrus, val lessonRange = lessonRangeEl?.asJsonArray?.asJsonObjectList() if (lessonRange?.isNullOrEmpty() == false) lessonsFound = true - lessonRange?.forEachIndexed { index, lesson -> + lessonRange?.forEach { lesson -> parseLesson(lessonDate, lesson) } } if (day.isNullOrEmpty() || !lessonsFound) { - data.lessonNewList += Lesson(profileId, lessonDate.value.toLong()).apply { + data.lessonNewList.add(Lesson(profileId, lessonDate.value.toLong()).apply { type = Lesson.TYPE_NO_LESSONS date = lessonDate - } + }) } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/VulcanData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/VulcanData.kt index 432a21d2..66936a65 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/VulcanData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/VulcanData.kt @@ -64,6 +64,10 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) { data.startProgress(R.string.edziennik_progress_endpoint_attendance) VulcanApiAttendance(data, onSuccess) } + ENDPOINT_VULCAN_API_TIMETABLE -> { + data.startProgress(R.string.edziennik_progress_endpoint_timetable) + VulcanApiTimetable(data, onSuccess) + } ENDPOINT_VULCAN_API_MESSAGES_INBOX -> { data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox) VulcanApiMessagesInbox(data, onSuccess) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/api/VulcanApiAttendance.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/api/VulcanApiAttendance.kt index 1722cfed..174eed18 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/api/VulcanApiAttendance.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/api/VulcanApiAttendance.kt @@ -55,7 +55,7 @@ class VulcanApiAttendance(override val data: DataVulcan, val onSuccess: () -> Un lessonSemester, attendance.getString("PrzedmiotNazwa") + attendanceCategory.name.let { " - $it" }, lessonDate, - data.lessonRanges.get(attendance.getInt("IdPoraLekcji") ?: 0)?.startTime, + data.lessonRanges.get(attendance.getInt("Numer") ?: 0)?.startTime, type) data.attendanceList.add(attendanceObject) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/api/VulcanApiDictionaries.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/api/VulcanApiDictionaries.kt index b4548d9d..376a13b1 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/api/VulcanApiDictionaries.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/api/VulcanApiDictionaries.kt @@ -35,7 +35,7 @@ class VulcanApiDictionaries(override val data: DataVulcan, val onSuccess: () -> elements?.getJsonArray("KategorieUwag")?.forEach { saveNoticeType(it.asJsonObject) } elements?.getJsonArray("KategorieFrekwencji")?.forEach { saveAttendanceType(it.asJsonObject) } - data.setSyncNext(ENDPOINT_VULCAN_API_DICTIONARIES, 4*DAY) + data.setSyncNext(ENDPOINT_VULCAN_API_DICTIONARIES, 4 * DAY) onSuccess() } } @@ -73,7 +73,7 @@ class VulcanApiDictionaries(override val data: DataVulcan, val onSuccess: () -> } private fun saveLessonRange(lessonRange: JsonObject) { - val lessonNumber = lessonRange.getInt("Id") ?: return + val lessonNumber = lessonRange.getInt("Numer") ?: return val startTime = lessonRange.getString("PoczatekTekst")?.let { Time.fromH_m(it) } ?: return val endTime = lessonRange.getString("KoniecTekst")?.let { Time.fromH_m(it) } ?: return @@ -126,8 +126,7 @@ class VulcanApiDictionaries(override val data: DataVulcan, val onSuccess: () -> Attendance.TYPE_ABSENT_EXCUSED else Attendance.TYPE_ABSENT - } - else { + } else { val belated = attendanceType.getBoolean("Spoznienie") ?: false val released = attendanceType.getBoolean("Zwolnienie") ?: false val present = attendanceType.getBoolean("Obecnosc") ?: true diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/api/VulcanApiTimetable.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/api/VulcanApiTimetable.kt new file mode 100644 index 00000000..a7a2c83e --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/vulcan/data/api/VulcanApiTimetable.kt @@ -0,0 +1,186 @@ +/* + * Copyright (c) Kacper Ziubryniewicz 2019-11-13 + */ + +package pl.szczodrzynski.edziennik.api.v2.vulcan.data.api + +import pl.szczodrzynski.edziennik.* +import pl.szczodrzynski.edziennik.api.v2.Regexes +import pl.szczodrzynski.edziennik.api.v2.VULCAN_API_ENDPOINT_TIMETABLE +import pl.szczodrzynski.edziennik.api.v2.models.DataRemoveModel +import pl.szczodrzynski.edziennik.api.v2.vulcan.DataVulcan +import pl.szczodrzynski.edziennik.api.v2.vulcan.ENDPOINT_VULCAN_API_TIMETABLE +import pl.szczodrzynski.edziennik.api.v2.vulcan.data.VulcanApi +import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata +import pl.szczodrzynski.edziennik.data.db.modules.subjects.Subject +import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson +import pl.szczodrzynski.edziennik.utils.Utils.crc16 +import pl.szczodrzynski.edziennik.utils.Utils.d +import pl.szczodrzynski.edziennik.utils.models.Date + +class VulcanApiTimetable(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) { + companion object { + const val TAG = "VulcanApiTimetable" + } + + init { + data.profile?.also { profile -> + val currentWeekStart = Date.getToday().let { it.stepForward(0, 0, -it.weekDay) } + val getDate = data.arguments?.getString("weekStart") ?: currentWeekStart.stringY_m_d + + val weekStart = Date.fromY_m_d(getDate) + val weekEnd = weekStart.clone().stepForward(0, 0, 6) + + apiGet(TAG, VULCAN_API_ENDPOINT_TIMETABLE, parameters = mapOf( + "DataPoczatkowa" to weekStart.stringY_m_d, + "DataKoncowa" to weekEnd.stringY_m_d, + "IdUczen" to data.studentId, + "IdOddzial" to data.studentClassId, + "IdOkresKlasyfikacyjny" to data.studentSemesterId + )) { json, _ -> + val dates: MutableSet = mutableSetOf() + val lessons: MutableList = mutableListOf() + + json.getJsonArray("Data")?.asJsonObjectList()?.forEach { lesson -> + val lessonDate = Date.fromY_m_d(lesson.getString("DzienTekst")) + val lessonNumber = lesson.getInt("NumerLekcji") + val lessonRange = data.lessonRanges.singleOrNull { it.lessonNumber == lessonNumber } + val startTime = lessonRange?.startTime + val endTime = lessonRange?.endTime + val teacherId = lesson.getLong("IdPracownik") + val teamId = data.studentClassId.toLong() + val classroom = lesson.getString("Classroom") + + val oldTeacherId = lesson.getLong("IdPracownikOld") + + val changeAnnotation = lesson.getString("AdnotacjaOZmianie") ?: "" + val type = when { + changeAnnotation.startsWith("(przeniesiona z") -> Lesson.TYPE_SHIFTED_TARGET + changeAnnotation.startsWith("(przeniesiona na") -> Lesson.TYPE_SHIFTED_SOURCE + changeAnnotation.startsWith("(zastępstwo") -> Lesson.TYPE_CHANGE + lesson.getBoolean("PrzekreslonaNazwa") == true -> Lesson.TYPE_CANCELLED + else -> Lesson.TYPE_NORMAL + } + + val subjectId = lesson.getLong("IdPrzedmiot")?.let { + when (it) { + 0L -> { + val subjectName = lesson.getString("PrzedmiotNazwa") ?: "" + + data.subjectList.singleOrNull { subject -> subject.longName == subjectName }?.id + ?: { + /** + * CREATE A NEW SUBJECT IF IT DOESN'T EXIST + */ + + val subjectObject = Subject( + profileId, + -1 * crc16(subjectName.toByteArray()).toLong(), + subjectName, + subjectName + ) + data.subjectList.put(subjectObject.id, subjectObject) + subjectObject.id + }.invoke() + } + else -> it + } + } + + val id = lessonDate.combineWith(startTime) / 6L * 10L + (lesson.hashCode() and 0xFFFF) + + val lessonObject = Lesson(profileId, id).apply { + this.type = type + + when (type) { + Lesson.TYPE_NORMAL, Lesson.TYPE_CHANGE, Lesson.TYPE_SHIFTED_TARGET -> { + this.date = lessonDate + this.lessonNumber = lessonNumber + this.startTime = startTime + this.endTime = endTime + this.subjectId = subjectId + this.teacherId = teacherId + this.teamId = teamId + this.classroom = classroom + + this.oldTeacherId = oldTeacherId + } + + Lesson.TYPE_CANCELLED, Lesson.TYPE_SHIFTED_SOURCE -> { + this.oldDate = lessonDate + this.oldLessonNumber = lessonNumber + this.oldStartTime = startTime + this.oldEndTime = endTime + this.oldSubjectId = subjectId + this.oldTeacherId = teacherId + this.oldTeamId = teamId + this.oldClassroom = classroom + } + } + + if (type == Lesson.TYPE_SHIFTED_SOURCE || type == Lesson.TYPE_SHIFTED_TARGET) { + val shift = Regexes.VULCAN_SHITFT_ANNOTATION.find(changeAnnotation) + val oldLessonNumber = shift?.get(2)?.toInt() + val oldLessonDate = shift?.get(3)?.let { Date.fromd_m_Y(it) } + + val oldLessonRange = data.lessonRanges.singleOrNull { it.lessonNumber == oldLessonNumber } + val oldStartTime = oldLessonRange?.startTime + val oldEndTime = oldLessonRange?.endTime + + when (type) { + Lesson.TYPE_SHIFTED_SOURCE -> { + this.lessonNumber = oldLessonNumber + this.date = oldLessonDate + this.startTime = oldStartTime + this.endTime = oldEndTime + } + + Lesson.TYPE_SHIFTED_TARGET -> { + this.oldLessonNumber = oldLessonNumber + this.oldDate = oldLessonDate + this.oldStartTime = oldStartTime + this.oldEndTime = oldEndTime + } + } + } + } + + if (type != Lesson.TYPE_NORMAL) { + data.metadataList.add(Metadata( + profileId, + Metadata.TYPE_LESSON_CHANGE, + id, + profile.empty, + profile.empty, + System.currentTimeMillis() + )) + } + + dates.add(lessonDate.value) + lessons.add(lessonObject) + } + + val date: Date = weekStart.clone() + while (date <= weekEnd) { + if (!dates.contains(date.value)) { + lessons.add(Lesson(profileId, date.value.toLong()).apply { + this.type = Lesson.TYPE_NO_LESSONS + this.date = date.clone() + }) + } + + date.stepForward(0, 0, 1) + } + + d(TAG, "Clearing lessons between ${weekStart.stringY_m_d} and ${weekEnd.stringY_m_d} - timetable downloaded for $getDate") + + data.lessonNewList.addAll(lessons) + data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd)) + + data.setSyncNext(ENDPOINT_VULCAN_API_TIMETABLE, SYNC_ALWAYS) + onSuccess() + } + } + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/Date.java b/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/Date.java index d0411da2..993d2068 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/Date.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/models/Date.java @@ -12,13 +12,11 @@ public class Date implements Comparable { public int month = 0; public int day = 0; - public Date() - { + public Date() { this(2000, 0, 0); } - public Date(int year, int month, int day) - { + public Date(int year, int month, int day) { this.year = year; this.month = month; this.day = day; @@ -43,14 +41,8 @@ public class Date implements Comparable { return new Date(this.year, this.month, this.day); } - public long combineWith(Time time) { - if (time == null) { - return getInMillis(); - } - Calendar c = Calendar.getInstance(); - c.set(this.year, this.month-1, this.day, time.hour, time.minute, time.second); - c.set(Calendar.MILLISECOND, 0); - return c.getTimeInMillis(); + public static Date fromYmd(String dateTime) { + return new Date(Integer.parseInt(dateTime.substring(0, 4)), Integer.parseInt(dateTime.substring(4, 6)), Integer.parseInt(dateTime.substring(6, 8))); } public static Date fromMillis(long millis) { @@ -67,9 +59,8 @@ public class Date implements Comparable { return Calendar.getInstance().getTimeInMillis(); } - public int getWeekDay() - { - return Week.getWeekDayFromDate(this); + public static Date fromY_m_d(String dateTime) { + return new Date(Integer.parseInt(dateTime.substring(0, 4)), Integer.parseInt(dateTime.substring(5, 7)), Integer.parseInt(dateTime.substring(8, 10))); } public long getInMillis() { @@ -83,142 +74,137 @@ public class Date implements Comparable { return getInMillis() / 1000; } - public Date stepForward(int years, int months, int days) - { + public static Date fromd_m_Y(String dateTime) { + return new Date(Integer.parseInt(dateTime.substring(6, 10)), Integer.parseInt(dateTime.substring(3, 5)), Integer.parseInt(dateTime.substring(0, 2))); + } + + public static long fromIso(String dateTime) { + return Date.fromY_m_d(dateTime).combineWith(new Time(Integer.parseInt(dateTime.substring(11, 13)), Integer.parseInt(dateTime.substring(14, 16)), Integer.parseInt(dateTime.substring(17, 19)))); + } + + public static long fromIsoHm(String dateTime) { + return Date.fromY_m_d(dateTime).combineWith(new Time(Integer.parseInt(dateTime.substring(11, 13)), Integer.parseInt(dateTime.substring(14, 16)), 0)); + } + + public static Date fromValue(int value) { + int year = value / 10000; + int month = (value - year * 10000) / 100; + int day = (value - year * 10000 - month * 100); + return new Date(year, month, day); + } + + public static Date getToday() { + Calendar cal = Calendar.getInstance(); + return new Date(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH)); + } + + public static int diffDays(Date d1, Date d2) { + return (int) ((d1.getInMillis() - d2.getInMillis()) / (24 * 60 * 60 * 1000)); + } + + public static boolean isToday(Date date) { + return equals(date, getToday()); + } + + public static boolean isToday(String dateStr) { + return equals(dateStr, getToday()); + } + + public static boolean equals(Date first, Date second) { + return (first.getValue() == second.getValue()); + } + + public static boolean equals(String first, Date second) { + return equals(new Date().parseFromYmd(first), second); + } + + public long combineWith(Time time) { + if (time == null) { + return getInMillis(); + } + Calendar c = Calendar.getInstance(); + c.set(this.year, this.month - 1, this.day, time.hour, time.minute, time.second); + c.set(Calendar.MILLISECOND, 0); + return c.getTimeInMillis(); + } + + public int getWeekDay() { + return Week.getWeekDayFromDate(this); + } + + public Date stepForward(int years, int months, int days) { Calendar c = Calendar.getInstance(); int newMonth = month + months; if (newMonth > 12) { newMonth = 1; years++; } - c.set(year+years, newMonth - 1, day); - c.setTimeInMillis(c.getTimeInMillis() + days*24*60*60*1000); + c.set(year + years, newMonth - 1, day); + c.setTimeInMillis(c.getTimeInMillis() + days * 24 * 60 * 60 * 1000); this.year = c.get(Calendar.YEAR); this.month = c.get(Calendar.MONTH) + 1; this.day = c.get(Calendar.DAY_OF_MONTH); return this; } - public Date parseFromYmd(String dateTime) - { + public Date parseFromYmd(String dateTime) { this.year = Integer.parseInt(dateTime.substring(0, 4)); this.month = Integer.parseInt(dateTime.substring(4, 6)); this.day = Integer.parseInt(dateTime.substring(6, 8)); return this; } - public static Date fromYmd(String dateTime) - { - return new Date(Integer.parseInt(dateTime.substring(0, 4)), Integer.parseInt(dateTime.substring(4, 6)), Integer.parseInt(dateTime.substring(6, 8))); - } - - public static Date fromY_m_d(String dateTime) - { - return new Date(Integer.parseInt(dateTime.substring(0, 4)), Integer.parseInt(dateTime.substring(5, 7)), Integer.parseInt(dateTime.substring(8, 10))); - } - - public static long fromIso(String dateTime) - { - return Date.fromY_m_d(dateTime).combineWith(new Time(Integer.parseInt(dateTime.substring(11, 13)), Integer.parseInt(dateTime.substring(14, 16)), Integer.parseInt(dateTime.substring(17, 19)))); - } - - public static long fromIsoHm(String dateTime) - { - return Date.fromY_m_d(dateTime).combineWith(new Time(Integer.parseInt(dateTime.substring(11, 13)), Integer.parseInt(dateTime.substring(14, 16)), 0)); - } - - public int getValue() - { + public int getValue() { return year * 10000 + month * 100 + day; } - public static Date fromValue(int value) { - int year = value / 10000; - int month = (value-year*10000) / 100; - int day = (value-year*10000-month*100); - return new Date(year, month, day); - } - - public String getStringValue() - { + public String getStringValue() { return Integer.toString(getValue()); } - public String getStringYmd() - { - return year +(month < 10 ? "0" : "")+ month +(day < 10 ? "0" : "")+ day; - } - - /** - * @return 2019-06-02 - */ - public String getStringY_m_d() - { - return year +(month < 10 ? "-0" : "-")+ month +(day < 10 ? "-0" : "-")+ day; - } - public String getStringDm() - { - return day +"."+(month < 10 ? "0" : "")+ month; - } - public String getStringDmy() - { - return day +"."+(month < 10 ? "0" : "")+ month +"."+ year; - } - - public String getFormattedString() - { - java.util.Date date = new java.util.Date(); - date.setTime(getInMillis()); - DateFormat format = DateFormat.getDateInstance(DateFormat.LONG, Locale.getDefault()); - if (year == Date.getToday().year) { - return format.format(date).replace(", "+year, "").replace(" "+year, ""); - } - else { - return format.format(date); - } - } - public String getFormattedStringShort() - { - java.util.Date date = new java.util.Date(); - date.setTime(getInMillis()); - DateFormat format = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault()); - if (year == Date.getToday().year) { - return format.format(date).replace(", "+year, "").replace(" "+year, ""); - } - else { - return format.format(date); - } - } - public boolean isLeap() { return ((year & 3) == 0) && ((year % 100) != 0 || (year % 400) == 0); } - public static Date getToday() - { - Calendar cal = Calendar.getInstance(); - return new Date(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH)+1, cal.get(Calendar.DAY_OF_MONTH)); + public String getStringYmd() { + return year + (month < 10 ? "0" : "") + month + (day < 10 ? "0" : "") + day; } - public static int diffDays(Date d1, Date d2) { - return (int)((d1.getInMillis() - d2.getInMillis()) / (24*60*60*1000)); + /** + * @return 2019-06-02 + */ + public String getStringY_m_d() { + return year + (month < 10 ? "-0" : "-") + month + (day < 10 ? "-0" : "-") + day; } - public static boolean isToday(Date date) - { - return equals(date, getToday()); + public String getStringDm() { + return day + "." + (month < 10 ? "0" : "") + month; } - public static boolean isToday(String dateStr) - { - return equals(dateStr, getToday()); + + public String getStringDmy() { + return day + "." + (month < 10 ? "0" : "") + month + "." + year; } - public static boolean equals(Date first, Date second) - { - return (first.getValue() == second.getValue()); + + public String getFormattedString() { + java.util.Date date = new java.util.Date(); + date.setTime(getInMillis()); + DateFormat format = DateFormat.getDateInstance(DateFormat.LONG, Locale.getDefault()); + if (year == Date.getToday().year) { + return format.format(date).replace(", " + year, "").replace(" " + year, ""); + } else { + return format.format(date); + } } - public static boolean equals(String first, Date second) - { - return equals(new Date().parseFromYmd(first), second); + + public String getFormattedStringShort() { + java.util.Date date = new java.util.Date(); + date.setTime(getInMillis()); + DateFormat format = DateFormat.getDateInstance(DateFormat.MEDIUM, Locale.getDefault()); + if (year == Date.getToday().year) { + return format.format(date).replace(", " + year, "").replace(" " + year, ""); + } else { + return format.format(date); + } } @Override