diff --git a/app/src/main/java/io/github/wulkanowy/data/repositories/preferences/PreferencesRepository.kt b/app/src/main/java/io/github/wulkanowy/data/repositories/preferences/PreferencesRepository.kt index d51fc495..b29e5143 100644 --- a/app/src/main/java/io/github/wulkanowy/data/repositories/preferences/PreferencesRepository.kt +++ b/app/src/main/java/io/github/wulkanowy/data/repositories/preferences/PreferencesRepository.kt @@ -17,6 +17,9 @@ class PreferencesRepository @Inject constructor( val isShowPresent: Boolean get() = sharedPref.getBoolean(context.getString(R.string.pref_key_attendance_present), true) + val gradeAverageMode: String + get() = sharedPref.getString(context.getString(R.string.pref_key_grade_average_mode), "only_one_semester") ?: "only_one_semester" + val isGradeExpandable: Boolean get() = !sharedPref.getBoolean(context.getString(R.string.pref_key_expand_grade), false) @@ -50,8 +53,7 @@ class PreferencesRepository @Inject constructor( get() = sharedPref.getString(context.getString(R.string.pref_key_grade_modifier_plus), "0.0")?.toDouble() ?: 0.0 val gradeMinusModifier: Double - get() = sharedPref.getString(context.getString(R.string.pref_key_grade_modifier_minus), "0.0")?.toDouble() - ?: 0.0 + get() = sharedPref.getString(context.getString(R.string.pref_key_grade_modifier_minus), "0.0")?.toDouble() ?: 0.0 val fillMessageContent: Boolean get() = sharedPref.getBoolean(context.getString(R.string.pref_key_fill_message_content), true) 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 new file mode 100644 index 00000000..a76f3d5a --- /dev/null +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/GradeAverageProvider.kt @@ -0,0 +1,54 @@ +package io.github.wulkanowy.ui.modules.grade + +import io.github.wulkanowy.data.db.entities.Semester +import io.github.wulkanowy.data.db.entities.Student +import io.github.wulkanowy.data.repositories.grade.GradeRepository +import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository +import io.github.wulkanowy.utils.calcAverage +import io.github.wulkanowy.utils.changeModifier +import io.reactivex.Single +import javax.inject.Inject + +class GradeAverageProvider @Inject constructor( + private val preferencesRepository: PreferencesRepository, + private val gradeRepository: GradeRepository +) { + fun getGradeAverage(student: Student, semesters: List, selectedSemesterId: Int, forceRefresh: Boolean): Single> { + return when (preferencesRepository.gradeAverageMode) { + "all_year" -> getAllYearAverage(student, semesters, selectedSemesterId, forceRefresh) + "only_one_semester" -> getOnlyOneSemesterAverage(student, semesters, selectedSemesterId, forceRefresh) + else -> throw IllegalArgumentException("Incorrect grade average mode: ${preferencesRepository.gradeAverageMode} ") + } + } + + private fun getAllYearAverage(student: Student, semesters: List, semesterId: Int, forceRefresh: Boolean): Single> { + val selectedSemester = semesters.single { it.semesterId == semesterId } + val firstSemester = semesters.single { it.diaryId == selectedSemester.diaryId && it.semesterName == 1 } + val plusModifier = preferencesRepository.gradePlusModifier + val minusModifier = preferencesRepository.gradeMinusModifier + + return gradeRepository.getGrades(student, selectedSemester, forceRefresh) + .flatMap { firstGrades -> + if (selectedSemester == firstSemester) Single.just(firstGrades) + else gradeRepository.getGrades(student, firstSemester) + .map { secondGrades -> secondGrades + firstGrades } + }.map { grades -> + grades.map { it.changeModifier(plusModifier, minusModifier) } + .groupBy { it.subject } + .mapValues { it.value.calcAverage() } + } + } + + private fun getOnlyOneSemesterAverage(student: Student, semesters: List, semesterId: Int, forceRefresh: Boolean): Single> { + val selectedSemester = semesters.single { it.semesterId == semesterId } + val plusModifier = preferencesRepository.gradePlusModifier + val minusModifier = preferencesRepository.gradeMinusModifier + + return gradeRepository.getGrades(student, selectedSemester, forceRefresh) + .map { grades -> + grades.map { it.changeModifier(plusModifier, minusModifier) } + .groupBy { it.subject } + .mapValues { it.value.calcAverage() } + } + } +} diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt index 1be0b36f..12e60687 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/details/GradeDetailsPresenter.kt @@ -8,10 +8,9 @@ import io.github.wulkanowy.data.repositories.semester.SemesterRepository import io.github.wulkanowy.data.repositories.student.StudentRepository import io.github.wulkanowy.ui.base.session.BaseSessionPresenter import io.github.wulkanowy.ui.base.session.SessionErrorHandler +import io.github.wulkanowy.ui.modules.grade.GradeAverageProvider import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider -import io.github.wulkanowy.utils.calcAverage -import io.github.wulkanowy.utils.changeModifier import io.github.wulkanowy.utils.getBackgroundColor import timber.log.Timber import javax.inject.Inject @@ -23,6 +22,7 @@ class GradeDetailsPresenter @Inject constructor( private val studentRepository: StudentRepository, private val semesterRepository: SemesterRepository, private val preferencesRepository: PreferencesRepository, + private val averageProvider: GradeAverageProvider, private val analytics: FirebaseAnalyticsHelper ) : BaseSessionPresenter(errorHandler) { @@ -109,11 +109,16 @@ class GradeDetailsPresenter @Inject constructor( private fun loadData(semesterId: Int, forceRefresh: Boolean) { Timber.i("Loading grade details data started") disposable.add(studentRepository.getCurrentStudent() - .flatMap { semesterRepository.getSemesters(it).map { semester -> semester to it } } - .flatMap { gradeRepository.getGrades(it.second, it.first.first { item -> item.semesterId == semesterId }, forceRefresh) } - .map { it.sortedByDescending { grade -> grade.date } } - .map { it.map { item -> item.changeModifier(preferencesRepository.gradePlusModifier, preferencesRepository.gradeMinusModifier) } } - .map { createGradeItems(it.groupBy { grade -> grade.subject }.toSortedMap()) } + .flatMap { semesterRepository.getSemesters(it).map { semester -> it to semester } } + .flatMap { (student, semesters) -> + averageProvider.getGradeAverage(student, semesters, semesterId, forceRefresh) + .flatMap { averages -> + gradeRepository.getGrades(student, semesters.first { semester -> semester.semesterId == semesterId }) + .map { it.sortedByDescending { grade -> grade.date } } + .map { it.groupBy { grade -> grade.subject }.toSortedMap() } + .map { createGradeItems(it, averages) } + } + } .subscribeOn(schedulers.backgroundThread) .observeOn(schedulers.mainThread) .doFinally { @@ -139,32 +144,36 @@ class GradeDetailsPresenter @Inject constructor( }) } - private fun createGradeItems(items: Map>): List { + private fun createGradeItems(items: Map>, averages: Map): List { + val isGradeExpandable = preferencesRepository.isGradeExpandable + val gradeColorTheme = preferencesRepository.gradeColorTheme + + val noDescriptionString = view?.noDescriptionString.orEmpty() + val weightString = view?.weightString.orEmpty() + return items.map { - it.value.calcAverage().let { average -> - GradeDetailsHeader( - subject = it.key, - average = formatAverage(average), - number = view?.getGradeNumberString(it.value.size).orEmpty(), - newGrades = it.value.filter { grade -> !grade.isRead }.size, - isExpandable = preferencesRepository.isGradeExpandable - ).apply { - subItems = it.value.map { item -> - GradeDetailsItem( - grade = item, - valueBgColor = item.getBackgroundColor(preferencesRepository.gradeColorTheme), - weightString = view?.weightString.orEmpty(), - noDescriptionString = view?.noDescriptionString.orEmpty() - ) - } + GradeDetailsHeader( + subject = it.key, + average = formatAverage(averages[it.key]), + number = view?.getGradeNumberString(it.value.size).orEmpty(), + newGrades = it.value.filter { grade -> !grade.isRead }.size, + isExpandable = isGradeExpandable + ).apply { + subItems = it.value.map { item -> + GradeDetailsItem( + grade = item, + valueBgColor = item.getBackgroundColor(gradeColorTheme), + weightString = weightString, + noDescriptionString = noDescriptionString + ) } } } } - private fun formatAverage(average: Double): String { + private fun formatAverage(average: Double?): String { return view?.run { - if (average == 0.0) emptyAverageString + if (average == null || average == .0) emptyAverageString else averageString.format(average) }.orEmpty() } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt index 5dbf7513..cbd4169d 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/grade/summary/GradeSummaryPresenter.kt @@ -1,17 +1,15 @@ package io.github.wulkanowy.ui.modules.grade.summary import io.github.wulkanowy.data.db.entities.GradeSummary -import io.github.wulkanowy.data.repositories.grade.GradeRepository import io.github.wulkanowy.data.repositories.gradessummary.GradeSummaryRepository -import io.github.wulkanowy.data.repositories.preferences.PreferencesRepository import io.github.wulkanowy.data.repositories.semester.SemesterRepository import io.github.wulkanowy.data.repositories.student.StudentRepository import io.github.wulkanowy.ui.base.session.BaseSessionPresenter import io.github.wulkanowy.ui.base.session.SessionErrorHandler +import io.github.wulkanowy.ui.modules.grade.GradeAverageProvider import io.github.wulkanowy.utils.FirebaseAnalyticsHelper import io.github.wulkanowy.utils.SchedulersProvider import io.github.wulkanowy.utils.calcAverage -import io.github.wulkanowy.utils.changeModifier import timber.log.Timber import java.lang.String.format import java.util.Locale.FRANCE @@ -20,10 +18,9 @@ import javax.inject.Inject class GradeSummaryPresenter @Inject constructor( private val errorHandler: SessionErrorHandler, private val gradeSummaryRepository: GradeSummaryRepository, - private val gradeRepository: GradeRepository, private val studentRepository: StudentRepository, private val semesterRepository: SemesterRepository, - private val preferencesRepository: PreferencesRepository, + private val averageProvider: GradeAverageProvider, private val schedulers: SchedulersProvider, private val analytics: FirebaseAnalyticsHelper ) : BaseSessionPresenter(errorHandler) { @@ -36,25 +33,12 @@ class GradeSummaryPresenter @Inject constructor( fun onParentViewLoadData(semesterId: Int, forceRefresh: Boolean) { Timber.i("Loading grade summary data started") disposable.add(studentRepository.getCurrentStudent() - .flatMap { semesterRepository.getSemesters(it).map { semester -> semester to it } } - .map { pair -> pair.first.first { it.semesterId == semesterId } to pair.second } - .flatMap { - gradeSummaryRepository.getGradesSummary(it.first, forceRefresh) + .flatMap { semesterRepository.getSemesters(it).map { semesters -> it to semesters } } + .flatMap { (student, semesters) -> + gradeSummaryRepository.getGradesSummary(semesters.first { it.semesterId == semesterId }, forceRefresh) .flatMap { gradesSummary -> - gradeRepository.getGrades(it.second, it.first, forceRefresh) - .map { grades -> - grades.map { item -> item.changeModifier(preferencesRepository.gradePlusModifier, preferencesRepository.gradeMinusModifier) } - .groupBy { grade -> grade.subject } - .mapValues { entry -> entry.value.calcAverage() } - .filterValues { value -> value != 0.0 } - .let { averages -> - createGradeSummaryItems(gradesSummary, averages) to - GradeSummaryScrollableHeader( - formatAverage(gradesSummary.calcAverage()), - formatAverage(averages.values.average()) - ) - } - } + averageProvider.getGradeAverage(student, semesters, semesterId, forceRefresh) + .map { averages -> createGradeSummaryItemsAndHeader(gradesSummary, averages) } } } .subscribeOn(schedulers.backgroundThread) @@ -66,14 +50,14 @@ class GradeSummaryPresenter @Inject constructor( enableSwipe(true) notifyParentDataLoaded(semesterId) } - }.subscribe({ + }.subscribe({ (gradeSummaryItems, gradeSummaryHeader) -> Timber.i("Loading grade summary result: Success") view?.run { - showEmpty(it.first.isEmpty()) - showContent(it.first.isNotEmpty()) - updateData(it.first, it.second) + showEmpty(gradeSummaryItems.isEmpty()) + showContent(gradeSummaryItems.isNotEmpty()) + updateData(gradeSummaryItems, gradeSummaryHeader) } - analytics.logEvent("load_grade_summary", "items" to it.first.size, "force_refresh" to forceRefresh) + analytics.logEvent("load_grade_summary", "items" to gradeSummaryItems.size, "force_refresh" to forceRefresh) }) { Timber.i("Loading grade summary result: An exception occurred") view?.run { showEmpty(isViewEmpty) } @@ -104,16 +88,24 @@ class GradeSummaryPresenter @Inject constructor( disposable.clear() } - private fun createGradeSummaryItems(gradesSummary: List, averages: Map) - : List { - return gradesSummary.filter { !checkEmpty(it, averages) }.map { it -> - GradeSummaryItem( - title = it.subject, - average = formatAverage(averages.getOrElse(it.subject) { 0.0 }, ""), - predictedGrade = it.predictedGrade, - finalGrade = it.finalGrade - ) - } + private fun createGradeSummaryItemsAndHeader(gradesSummary: List, averages: Map) + : Pair, GradeSummaryScrollableHeader> { + return averages.filterValues { value -> value != 0.0 } + .let { filteredAverages -> + gradesSummary.filter { !checkEmpty(it, filteredAverages) } + .map { + GradeSummaryItem( + title = it.subject, + average = formatAverage(filteredAverages.getOrElse(it.subject) { 0.0 }, ""), + predictedGrade = it.predictedGrade, + finalGrade = it.finalGrade + ) + }.let { + it to GradeSummaryScrollableHeader( + formatAverage(gradesSummary.calcAverage()), + formatAverage(filteredAverages.values.average())) + } + } } private fun checkEmpty(gradeSummary: GradeSummary, averages: Map): Boolean { diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 04a4a2ea..aee503b8 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -239,11 +239,11 @@ Wygląd Domyślny widok - Pokazuj podsumowanie w ocenach + Obliczanie średniej końcoworocznej Pokazuj obecność we frekwencji Ciemny motyw (Beta) Rozwiń oceny - Schemat kolorów ocen + Schemat kolorów ocen Powiadomienia Pokazuj powiadomienia diff --git a/app/src/main/res/values-pl/value_prefernces.xml b/app/src/main/res/values-pl/value_prefernces.xml index 2231cc0b..34a10909 100644 --- a/app/src/main/res/values-pl/value_prefernces.xml +++ b/app/src/main/res/values-pl/value_prefernces.xml @@ -30,4 +30,9 @@ Wulkanowy Kolory ocen w dzienniku + + + Średnia ocen z 2 semestru + Średnia ocen z całego roku + diff --git a/app/src/main/res/values/preferences_keys.xml b/app/src/main/res/values/preferences_keys.xml index 427cca56..d03b4fbb 100644 --- a/app/src/main/res/values/preferences_keys.xml +++ b/app/src/main/res/values/preferences_keys.xml @@ -5,6 +5,7 @@ theme grade_color_scheme expand_grade + grade_average_mode services_enable services_interval services_disable_wifi_only diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 69481ecf..8dc6a25c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -224,11 +224,11 @@ Appearance Default view - Show the summary in the grades + Calculation of the end-of-year average Show presence in attendance Dark theme (Beta) Expand grades - Grades color scheme + Grades color scheme Notifications Show notifications diff --git a/app/src/main/res/values/value_prefernces.xml b/app/src/main/res/values/value_prefernces.xml index 661615e1..3921b4e2 100644 --- a/app/src/main/res/values/value_prefernces.xml +++ b/app/src/main/res/values/value_prefernces.xml @@ -70,4 +70,13 @@ material grade_color + + + Average grades from the 2nd semester + Average of grades from the whole year + + + only_one_semester + all_year + diff --git a/app/src/main/res/xml/scheme_preferences.xml b/app/src/main/res/xml/scheme_preferences.xml index 08c24124..5c2a8dda 100644 --- a/app/src/main/res/xml/scheme_preferences.xml +++ b/app/src/main/res/xml/scheme_preferences.xml @@ -36,7 +36,7 @@ android:entryValues="@array/grade_color_scheme_values" android:key="@string/pref_key_grade_color_scheme" android:summary="%s" - android:title="@string/pref_grade_color_scheme" + android:title="@string/pref_view_grade_color_scheme" app:iconSpaceReserved="false" /> +