From 30a77f1a99aec1b82cde4fef81e7d6dc8040b128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Fri, 31 Jan 2025 23:10:07 +0100 Subject: [PATCH] [UI/Grades] Update views for university grades --- .../usos/data/api/UsosApiExamReports.kt | 4 +- .../edziennik/ui/grades/GradesAdapter.kt | 9 +- .../edziennik/ui/grades/GradesListFragment.kt | 37 ++++++- .../edziennik/ui/grades/models/GradesStats.kt | 4 + .../ui/grades/viewholder/StatsViewHolder.kt | 26 +++++ .../ui/grades/viewholder/SubjectViewHolder.kt | 43 +++++--- .../edziennik/utils/managers/GradesManager.kt | 2 + app/src/main/res/layout/grades_item_stats.xml | 101 ++++++++++++++++++ app/src/main/res/values/strings.xml | 5 + 9 files changed, 209 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiExamReports.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiExamReports.kt index 20fb52a2..8ad971db 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiExamReports.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/usos/data/api/UsosApiExamReports.kt @@ -153,7 +153,9 @@ class UsosApiExamReports( if (sessionNumber > 1) { val origId = examId * 10L + sessionNumber - 1 val grades = data.gradeList.filter { it.id == origId } - grades.firstOrNull()?.parentId = gradeObject.id + val improvedGrade = grades.firstOrNull() + improvedGrade?.parentId = gradeObject.id + improvedGrade?.weight = 0.0f gradeObject.isImprovement = true } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/GradesAdapter.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/GradesAdapter.kt index 05bb1da0..e91c2e83 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/GradesAdapter.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/GradesAdapter.kt @@ -134,6 +134,7 @@ class GradesAdapter( if (model.state == STATE_CLOSED) { val subItems = when { + model is GradesSubject && manager.isUniversity -> listOf() model is GradesSemester && model.grades.isEmpty() -> listOf(GradesEmpty()) model is GradesSemester && manager.hideImproved -> @@ -147,10 +148,12 @@ class GradesAdapter( if (notifyAdapter) notifyItemInserted(position) } - position++ model.state = STATE_OPENED - items.addAll(position, subItems.filterNotNull()) - if (notifyAdapter) notifyItemRangeInserted(position, subItems.size) + if (subItems.isNotEmpty()) { + position++ + items.addAll(position, subItems.filterNotNull()) + if (notifyAdapter) notifyItemRangeInserted(position, subItems.size) + } if (model is GradesSubject) { // auto expand first semester diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/GradesListFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/GradesListFragment.kt index 905abefd..6abe853c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/GradesListFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/GradesListFragment.kt @@ -258,8 +258,40 @@ class GradesListFragment : Fragment(), CoroutineScope { subject.lastAddedDate = max(subject.lastAddedDate, grade.addedDate) } + when (manager.orderBy) { + GradesManager.ORDER_BY_DATE_DESC -> items.sortByDescending { it.lastAddedDate } + GradesManager.ORDER_BY_DATE_ASC -> items.sortBy { it.lastAddedDate } + } + val stats = GradesStats() + if (manager.isUniversity) { + val semesterSum = mutableListOf() + val semesterCount = mutableListOf() + val totalSum = mutableListOf() + val totalCount = mutableListOf() + val ectsPoints = mutableMapOf() + for (grade in grades) { + if (grade.value == 0.0f || grade.weight == 0.0f) + continue + totalSum.add(grade.value * grade.weight) + totalCount.add(grade.weight) + if (grade.value < 3.0) + // exam not passed, reset points for this subject + ectsPoints[grade.subjectId] = 0.0f + else if (grade.subjectId !in ectsPoints) + // no points for this subject, simply assign + ectsPoints[grade.subjectId] = grade.weight + + semesterSum.add(grade.value * grade.weight) + semesterCount.add(grade.weight) + } + stats.universitySem = semesterSum.sum() / semesterCount.sum() + stats.universityTotal = totalSum.sum() / totalCount.sum() + stats.universityEcts = ectsPoints.values.sum() + return (items + stats).toMutableList() + } + val sem1Expected = mutableListOf() val sem2Expected = mutableListOf() val yearlyExpected = mutableListOf() @@ -330,11 +362,6 @@ class GradesListFragment : Fragment(), CoroutineScope { stats.pointSem2 = sem2Point.averageOrNull()?.toFloat() ?: 0f stats.pointYearly = yearlyPoint.averageOrNull()?.toFloat() ?: 0f - when (manager.orderBy) { - GradesManager.ORDER_BY_DATE_DESC -> items.sortByDescending { it.lastAddedDate } - GradesManager.ORDER_BY_DATE_ASC -> items.sortBy { it.lastAddedDate } - } - return (items + stats).toMutableList() } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/models/GradesStats.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/models/GradesStats.kt index 26041dcd..2d8f04e9 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/models/GradesStats.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/models/GradesStats.kt @@ -22,4 +22,8 @@ class GradesStats { var pointSem1 = 0f var pointSem2 = 0f var pointYearly = 0f + + var universitySem = 0f + var universityTotal = 0f + var universityEcts = 0f } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/viewholder/StatsViewHolder.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/viewholder/StatsViewHolder.kt index 3386b276..c0c821e2 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/viewholder/StatsViewHolder.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/viewholder/StatsViewHolder.kt @@ -31,9 +31,35 @@ class StatsViewHolder( override fun onBind(activity: AppCompatActivity, app: App, item: GradesStats, position: Int, adapter: GradesAdapter) { val manager = app.gradesManager + val isUniversity = manager.isUniversity val showAverages = mutableListOf() val showPoint = mutableListOf() + b.universityTitle.isVisible = isUniversity + b.universityLayout.isVisible = isUniversity + b.universityDivider.isVisible = isUniversity + + if (isUniversity) { + val format = DecimalFormat("#.00") + + b.normalTitle.isVisible = false + b.normalLayout.isVisible = false + b.normalDivider.isVisible = false + b.helpButton.isVisible = false + b.pointTitle.isVisible = false + b.pointLayout.isVisible = false + b.pointDivider.isVisible = false + b.noData.isVisible = false + b.disclaimer.isVisible = true + b.customValueDivider.isVisible = false + b.customValueLayout.isVisible = false + + b.universitySemester.text = format.format(item.universitySem) + b.universityTotal.text = format.format(item.universityTotal) + b.universityEcts.text = format.format(item.universityEcts) + return + } + getSemesterString(app, item.normalSem1, item.normalSem1Proposed, item.normalSem1Final, item.sem1NotAllFinal).let { (average, notice) -> b.normalSemester1Layout.isVisible = average != null b.normalSemester1Notice.isVisible = notice != null diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/viewholder/SubjectViewHolder.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/viewholder/SubjectViewHolder.kt index 1033fd65..51ea92ef 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/viewholder/SubjectViewHolder.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/grades/viewholder/SubjectViewHolder.kt @@ -62,9 +62,24 @@ class SubjectViewHolder( val firstSemester = item.semesters.firstOrNull() ?: return - b.yearSummary.text = manager.getYearSummaryString(app, item.semesters.map { it.grades.size }.sum(), item.averages) + if (manager.isUniversity) { + val ectsPoints = item.semesters.firstOrNull()?.grades?.maxOf { it.weight } + b.yearSummary.text = if (ectsPoints != null) + contextWrapper.getString( + R.string.grades_ects_points_format, + ectsPoints + ) + else + null + } else { + b.yearSummary.text = manager.getYearSummaryString( + app, + item.semesters.map { it.grades.size }.sum(), + item.averages + ) + } - if (firstSemester.number != item.semester) { + if (firstSemester.number != item.semester && !manager.isUniversity) { b.gradesContainer.addView(TextView(contextWrapper).apply { setTextColor(android.R.attr.textColorSecondary.resolveAttr(context)) setText(R.string.grades_preview_other_semester, firstSemester.number) @@ -92,16 +107,18 @@ class SubjectViewHolder( )) } - b.previewContainer.addView(TextView(contextWrapper).apply { - setTextColor(android.R.attr.textColorSecondary.resolveAttr(context)) - text = manager.getAverageString(app, firstSemester.averages, nameSemester = true, showSemester = firstSemester.number) - //gravity = Gravity.END - layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { - setMargins(0, 0, 8.dp, 0) - } - maxLines = 1 - ellipsize = TextUtils.TruncateAt.END - }) + if (!manager.isUniversity) { + b.previewContainer.addView(TextView(contextWrapper).apply { + setTextColor(android.R.attr.textColorSecondary.resolveAttr(context)) + text = manager.getAverageString(app, firstSemester.averages, nameSemester = true, showSemester = firstSemester.number) + //gravity = Gravity.END + layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { + setMargins(0, 0, 8.dp, 0) + } + maxLines = 1 + ellipsize = TextUtils.TruncateAt.END + }) + } // add the topmost semester's grades to preview container (collapsed) firstSemester.proposedGrade?.let { @@ -139,7 +156,7 @@ class SubjectViewHolder( } // if showing semester 2, add yearly grades to preview container (collapsed) - if (firstSemester.number == item.semester) { + if (firstSemester.number == item.semester && !manager.isUniversity) { b.previewContainer.addView(TextView(contextWrapper).apply { text = manager.getAverageString(app, item.averages, nameSemester = true) layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/GradesManager.kt b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/GradesManager.kt index 1fd188fa..b381eb88 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/GradesManager.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/GradesManager.kt @@ -70,6 +70,8 @@ class GradesManager(val app: App) : CoroutineScope { get() = app.profile.config.grades.hideImproved val averageWithoutWeight get() = app.profile.config.grades.averageWithoutWeight + val isUniversity + get() = app.profile.loginStoreType.schoolType == SchoolType.UNIVERSITY fun getOrderByString() = when (orderBy) { diff --git a/app/src/main/res/layout/grades_item_stats.xml b/app/src/main/res/layout/grades_item_stats.xml index 8bddb7de..da99c686 100644 --- a/app/src/main/res/layout/grades_item_stats.xml +++ b/app/src/main/res/layout/grades_item_stats.xml @@ -283,6 +283,107 @@ android:layout_marginTop="8dp" android:background="@drawable/divider" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Własna wartość minusa Własna wartość plusa Konfiguracja ocen + Punkty ECTS: %#.2f Dodaj ocenę Dodawanie oceny Podaj wagę oceny @@ -474,9 +475,11 @@ semestr %d: %spkt Semestr %d Semestr %d + wszystkie oceny Aktualne ustawienia ocen mogą wpływać na średnią. Jeśli uważasz, że się ona nie zgadza, kliknij Konfiguruj. Została ustawiona własna wartość plusa/minusa. Jeśli uważasz, że się ona nie zgadza, kliknij Konfiguruj. *średnie ocen są poglądowe i mogą się różnić, w zależności od ustawień szkoły + punkty ECTS *przewidywana średnia *z ocen końcowych\nPrzewidywana: %s *z ocen końcowych @@ -490,7 +493,9 @@ Śr. ocen proponowanych:\n%s semestr 1 semestr 2 + ten semestr Statystyka ocen + Średnia ocen za studia całoroczna wartość: %s waga %s