diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt index 5bd1f3c12..375dd62e7 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/PreferencesRepository.kt @@ -146,6 +146,12 @@ class PreferencesRepository @Inject constructor( R.bool.pref_default_subjects_without_grades ) + val isOptionalArithmeticAverage: Boolean + get() = getBoolean( + R.string.pref_key_optional_arithmetic_average, + R.bool.pref_default_optional_arithmetic_average + ) + var isKitkatDialogDisabled: Boolean get() = sharedPref.getBoolean("kitkat_dialog_disabled", false) set(value) = sharedPref.edit { putBoolean("kitkat_dialog_disabled", value) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt index 7e9b56b94..67472fa34 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt @@ -34,6 +34,8 @@ class GradeAverageProvider @Inject constructor( private val minusModifier get() = preferencesRepository.gradeMinusModifier + private val isOptionalArithmeticAverage get() = preferencesRepository.isOptionalArithmeticAverage + fun getGradesDetailsWithAverage(student: Student, semesterId: Int, forceRefresh: Boolean) = flowWithResourceIn { val semesters = semesterRepository.getSemesters(student) @@ -130,7 +132,7 @@ class GradeAverageProvider @Inject constructor( val updatedFirstSemesterGrades = firstSemesterSubject?.grades?.updateModifiers(student).orEmpty() - (updatedSecondSemesterGrades + updatedFirstSemesterGrades).calcAverage() + (updatedSecondSemesterGrades + updatedFirstSemesterGrades).calcAverage(isOptionalArithmeticAverage) } else { secondSemesterSubject.average } @@ -146,9 +148,9 @@ class GradeAverageProvider @Inject constructor( return if (!isAnyVulcanAverage || gradeAverageForceCalc) { val secondSemesterAverage = - secondSemesterSubject.grades.updateModifiers(student).calcAverage() + secondSemesterSubject.grades.updateModifiers(student).calcAverage(isOptionalArithmeticAverage) val firstSemesterAverage = firstSemesterSubject?.grades?.updateModifiers(student) - ?.calcAverage() ?: secondSemesterAverage + ?.calcAverage(isOptionalArithmeticAverage) ?: secondSemesterAverage (secondSemesterAverage + firstSemesterAverage) / divider } else { @@ -179,7 +181,7 @@ class GradeAverageProvider @Inject constructor( GradeSubject( subject = summary.subject, average = if (!isAnyAverage || gradeAverageForceCalc) { - grades.updateModifiers(student).calcAverage() + grades.updateModifiers(student).calcAverage(isOptionalArithmeticAverage) } else summary.average, points = summary.pointsSum, summary = summary, @@ -211,7 +213,7 @@ class GradeAverageProvider @Inject constructor( proposedPoints = "", finalPoints = "", pointsSum = "", - average = if (calcAverage) details.updateModifiers(student).calcAverage() else .0 + average = if (calcAverage) details.updateModifiers(student).calcAverage(isOptionalArithmeticAverage) else .0 ) } } diff --git a/app/src/main/java/io/github/wulkanowy/utils/GradeExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/GradeExtension.kt index 6facb5ef6..820e7f435 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/GradeExtension.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/GradeExtension.kt @@ -3,14 +3,17 @@ package io.github.wulkanowy.utils import io.github.wulkanowy.R import io.github.wulkanowy.data.db.entities.Grade import io.github.wulkanowy.data.db.entities.GradeSummary +import io.github.wulkanowy.sdk.scrapper.grades.* -fun List.calcAverage(): Double { +fun List.calcAverage(isOptionalArithmeticAverage: Boolean): Double { + val isArithmeticAverage = isOptionalArithmeticAverage && !any { it.weightValue != .0 } var counter = 0.0 var denominator = 0.0 forEach { - counter += (it.value + it.modifier) * it.weightValue - denominator += it.weightValue + val weight = if (isArithmeticAverage && isGradeValid(it.entry)) 1.0 else it.weightValue + counter += (it.value + it.modifier) * weight + denominator += weight } return if (denominator != 0.0) counter / denominator else 0.0 } diff --git a/app/src/main/res/values/preferences_defaults.xml b/app/src/main/res/values/preferences_defaults.xml index fb82e0ed6..a3aa62f81 100644 --- a/app/src/main/res/values/preferences_defaults.xml +++ b/app/src/main/res/values/preferences_defaults.xml @@ -24,4 +24,5 @@ false false false + false diff --git a/app/src/main/res/values/preferences_keys.xml b/app/src/main/res/values/preferences_keys.xml index 0cfa485e3..1d00dcd6b 100644 --- a/app/src/main/res/values/preferences_keys.xml +++ b/app/src/main/res/values/preferences_keys.xml @@ -26,4 +26,5 @@ timetable_show_timers homework_fullscreen subjects_without_grades + optional_arithmetic_average diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c4109d2b8..1b7c9e427 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -507,6 +507,7 @@ Value of the plus Value of the minus Reply with message history + Show arithmetic average when no weights provided Advanced Appearance & Behavior diff --git a/app/src/main/res/xml/scheme_preferences_advanced.xml b/app/src/main/res/xml/scheme_preferences_advanced.xml index 1d7e9b832..461037871 100644 --- a/app/src/main/res/xml/scheme_preferences_advanced.xml +++ b/app/src/main/res/xml/scheme_preferences_advanced.xml @@ -25,6 +25,12 @@ app:key="@string/pref_key_grade_average_force_calc" app:singleLineTitle="false" app:title="@string/pref_view_grade_average_force_calc" /> + () to emptyList() } @@ -227,6 +271,7 @@ class GradeAverageProviderTest { @Test fun `force calc current semester average with default modifiers in scraper mode`() { every { preferencesRepository.gradeAverageForceCalc } returns true + every { preferencesRepository.isOptionalArithmeticAverage } returns false every { preferencesRepository.gradeAverageMode } returns GradeAverageMode.ONE_SEMESTER coEvery { semesterRepository.getSemesters(student) } returns semesters coEvery { gradeRepository.getGrades(student, semesters[2], true) } returns flowWithResource { secondGradeWithModifier to secondSummariesWithModifier } @@ -241,6 +286,7 @@ class GradeAverageProviderTest { val student = student.copy(loginMode = Sdk.Mode.SCRAPPER.name) every { preferencesRepository.gradeAverageForceCalc } returns true + every { preferencesRepository.isOptionalArithmeticAverage } returns false every { preferencesRepository.gradeMinusModifier } returns .33 every { preferencesRepository.gradePlusModifier } returns .33 @@ -258,6 +304,7 @@ class GradeAverageProviderTest { val student = student.copy(loginMode = Sdk.Mode.API.name) every { preferencesRepository.gradeAverageForceCalc } returns true + every { preferencesRepository.isOptionalArithmeticAverage } returns false every { preferencesRepository.gradeMinusModifier } returns .33 // useless in this mode every { preferencesRepository.gradePlusModifier } returns .33 @@ -275,6 +322,7 @@ class GradeAverageProviderTest { val student = student.copy(loginMode = Sdk.Mode.HYBRID.name) every { preferencesRepository.gradeAverageForceCalc } returns true + every { preferencesRepository.isOptionalArithmeticAverage } returns false every { preferencesRepository.gradeMinusModifier } returns .33 // useless in this mode every { preferencesRepository.gradePlusModifier } returns .33 @@ -290,6 +338,7 @@ class GradeAverageProviderTest { @Test fun `calc current semester average`() { every { preferencesRepository.gradeAverageForceCalc } returns false + every { preferencesRepository.isOptionalArithmeticAverage } returns false every { preferencesRepository.gradeAverageMode } returns GradeAverageMode.ONE_SEMESTER coEvery { gradeRepository.getGrades(student, semesters[2], true) } returns flowWithResource { secondGrades to secondSummaries } @@ -303,6 +352,7 @@ class GradeAverageProviderTest { @Test fun `force calc current semester average`() { every { preferencesRepository.gradeAverageForceCalc } returns true + every { preferencesRepository.isOptionalArithmeticAverage } returns false every { preferencesRepository.gradeAverageMode } returns GradeAverageMode.ONE_SEMESTER coEvery { gradeRepository.getGrades(student, semesters[2], true) } returns flowWithResource { secondGrades to secondSummaries } @@ -316,6 +366,7 @@ class GradeAverageProviderTest { @Test fun `force calc full year average when current is first`() { every { preferencesRepository.gradeAverageForceCalc } returns true + every { preferencesRepository.isOptionalArithmeticAverage } returns false every { preferencesRepository.gradeAverageMode } returns GradeAverageMode.ALL_YEAR coEvery { gradeRepository.getGrades(student, semesters[1], true) } returns flowWithResource { firstGrades to firstSummaries } @@ -329,6 +380,7 @@ class GradeAverageProviderTest { @Test fun `calc full year average when current is first with load from cache sequence`() { every { preferencesRepository.gradeAverageForceCalc } returns true + every { preferencesRepository.isOptionalArithmeticAverage } returns false every { preferencesRepository.gradeAverageMode } returns GradeAverageMode.ALL_YEAR coEvery { semesterRepository.getSemesters(student) } returns semesters coEvery { gradeRepository.getGrades(student, semesters[1], true) } returns flow { @@ -361,6 +413,7 @@ class GradeAverageProviderTest { fun `calc both semesters average`() { every { preferencesRepository.gradeAverageMode } returns GradeAverageMode.BOTH_SEMESTERS every { preferencesRepository.gradeAverageForceCalc } returns false + every { preferencesRepository.isOptionalArithmeticAverage } returns false coEvery { gradeRepository.getGrades(student, semesters[1], true) } returns flowWithResource { firstGrades to listOf( getSummary(22, "Matematyka", 3.0), @@ -384,6 +437,7 @@ class GradeAverageProviderTest { @Test fun `calc both semesters average when current is second with load from cache sequence`() { every { preferencesRepository.gradeAverageMode } returns GradeAverageMode.BOTH_SEMESTERS + every { preferencesRepository.isOptionalArithmeticAverage } returns false every { preferencesRepository.gradeAverageForceCalc } returns false coEvery { gradeRepository.getGrades(student, semesters[1], true) } returns flow { emit(Resource.loading()) @@ -431,6 +485,7 @@ class GradeAverageProviderTest { @Test fun `force calc full year average`() { every { preferencesRepository.gradeAverageForceCalc } returns true + every { preferencesRepository.isOptionalArithmeticAverage } returns false every { preferencesRepository.gradeAverageMode } returns GradeAverageMode.ALL_YEAR coEvery { gradeRepository.getGrades(student, semesters[1], true) } returns flowWithResource { firstGrades to firstSummaries } coEvery { gradeRepository.getGrades(student, semesters[2], true) } returns flowWithResource { @@ -450,6 +505,7 @@ class GradeAverageProviderTest { @Test fun `calc full year average when current is second with load from cache sequence`() { every { preferencesRepository.gradeAverageForceCalc } returns true + every { preferencesRepository.isOptionalArithmeticAverage } returns false every { preferencesRepository.gradeAverageMode } returns GradeAverageMode.ALL_YEAR coEvery { semesterRepository.getSemesters(student) } returns semesters coEvery { gradeRepository.getGrades(student, semesters[1], true) } returns flow { @@ -492,6 +548,7 @@ class GradeAverageProviderTest { @Test fun `calc both semesters average when no summaries`() { every { preferencesRepository.gradeAverageForceCalc } returns true + every { preferencesRepository.isOptionalArithmeticAverage } returns false every { preferencesRepository.gradeAverageMode } returns GradeAverageMode.BOTH_SEMESTERS coEvery { gradeRepository.getGrades(student, semesters[1], true) } returns flowWithResource { firstGrades to emptyList() } @@ -507,6 +564,7 @@ class GradeAverageProviderTest { @Test fun `force calc full year average when no summaries`() { every { preferencesRepository.gradeAverageForceCalc } returns true + every { preferencesRepository.isOptionalArithmeticAverage } returns false every { preferencesRepository.gradeAverageMode } returns GradeAverageMode.ALL_YEAR coEvery { gradeRepository.getGrades(student, semesters[1], true) } returns flowWithResource { firstGrades to emptyList() } @@ -522,6 +580,7 @@ class GradeAverageProviderTest { @Test fun `calc both semesters average when missing summaries in both semesters`() { every { preferencesRepository.gradeAverageForceCalc } returns false + every { preferencesRepository.isOptionalArithmeticAverage } returns false every { preferencesRepository.gradeAverageMode } returns GradeAverageMode.BOTH_SEMESTERS coEvery { gradeRepository.getGrades(student, semesters[1], true) } returns flowWithResource { @@ -545,6 +604,7 @@ class GradeAverageProviderTest { @Test fun `calc both semesters average when missing summary in second semester`() { every { preferencesRepository.gradeAverageForceCalc } returns false + every { preferencesRepository.isOptionalArithmeticAverage } returns false every { preferencesRepository.gradeAverageMode } returns GradeAverageMode.BOTH_SEMESTERS coEvery { gradeRepository.getGrades(student, semesters[1], true) } returns flowWithResource { firstGrades to firstSummaries } @@ -560,6 +620,7 @@ class GradeAverageProviderTest { @Test fun `calc both semesters average when missing summary in first semester`() { every { preferencesRepository.gradeAverageForceCalc } returns false + every { preferencesRepository.isOptionalArithmeticAverage } returns false every { preferencesRepository.gradeAverageMode } returns GradeAverageMode.BOTH_SEMESTERS coEvery { gradeRepository.getGrades(student, semesters[1], true) } returns flowWithResource { firstGrades to firstSummaries.dropLast(1) } @@ -575,6 +636,7 @@ class GradeAverageProviderTest { @Test fun `force calc full year average when missing summary in first semester`() { every { preferencesRepository.gradeAverageForceCalc } returns true + every { preferencesRepository.isOptionalArithmeticAverage } returns false every { preferencesRepository.gradeAverageMode } returns GradeAverageMode.ALL_YEAR coEvery { gradeRepository.getGrades(student, semesters[1], true) } returns flowWithResource { firstGrades to firstSummaries.dropLast(1) } @@ -591,6 +653,7 @@ class GradeAverageProviderTest { fun `force calc both semesters average with different average from all grades and from two semesters`() { every { preferencesRepository.gradeAverageForceCalc } returns true every { preferencesRepository.gradeAverageMode } returns GradeAverageMode.BOTH_SEMESTERS + every { preferencesRepository.isOptionalArithmeticAverage } returns false coEvery { gradeRepository.getGrades(student, semesters[1], true) } returns flowWithResource { listOf( @@ -620,6 +683,7 @@ class GradeAverageProviderTest { @Test fun `force calc full year average with different average from all grades and from two semesters`() { every { preferencesRepository.gradeAverageForceCalc } returns true + every { preferencesRepository.isOptionalArithmeticAverage } returns false every { preferencesRepository.gradeAverageMode } returns GradeAverageMode.ALL_YEAR coEvery { gradeRepository.getGrades(student, semesters[1], true) } returns flowWithResource { @@ -652,6 +716,7 @@ class GradeAverageProviderTest { val student = student.copy(loginMode = Sdk.Mode.SCRAPPER.name) every { preferencesRepository.gradeAverageForceCalc } returns true + every { preferencesRepository.isOptionalArithmeticAverage } returns false every { preferencesRepository.gradeMinusModifier } returns .33 every { preferencesRepository.gradePlusModifier } returns .5 @@ -688,6 +753,7 @@ class GradeAverageProviderTest { val student = student.copy(loginMode = Sdk.Mode.SCRAPPER.name) every { preferencesRepository.gradeAverageForceCalc } returns true + every { preferencesRepository.isOptionalArithmeticAverage } returns false every { preferencesRepository.gradeMinusModifier } returns .33 every { preferencesRepository.gradePlusModifier } returns .5 @@ -719,7 +785,7 @@ class GradeAverageProviderTest { assertEquals(5.5555, items.single { it.subject == "Fizyka" }.average, .0001) // (from details): 5.72727272 + 4,8 → .average() } - private fun getGrade(semesterId: Int, subject: String, value: Double, modifier: Double = 0.0, weight: Double = 1.0): Grade { + private fun getGrade(semesterId: Int, subject: String, value: Double, modifier: Double = 0.0, weight: Double = 1.0, entry: String = ""): Grade { return Grade( studentId = 101, semesterId = semesterId, @@ -731,7 +797,7 @@ class GradeAverageProviderTest { date = now(), weight = "", gradeSymbol = "", - entry = "", + entry = entry, description = "", comment = "", color = "" diff --git a/app/src/test/java/io/github/wulkanowy/utils/GradeExtensionTest.kt b/app/src/test/java/io/github/wulkanowy/utils/GradeExtensionTest.kt index 958b9169b..32b1602e9 100644 --- a/app/src/test/java/io/github/wulkanowy/utils/GradeExtensionTest.kt +++ b/app/src/test/java/io/github/wulkanowy/utils/GradeExtensionTest.kt @@ -28,7 +28,7 @@ class GradeExtensionTest { createGrade(4.0, 1.0, 0.0), createGrade(1.0, 9.0, 0.5), createGrade(0.0, .0, 0.0) - ).calcAverage(), 0.005) + ).calcAverage(false), 0.005) } @Test