mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2025-01-31 05:48:19 +01:00
[Timetable] Implement Librus timetable with lesson changes and shifts. Update UI.
This commit is contained in:
parent
5fa7409317
commit
4eeaa54a47
@ -390,5 +390,5 @@ fun List<CharSequence>.concat(delimiter: String? = null): CharSequence {
|
||||
}
|
||||
|
||||
fun TextView.setText(@StringRes resid: Int, vararg formatArgs: Any) {
|
||||
text = context.getString(resid, formatArgs)
|
||||
text = context.getString(resid, *formatArgs)
|
||||
}
|
@ -80,6 +80,7 @@ class LibrusData(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_timetable)
|
||||
LibrusApiTimetables(data, onSuccess)
|
||||
}
|
||||
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GRADES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grades)
|
||||
LibrusApiGrades(data, onSuccess)
|
||||
|
@ -1,14 +1,16 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-11-10
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-11-10.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_TIMETABLES
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
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.timetable.Lesson
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
@ -21,34 +23,15 @@ class LibrusApiTimetables(override val data: DataLibrus,
|
||||
|
||||
init {
|
||||
apiGet(TAG, "Timetables") { json ->
|
||||
json.getJsonObject("Timetable")?.also { timetables ->
|
||||
timetables.keySet().forEach { dateStr ->
|
||||
val date = Date.fromY_m_d(dateStr)
|
||||
val days = json.getJsonObject("Timetable")
|
||||
|
||||
timetables.getJsonArray(dateStr)?.asJsonObjectList()?.forEach { lesson ->
|
||||
val lessonNumber = lesson.getInt("LessonNo")
|
||||
val startTime = lesson.getString("HourFrom")?.let { Time.fromH_m(it) }
|
||||
val endTime = lesson.getString("HourTo")?.let { Time.fromH_m(it) }
|
||||
val teacherId = lesson.getJsonObject("Teacher")?.getLong("Id")
|
||||
val subjectId = lesson.getJsonObject("Subject")?.getLong("Id")
|
||||
val classId = lesson.getJsonObject("Class")?.getLong("Id")
|
||||
val virtualClassId = lesson.getJsonObject("VirtualClass")?.getLong("Id")
|
||||
val teamId = virtualClassId ?: classId
|
||||
val classroomId = lesson.getJsonObject("Classroom")?.getLong("Id")
|
||||
val classroom = data.classrooms.singleOrNull { it.id == classroomId }?.name
|
||||
|
||||
val lessonObject = Lesson(profileId).apply {
|
||||
this.date = date
|
||||
this.lessonNumber = lessonNumber
|
||||
this.startTime = startTime
|
||||
this.endTime = endTime
|
||||
this.teacherId = teacherId
|
||||
this.subjectId = subjectId
|
||||
this.teamId = teamId
|
||||
this.classroom = classroom
|
||||
}
|
||||
|
||||
// TODO add to the database
|
||||
days?.entrySet()?.forEach { (dateString, dayEl) ->
|
||||
val lessonDate = dateString?.let { Date.fromY_m_d(it) } ?: return@forEach
|
||||
val day = dayEl?.asJsonArray
|
||||
day?.forEach { lessonRangeEl ->
|
||||
val lessonRange = lessonRangeEl?.asJsonArray?.asJsonObjectList()
|
||||
lessonRange?.forEachIndexed { index, lesson ->
|
||||
parseLesson(lessonDate, lesson)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -57,4 +40,126 @@ class LibrusApiTimetables(override val data: DataLibrus,
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseLesson(lessonDate: Date, lesson: JsonObject) {
|
||||
val lessonObject = Lesson(profileId, lesson.hashCode().toLong())
|
||||
|
||||
val isSubstitution = lesson.getBoolean("IsSubstitutionClass") ?: false
|
||||
val isCancelled = lesson.getBoolean("IsCanceled") ?: false
|
||||
|
||||
val lessonNo = lesson.getInt("LessonNo") ?: return
|
||||
val startTime = lesson.getString("HourFrom")?.let { Time.fromH_m(it) } ?: return
|
||||
val endTime = lesson.getString("HourTo")?.let { Time.fromH_m(it) } ?: return
|
||||
val subjectId = lesson.getJsonObject("Subject")?.getLong("Id")
|
||||
val teacherId = lesson.getJsonObject("Teacher")?.getLong("Id")
|
||||
val classroomId = lesson.getJsonObject("Classroom")?.getLong("Id") ?: -1
|
||||
val virtualClassId = lesson.getJsonObject("VirtualClass")?.getLong("Id")
|
||||
val teamId = lesson.getJsonObject("Class")?.getLong("Id") ?: virtualClassId
|
||||
|
||||
if (isSubstitution && isCancelled) {
|
||||
// shifted lesson - source
|
||||
val newDate = lesson.getString("NewDate")?.let { Date.fromY_m_d(it) } ?: return
|
||||
val newLessonNo = lesson.getInt("NewLessonNo") ?: return
|
||||
val newStartTime = lesson.getString("NewHourFrom")?.let { Time.fromH_m(it) } ?: return
|
||||
val newEndTime = lesson.getString("NewHourTo")?.let { Time.fromH_m(it) } ?: return
|
||||
val newSubjectId = lesson.getJsonObject("NewSubject")?.getLong("Id")
|
||||
val newTeacherId = lesson.getJsonObject("NewTeacher")?.getLong("Id")
|
||||
val newClassroomId = lesson.getJsonObject("NewClassroom")?.getLong("Id") ?: -1
|
||||
val newVirtualClassId = lesson.getJsonObject("NewVirtualClass")?.getLong("Id")
|
||||
val newTeamId = lesson.getJsonObject("NewClass")?.getLong("Id") ?: newVirtualClassId
|
||||
|
||||
lessonObject.let {
|
||||
it.type = Lesson.TYPE_SHIFTED_SOURCE
|
||||
it.oldDate = lessonDate
|
||||
it.oldLessonNumber = lessonNo
|
||||
it.oldStartTime = startTime
|
||||
it.oldEndTime = endTime
|
||||
it.oldSubjectId = subjectId
|
||||
it.oldTeacherId = teacherId
|
||||
it.oldTeamId = teamId
|
||||
it.oldClassroom = data.classrooms[classroomId]?.name
|
||||
|
||||
it.date = newDate
|
||||
it.lessonNumber = newLessonNo
|
||||
it.startTime = newStartTime
|
||||
it.endTime = newEndTime
|
||||
it.subjectId = newSubjectId
|
||||
it.teacherId = newTeacherId
|
||||
it.teamId = newTeamId
|
||||
it.classroom = data.classrooms[newClassroomId]?.name
|
||||
}
|
||||
}
|
||||
else if (isSubstitution) {
|
||||
// lesson change OR shifted lesson - target
|
||||
val oldDate = lesson.getString("OrgDate")?.let { Date.fromY_m_d(it) } ?: return
|
||||
val oldLessonNo = lesson.getInt("OrgLessonNo") ?: return
|
||||
val oldStartTime = lesson.getString("OrgHourFrom")?.let { Time.fromH_m(it) } ?: return
|
||||
val oldEndTime = lesson.getString("OrgHourTo")?.let { Time.fromH_m(it) } ?: return
|
||||
val oldSubjectId = lesson.getJsonObject("OrgSubject")?.getLong("Id")
|
||||
val oldTeacherId = lesson.getJsonObject("OrgTeacher")?.getLong("Id")
|
||||
val oldClassroomId = lesson.getJsonObject("OrgClassroom")?.getLong("Id") ?: -1
|
||||
val oldVirtualClassId = lesson.getJsonObject("OrgVirtualClass")?.getLong("Id")
|
||||
val oldTeamId = lesson.getJsonObject("OrgClass")?.getLong("Id") ?: oldVirtualClassId
|
||||
|
||||
lessonObject.let {
|
||||
it.type = if (lessonDate == oldDate && lessonNo == oldLessonNo) Lesson.TYPE_CHANGE else Lesson.TYPE_SHIFTED_TARGET
|
||||
it.oldDate = oldDate
|
||||
it.oldLessonNumber = oldLessonNo
|
||||
it.oldStartTime = oldStartTime
|
||||
it.oldEndTime = oldEndTime
|
||||
it.oldSubjectId = oldSubjectId
|
||||
it.oldTeacherId = oldTeacherId
|
||||
it.oldTeamId = oldTeamId
|
||||
it.oldClassroom = data.classrooms[oldClassroomId]?.name
|
||||
|
||||
it.date = lessonDate
|
||||
it.lessonNumber = lessonNo
|
||||
it.startTime = startTime
|
||||
it.endTime = endTime
|
||||
it.subjectId = subjectId
|
||||
it.teacherId = teacherId
|
||||
it.teamId = teamId
|
||||
it.classroom = data.classrooms[classroomId]?.name
|
||||
}
|
||||
}
|
||||
else if (isCancelled) {
|
||||
lessonObject.let {
|
||||
it.type = Lesson.TYPE_CANCELLED
|
||||
it.oldDate = lessonDate
|
||||
it.oldLessonNumber = lessonNo
|
||||
it.oldStartTime = startTime
|
||||
it.oldEndTime = endTime
|
||||
it.oldSubjectId = subjectId
|
||||
it.oldTeacherId = teacherId
|
||||
it.oldTeamId = teamId
|
||||
it.oldClassroom = data.classrooms[classroomId]?.name
|
||||
}
|
||||
}
|
||||
else {
|
||||
lessonObject.let {
|
||||
it.type = Lesson.TYPE_NORMAL
|
||||
it.date = lessonDate
|
||||
it.lessonNumber = lessonNo
|
||||
it.startTime = startTime
|
||||
it.endTime = endTime
|
||||
it.subjectId = subjectId
|
||||
it.teacherId = teacherId
|
||||
it.teamId = teamId
|
||||
it.classroom = data.classrooms[classroomId]?.name
|
||||
}
|
||||
}
|
||||
|
||||
if (lessonObject.type != Lesson.TYPE_NORMAL) {
|
||||
data.metadataList.add(
|
||||
Metadata(
|
||||
data.profileId,
|
||||
Metadata.TYPE_LESSON_CHANGE,
|
||||
lessonObject.id,
|
||||
data.profile?.empty ?: false,
|
||||
data.profile?.empty ?: false,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
data.lessonNewList += lessonObject
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,12 @@ class LessonFull(profileId: Int, id: Long) : Lesson(profileId, id) {
|
||||
return oldDate
|
||||
return date ?: oldDate
|
||||
}
|
||||
val displayLessonNumber: Int?
|
||||
get() {
|
||||
if (type == TYPE_SHIFTED_SOURCE)
|
||||
return oldLessonNumber
|
||||
return lessonNumber ?: oldLessonNumber
|
||||
}
|
||||
val displayStartTime: Time?
|
||||
get() {
|
||||
if (type == TYPE_SHIFTED_SOURCE)
|
||||
|
@ -35,7 +35,8 @@ interface TimetableDao {
|
||||
LEFT JOIN teachers AS oldT ON timetable.profileId = oldT.profileId AND timetable.oldTeacherId = oldT.teacherId
|
||||
LEFT JOIN teams AS oldG ON timetable.profileId = oldG.profileId AND timetable.oldTeamId = oldG.teamId
|
||||
LEFT JOIN metadata ON id = thingId AND thingType = ${Metadata.TYPE_LESSON_CHANGE} AND metadata.profileId = timetable.profileId
|
||||
WHERE timetable.profileId = :profileId AND (type != 3 AND date = :date) OR (type = 3 AND oldDate = :date)
|
||||
WHERE timetable.profileId = :profileId AND (type != 3 AND date = :date) OR ((type = 3 OR type = 1) AND oldDate = :date)
|
||||
ORDER BY type
|
||||
""")
|
||||
fun getForDate(profileId: Int, date: Date) : LiveData<List<LessonFull>>
|
||||
}
|
||||
|
@ -122,7 +122,13 @@ class TimetableDayFragment(val date: Date) : Fragment() {
|
||||
}.concat(arrowRight)
|
||||
|
||||
|
||||
lb.subjectName.text = lesson.displaySubjectName?.let { if (lesson.type == Lesson.TYPE_CANCELLED) it.asStrikethroughSpannable().asColoredSpannable(colorSecondary) else it }
|
||||
lb.lessonNumber = lesson.displayLessonNumber
|
||||
lb.subjectName.text = lesson.displaySubjectName?.let {
|
||||
if (lesson.type == Lesson.TYPE_CANCELLED || lesson.type == Lesson.TYPE_SHIFTED_SOURCE)
|
||||
it.asStrikethroughSpannable().asColoredSpannable(colorSecondary)
|
||||
else
|
||||
it
|
||||
}
|
||||
lb.detailsFirst.text = listOfNotEmpty(timeRange, classroomInfo).concat(bullet)
|
||||
lb.detailsSecond.text = listOfNotEmpty(teacherInfo, teamInfo).concat(bullet)
|
||||
|
||||
@ -165,7 +171,55 @@ class TimetableDayFragment(val date: Date) : Fragment() {
|
||||
}
|
||||
|
||||
lb.annotation.background.colorFilter = PorterDuffColorFilter(
|
||||
getColorFromAttr(activity, R.attr.timetable_lesson_cancelled_color),
|
||||
getColorFromAttr(activity, R.attr.timetable_lesson_change_color),
|
||||
PorterDuff.Mode.SRC_ATOP
|
||||
)
|
||||
}
|
||||
Lesson.TYPE_SHIFTED_SOURCE -> {
|
||||
lb.annotationVisible = true
|
||||
if (lesson.date != lesson.oldDate) {
|
||||
lb.annotation.setText(
|
||||
R.string.timetable_lesson_shifted_other_day,
|
||||
lesson.date?.stringY_m_d ?: "?",
|
||||
lesson.startTime?.stringHM ?: "?"
|
||||
)
|
||||
}
|
||||
else if (lesson.startTime != lesson.oldStartTime) {
|
||||
lb.annotation.setText(
|
||||
R.string.timetable_lesson_shifted_same_day,
|
||||
lesson.startTime?.stringHM ?: "?"
|
||||
)
|
||||
}
|
||||
else {
|
||||
lb.annotation.setText(R.string.timetable_lesson_shifted)
|
||||
}
|
||||
|
||||
lb.annotation.background.colorFilter = PorterDuffColorFilter(
|
||||
getColorFromAttr(activity, R.attr.timetable_lesson_shifted_source_color),
|
||||
PorterDuff.Mode.SRC_ATOP
|
||||
)
|
||||
}
|
||||
Lesson.TYPE_SHIFTED_TARGET -> {
|
||||
lb.annotationVisible = true
|
||||
if (lesson.date != lesson.oldDate) {
|
||||
lb.annotation.setText(
|
||||
R.string.timetable_lesson_shifted_from_other_day,
|
||||
lesson.oldDate?.stringY_m_d ?: "?",
|
||||
lesson.oldStartTime?.stringHM ?: "?"
|
||||
)
|
||||
}
|
||||
else if (lesson.startTime != lesson.oldStartTime) {
|
||||
lb.annotation.setText(
|
||||
R.string.timetable_lesson_shifted_from_same_day,
|
||||
lesson.oldStartTime?.stringHM ?: "?"
|
||||
)
|
||||
}
|
||||
else {
|
||||
lb.annotation.setText(R.string.timetable_lesson_shifted_from)
|
||||
}
|
||||
|
||||
lb.annotation.background.colorFilter = PorterDuffColorFilter(
|
||||
getColorFromAttr(activity, R.attr.timetable_lesson_shifted_target_color),
|
||||
PorterDuff.Mode.SRC_ATOP
|
||||
)
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package pl.szczodrzynski.edziennik.utils.models;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.Calendar;
|
||||
@ -218,6 +219,11 @@ public class Date implements Comparable<Date> {
|
||||
return this.getValue() - o.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
return obj instanceof Date && this.getValue() == ((Date) obj).getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Date{" +
|
||||
|
@ -1,5 +1,7 @@
|
||||
package pl.szczodrzynski.edziennik.utils.models;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
public class Time {
|
||||
@ -173,6 +175,11 @@ public class Time {
|
||||
return (currentTime.getValue() >= startTime.getValue() && currentTime.getValue() <= endTime.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
return obj instanceof Time && this.getValue() == ((Time) obj).getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Time{" +
|
||||
|
@ -8,6 +8,9 @@
|
||||
<variable
|
||||
name="annotationVisible"
|
||||
type="boolean"/>
|
||||
<variable
|
||||
name="lessonNumber"
|
||||
type="Integer" />
|
||||
</data>
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
@ -91,11 +94,13 @@
|
||||
android:layout_gravity="center_vertical"
|
||||
android:fontFamily="sans-serif-condensed-light"
|
||||
android:includeFontPadding="false"
|
||||
|
||||
android:layout_marginBottom="-4dp"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:text="9"
|
||||
tools:textSize="28sp"/>
|
||||
android:text="@{Integer.toString(lessonNumber)}"
|
||||
android:textSize="28sp"
|
||||
android:visibility="@{lessonNumber != null ? View.VISIBLE : View.GONE}"
|
||||
tools:text="3"/>
|
||||
<!--android:layout_marginTop="@{annotationVisible ? `-4dp` : `4dp`}"
|
||||
android:layout_marginBottom="@{annotationVisible ? `-4dp` : `0dp`}"-->
|
||||
|
||||
|
@ -6,5 +6,6 @@
|
||||
<attr name="timetable_lesson_bg" format="reference" />
|
||||
<attr name="timetable_lesson_cancelled_color" format="color" />
|
||||
<attr name="timetable_lesson_change_color" format="color" />
|
||||
<attr name="timetable_lesson_shifted_color" format="color" />
|
||||
<attr name="timetable_lesson_shifted_source_color" format="color" />
|
||||
<attr name="timetable_lesson_shifted_target_color" format="color" />
|
||||
</resources>
|
@ -991,4 +991,8 @@
|
||||
<string name="timetable_lesson_change_format">Zastępstwo: zamiast %s</string>
|
||||
<string name="timetable_lesson_shifted_same_day">Lekcja przeniesiona na godz. %s</string>
|
||||
<string name="timetable_lesson_shifted_other_day">Lekcja przeniesiona na %s, godz. %s</string>
|
||||
<string name="timetable_lesson_shifted_from_same_day">Lekcja przeniesiona z godz. %s</string>
|
||||
<string name="timetable_lesson_shifted_from_other_day">Lekcja przeniesiona z dnia %s, godz. %s</string>
|
||||
<string name="timetable_lesson_shifted">Lekcja przeniesiona na inny termin</string>
|
||||
<string name="timetable_lesson_shifted_from">Lekcja przeniesiona z innego terminu</string>
|
||||
</resources>
|
||||
|
@ -99,7 +99,8 @@
|
||||
<item name="timetable_lesson_bg">@drawable/timetable_lesson_bg_light</item>
|
||||
<item name="timetable_lesson_cancelled_color">#9f9f9f</item>
|
||||
<item name="timetable_lesson_change_color">#ffb300</item>
|
||||
<item name="timetable_lesson_shifted_color">#4caf50</item>
|
||||
<item name="timetable_lesson_shifted_source_color">#A1887F</item>
|
||||
<item name="timetable_lesson_shifted_target_color">#4caf50</item>
|
||||
</style>
|
||||
<style name="AppTheme.Dark" parent="NavView.Dark">
|
||||
<item name="colorPrimary">#64b5f6</item>
|
||||
@ -128,7 +129,8 @@
|
||||
<item name="timetable_lesson_bg">@drawable/timetable_lesson_bg_dark</item>
|
||||
<item name="timetable_lesson_cancelled_color">#838383</item>
|
||||
<item name="timetable_lesson_change_color">#ffb300</item>
|
||||
<item name="timetable_lesson_shifted_color">#4caf50</item>
|
||||
<item name="timetable_lesson_shifted_source_color">#A1887F</item>
|
||||
<item name="timetable_lesson_shifted_target_color">#4caf50</item>
|
||||
</style>
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user