From f17a02be546fe7ee7267c191dbf458edb55ea71c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Fri, 6 Mar 2020 21:09:05 +0100 Subject: [PATCH] [Grades] Implement new Grades module (UI & API changes). --- app/build.gradle | 2 + .../java/pl/szczodrzynski/edziennik/App.kt | 2 + .../pl/szczodrzynski/edziennik/Extensions.kt | 12 + .../edziennik/config/ConfigGrades.kt | 12 +- .../edziennik/config/ProfileConfigGrades.kt | 19 +- .../config/utils/ConfigExtensions.kt | 6 +- .../edziennik/config/utils/ConfigMigration.kt | 2 +- .../config/utils/ProfileConfigMigration.kt | 6 +- .../data/web/EdudziennikWebGrades.kt | 105 +-- .../idziennik/data/web/IdziennikWebGrades.kt | 49 +- .../data/web/IdziennikWebProposedGrades.kt | 60 +- .../data/api/LibrusApiBehaviourGrades.kt | 78 +- .../data/api/LibrusApiDescriptiveGrades.kt | 32 +- .../librus/data/api/LibrusApiGrades.kt | 52 +- .../librus/data/api/LibrusApiPointGrades.kt | 27 +- .../librus/data/api/LibrusApiTextGrades.kt | 30 +- .../data/api/MobidziennikApiGrades.kt | 33 +- .../data/web/MobidziennikWebGrades.kt | 25 +- .../vulcan/data/api/VulcanApiGrades.kt | 25 +- .../data/api/VulcanApiProposedGrades.kt | 38 +- .../szczodrzynski/edziennik/data/db/AppDb.kt | 5 +- .../edziennik/data/db/dao/MetadataDao.java | 8 +- .../edziennik/data/db/entity/Grade.java | 104 --- .../edziennik/data/db/entity/Grade.kt | 85 ++ .../edziennik/data/db/entity/Profile.kt | 7 - .../edziennik/data/db/full/GradeFull.java | 23 - .../edziennik/data/db/full/GradeFull.kt | 26 + .../data/db/migration/Migration78.kt | 44 + .../ui/dialogs/grade/GradeDetailsDialog.java | 129 --- .../ui/dialogs/grade/GradeDetailsDialog.kt | 83 ++ .../ui/dialogs/settings/GradesConfigDialog.kt | 84 +- .../edziennik/ui/modules/grades/GradeView.kt | 118 +++ .../ui/modules/grades/GradesAdapter.kt | 187 +++++ .../ui/modules/grades/GradesFragment.java | 513 ------------ .../ui/modules/grades/GradesFragment.kt | 245 ++++++ .../ui/modules/grades/GradesListAdapter.java | 143 ---- .../modules/grades/GradesSubjectAdapter.java | 787 ------------------ .../grades/editor/GradesEditorFragment.kt | 8 +- .../grades/models/ExpandableItemModel.kt | 12 + .../modules/grades/models/GradesAverages.kt | 20 + .../ui/modules/grades/models/GradesEmpty.kt | 7 + .../modules/grades/models/GradesSemester.kt | 20 + .../ui/modules/grades/models/GradesStats.kt | 25 + .../ui/modules/grades/models/GradesSubject.kt | 22 + .../grades/viewholder/BindableViewHolder.kt | 12 + .../grades/viewholder/EmptyViewHolder.kt | 27 + .../grades/viewholder/GradeViewHolder.kt | 63 ++ .../grades/viewholder/SemesterViewHolder.kt | 39 + .../grades/viewholder/StatsViewHolder.kt | 142 ++++ .../grades/viewholder/SubjectViewHolder.kt | 134 +++ .../ui/modules/home/cards/HomeGradesCard.kt | 10 +- .../modules/settings/SettingsNewFragment.java | 10 +- .../szczodrzynski/edziennik/utils/Colors.java | 14 +- .../edziennik/utils/managers/GradesManager.kt | 227 +++++ .../edziennik/utils/models/Date.java | 2 +- .../res/drawable/bg_rounded_4dp_outline.xml | 4 +- app/src/main/res/drawable/bg_rounded_8dp.xml | 2 +- app/src/main/res/drawable/ic_no_grades.xml | 16 + .../main/res/layout/dialog_config_grades.xml | 77 +- .../main/res/layout/dialog_grade_details.xml | 458 +++++----- app/src/main/res/layout/grades_fragment.xml | 37 + app/src/main/res/layout/grades_item_empty.xml | 21 + app/src/main/res/layout/grades_item_grade.xml | 101 +++ .../main/res/layout/grades_item_semester.xml | 80 ++ app/src/main/res/layout/grades_item_stats.xml | 334 ++++++++ .../main/res/layout/grades_item_subject.xml | 91 ++ app/src/main/res/values-en/strings.xml | 4 +- app/src/main/res/values/plurals.xml | 8 +- app/src/main/res/values/strings.xml | 42 +- 69 files changed, 3009 insertions(+), 2266 deletions(-) delete mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Grade.java create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Grade.kt delete mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/db/full/GradeFull.java create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/db/full/GradeFull.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration78.kt delete mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradeDetailsDialog.java create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradeDetailsDialog.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradeView.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesAdapter.kt delete mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesFragment.java create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesFragment.kt delete mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesListAdapter.java delete mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesSubjectAdapter.java create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/ExpandableItemModel.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/GradesAverages.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/GradesEmpty.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/GradesSemester.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/GradesStats.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/GradesSubject.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/BindableViewHolder.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/EmptyViewHolder.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/GradeViewHolder.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/SemesterViewHolder.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/StatsViewHolder.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/SubjectViewHolder.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/GradesManager.kt create mode 100644 app/src/main/res/drawable/ic_no_grades.xml create mode 100644 app/src/main/res/layout/grades_fragment.xml create mode 100644 app/src/main/res/layout/grades_item_empty.xml create mode 100644 app/src/main/res/layout/grades_item_grade.xml create mode 100644 app/src/main/res/layout/grades_item_semester.xml create mode 100644 app/src/main/res/layout/grades_item_stats.xml create mode 100644 app/src/main/res/layout/grades_item_subject.xml diff --git a/app/build.gradle b/app/build.gradle index beadd513..71e7a7dc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -190,6 +190,8 @@ dependencies { implementation 'com.github.jetradarmobile:android-snowfall:1.2.0' implementation "io.coil-kt:coil:0.9.2" + + implementation 'com.github.kuba2k2:NumberSlidingPicker:2921225f76' } repositories { mavenCentral() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt index b2dc9e0e..98180d87 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/App.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/App.kt @@ -45,6 +45,7 @@ import pl.szczodrzynski.edziennik.sync.SyncWorker import pl.szczodrzynski.edziennik.sync.UpdateWorker import pl.szczodrzynski.edziennik.ui.modules.base.CrashActivity import pl.szczodrzynski.edziennik.utils.* +import pl.szczodrzynski.edziennik.utils.managers.GradesManager import pl.szczodrzynski.edziennik.utils.managers.NotificationChannelsManager import pl.szczodrzynski.edziennik.utils.managers.UserActionManager import java.util.concurrent.TimeUnit @@ -65,6 +66,7 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope { val notificationChannelsManager by lazy { NotificationChannelsManager(this) } val userActionManager by lazy { UserActionManager(this) } + val gradesManager by lazy { GradesManager(this) } val db get() = App.db diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt index c491c71e..df60318f 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/Extensions.kt @@ -1080,3 +1080,15 @@ fun Throwable.toErrorCode() = when (this) { private fun ApiResponse.Error.toErrorCode() = when (this.code) { else -> ERROR_API_EXCEPTION } + +inline fun ifNotNull(a: A?, b: B?, code: (A, B) -> R): R? { + if (a != null && b != null) { + return code(a, b) + } + return null +} + +@kotlin.jvm.JvmName("averageOrNullOfInt") +fun Iterable.averageOrNull() = this.average().let { if (it.isNaN()) null else it } +@kotlin.jvm.JvmName("averageOrNullOfFloat") +fun Iterable.averageOrNull() = this.average().let { if (it.isNaN()) null else it } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/ConfigGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/ConfigGrades.kt index 649bbed7..267ec322 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/config/ConfigGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/ConfigGrades.kt @@ -6,17 +6,11 @@ package pl.szczodrzynski.edziennik.config import pl.szczodrzynski.edziennik.config.utils.get import pl.szczodrzynski.edziennik.config.utils.set +import pl.szczodrzynski.edziennik.utils.managers.GradesManager class ConfigGrades(private val config: Config) { - companion object { - const val ORDER_BY_DATE_DESC = 0 - const val ORDER_BY_SUBJECT_ASC = 1 - const val ORDER_BY_DATE_ASC = 2 - const val ORDER_BY_SUBJECT_DESC = 3 - } - private var mOrderBy: Int? = null var orderBy: Int - get() { mOrderBy = mOrderBy ?: config.values.get("gradesOrderBy", 0); return mOrderBy ?: ORDER_BY_DATE_DESC } + get() { mOrderBy = mOrderBy ?: config.values.get("gradesOrderBy", 0); return mOrderBy ?: GradesManager.ORDER_BY_DATE_DESC } set(value) { config.set("gradesOrderBy", value); mOrderBy = value } -} \ No newline at end of file +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/ProfileConfigGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/ProfileConfigGrades.kt index b82f6bb5..af6c8349 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/config/ProfileConfigGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/ProfileConfigGrades.kt @@ -5,9 +5,10 @@ package pl.szczodrzynski.edziennik.config import pl.szczodrzynski.edziennik.config.utils.get +import pl.szczodrzynski.edziennik.config.utils.getFloat import pl.szczodrzynski.edziennik.config.utils.set -import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.COLOR_MODE_WEIGHTED -import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.YEAR_ALL_GRADES +import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.COLOR_MODE_WEIGHTED +import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_ALL_GRADES class ProfileConfigGrades(private val config: ProfileConfig) { private var mColorMode: Int? = null @@ -24,4 +25,18 @@ class ProfileConfigGrades(private val config: ProfileConfig) { var countZeroToAvg: Boolean get() { mCountZeroToAvg = mCountZeroToAvg ?: config.values.get("countZeroToAvg", true); return mCountZeroToAvg ?: true } set(value) { config.set("countZeroToAvg", value); mCountZeroToAvg = value } + + private var mPlusValue: Float? = null + var plusValue: Float? + get() { mPlusValue = mPlusValue ?: config.values.getFloat("plusValue"); return mPlusValue } + set(value) { config.set("plusValue", value); mPlusValue = value } + private var mMinusValue: Float? = null + var minusValue: Float? + get() { mMinusValue = mMinusValue ?: config.values.getFloat("minusValue"); return mMinusValue } + set(value) { config.set("minusValue", value); mMinusValue = value } + + private var mDontCountGrades: List? = null + var dontCountGrades: List + get() { mDontCountGrades = mDontCountGrades ?: config.values.get("dontCountGrades", listOf()); return mDontCountGrades ?: listOf() } + set(value) { config.set("dontCountGrades", value); mDontCountGrades = value } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/ConfigExtensions.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/ConfigExtensions.kt index 9124542f..1188b1a4 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/ConfigExtensions.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/ConfigExtensions.kt @@ -94,10 +94,14 @@ fun HashMap.getLongList(key: String, default: List?): Lis return this[key]?.let { gson.fromJson>(it, object: TypeToken>(){}.type) } ?: default } +fun HashMap.getFloat(key: String): Float? { + return this[key]?.toFloatOrNull() +} + fun List.toHashMap(profileId: Int, map: HashMap) { map.clear() forEach { if (it.profileId == profileId) map[it.key] = it.value } -} \ No newline at end of file +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/ConfigMigration.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/ConfigMigration.kt index 8359ed0c..91951e49 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/ConfigMigration.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/ConfigMigration.kt @@ -10,7 +10,7 @@ import pl.szczodrzynski.edziennik.BuildConfig import pl.szczodrzynski.edziennik.HOUR import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.config.Config -import pl.szczodrzynski.edziennik.config.ConfigGrades.Companion.ORDER_BY_DATE_DESC +import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.ORDER_BY_DATE_DESC class ConfigMigration(app: App, config: Config) { init { config.apply { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/ProfileConfigMigration.kt b/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/ProfileConfigMigration.kt index dbfe8191..ba756105 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/ProfileConfigMigration.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/config/utils/ProfileConfigMigration.kt @@ -6,8 +6,8 @@ package pl.szczodrzynski.edziennik.config.utils import pl.szczodrzynski.edziennik.config.ProfileConfig import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.AGENDA_DEFAULT -import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.COLOR_MODE_WEIGHTED -import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.YEAR_ALL_GRADES +import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.COLOR_MODE_WEIGHTED +import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_ALL_GRADES class ProfileConfigMigration(config: ProfileConfig) { init { config.apply { @@ -21,4 +21,4 @@ class ProfileConfigMigration(config: ProfileConfig) { dataVersion = 1 } }} -} \ No newline at end of file +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebGrades.kt index 6e0caa2d..50557333 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebGrades.kt @@ -14,7 +14,12 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZI import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Grade -import pl.szczodrzynski.edziennik.data.db.entity.Grade.* +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_NORMAL +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_POINT_SUM +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_FINAL +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_PROPOSED +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_FINAL +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_PROPOSED import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS import pl.szczodrzynski.edziennik.get @@ -90,7 +95,7 @@ class EdudziennikWebGrades(override val data: DataEdudziennik, val columnName = info.child(4).text().trim() val comment = info.ownText() - val description = columnName + if (comment.isNotBlank()) " - $comment" else "" + val description = columnName + if (comment.isNotBlank()) " - $comment" else null val teacherName = info.child(1).text() val teacher = data.getTeacherByLastFirst(teacherName) @@ -109,20 +114,20 @@ class EdudziennikWebGrades(override val data: DataEdudziennik, } ?: -1 val gradeObject = Grade( - profileId, - id, - fullName, - color, - description, - name, - value, - if (gradeCountToAverage) weight else 0f, - semester, - teacher.id, - subject.id - ).apply { - type = gradeType - } + profileId = profileId, + id = id, + name = name, + type = gradeType, + value = value, + weight = if (gradeCountToAverage) weight else 0f, + color = color, + category = fullName, + description = description, + comment = null, + semester = semester, + teacherId = teacher.id, + subjectId = subject.id + ) data.gradeList.add(gradeObject) data.metadataList.add(Metadata( @@ -139,23 +144,23 @@ class EdudziennikWebGrades(override val data: DataEdudziennik, if (proposed != null && proposed.isNotBlank()) { val proposedGradeObject = Grade( - profileId, - (-1 * subject.id) - 1, - "", - -1, - "", - proposed, - proposed.toFloatOrNull() ?: 0f, - 0f, - semester, - -1, - subject.id - ).apply { - type = when (semester) { - 1 -> TYPE_SEMESTER1_PROPOSED - else -> TYPE_SEMESTER2_PROPOSED - } - } + profileId = profileId, + id = (-1 * subject.id) - 1, + name = proposed, + type = when (semester) { + 1 -> TYPE_SEMESTER1_PROPOSED + else -> TYPE_SEMESTER2_PROPOSED + }, + value = proposed.toFloatOrNull() ?: 0f, + weight = 0f, + color = -1, + category = null, + description = null, + comment = null, + semester = semester, + teacherId = -1, + subjectId = subject.id + ) data.gradeList.add(proposedGradeObject) data.metadataList.add(Metadata( @@ -172,23 +177,23 @@ class EdudziennikWebGrades(override val data: DataEdudziennik, if (final != null && final.isNotBlank()) { val finalGradeObject = Grade( - profileId, - (-1 * subject.id) - 2, - "", - -1, - "", - final, - final.toFloatOrNull() ?: 0f, - 0f, - semester, - -1, - subject.id - ).apply { - type = when (semester) { - 1 -> TYPE_SEMESTER1_FINAL - else -> TYPE_SEMESTER2_FINAL - } - } + profileId = profileId, + id = (-1 * subject.id) - 2, + name = final, + type = when (semester) { + 1 -> TYPE_SEMESTER1_FINAL + else -> TYPE_SEMESTER2_FINAL + }, + value = final.toFloatOrNull() ?: 0f, + weight = 0f, + color = -1, + category = null, + description = null, + comment = null, + semester = semester, + teacherId = -1, + subjectId = subject.id + ) data.gradeList.add(finalGradeObject) data.metadataList.add(Metadata( diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebGrades.kt index 67838070..b3237c82 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebGrades.kt @@ -14,6 +14,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Grade +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_NORMAL import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS import pl.szczodrzynski.edziennik.utils.models.Date @@ -63,17 +64,19 @@ class IdziennikWebGrades(override val data: DataIdziennik, } val gradeObject = Grade( - profileId, - id, - category, - colorInt, - "", - name, - value, - weight, - semester, - teacher.id, - subject.id) + profileId = profileId, + id = id, + name = name, + type = TYPE_NORMAL, + value = value, + weight = weight, + color = colorInt, + category = category, + description = null, + comment = null, + semester = semester, + teacherId = teacher.id, + subjectId = subject.id) when (grade.getInt("Typ")) { 0 -> { @@ -98,17 +101,19 @@ class IdziennikWebGrades(override val data: DataIdziennik, } val historyObject = Grade( - profileId, - gradeObject.id * -1, - historyItem.get("Kategoria").asString, - colorInt, - historyItem.get("Uzasadnienie").asString, - historyItem.get("Ocena").asString, - value, - if (value > 0f && countToTheAverage) weight * -1f else 0f, - historyItem.get("Semestr").asInt, - teacher.id, - subject.id) + profileId = profileId, + id = gradeObject.id * -1, + name = historyItem.getString("Ocena") ?: "", + type = TYPE_NORMAL, + value = value, + weight = if (value > 0f && countToTheAverage) weight * -1f else 0f, + color = colorInt, + category = historyItem.getString("Kategoria"), + description = historyItem.getString("Uzasadnienie"), + comment = null, + semester = historyItem.getInt("Semestr") ?: 1, + teacherId = teacher.id, + subjectId = subject.id) historyObject.parentId = gradeObject.id val addedDate = historyItem.getString("Data_wystaw")?.let { Date.fromY_m_d(it).inMillis } ?: System.currentTimeMillis() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebProposedGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebProposedGrades.kt index 1e681ea1..fe5a0156 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebProposedGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebProposedGrades.kt @@ -13,8 +13,8 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Grade -import pl.szczodrzynski.edziennik.data.db.entity.Grade.TYPE_SEMESTER1_PROPOSED -import pl.szczodrzynski.edziennik.data.db.entity.Grade.TYPE_YEAR_PROPOSED +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_PROPOSED +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_PROPOSED import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS import pl.szczodrzynski.edziennik.getJsonArray @@ -54,20 +54,20 @@ class IdziennikWebProposedGrades(override val data: DataIdziennik, if (semester1Proposed != "") { val gradeObject = Grade( - profileId, - semester1Id, - "", - -1, - "", - semester1Value.toString(), - semester1Value.toFloat(), - 0f, - 1, - -1, - subjectObject.id - ).apply { - type = TYPE_SEMESTER1_PROPOSED - } + profileId = profileId, + id = semester1Id, + name = semester1Value.toString(), + type = TYPE_SEMESTER1_PROPOSED, + value = semester1Value.toFloat(), + weight = 0f, + color = -1, + category = null, + description = null, + comment = null, + semester = 1, + teacherId = -1, + subjectId = subjectObject.id + ) data.gradeList.add(gradeObject) data.metadataList.add(Metadata( @@ -82,20 +82,20 @@ class IdziennikWebProposedGrades(override val data: DataIdziennik, if (semester2Proposed != "") { val gradeObject = Grade( - profileId, - semester2Id, - "", - -1, - "", - semester2Value.toString(), - semester2Value.toFloat(), - 0f, - 2, - -1, - subjectObject.id - ).apply { - type = TYPE_YEAR_PROPOSED - } + profileId = profileId, + id = semester2Id, + name = semester2Value.toString(), + type = TYPE_YEAR_PROPOSED, + value = semester2Value.toFloat(), + weight = 0f, + color = -1, + category = null, + description = null, + comment = null, + semester = 2, + teacherId = -1, + subjectId = subjectObject.id + ) val addedDate = if (data.profile.empty) data.profile.dateSemester1Start.inMillis diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiBehaviourGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiBehaviourGrades.kt index 16c2b544..fc36fe07 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiBehaviourGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiBehaviourGrades.kt @@ -10,6 +10,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Grade +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_POINT_SUM import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS @@ -31,18 +32,20 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus, if (data.startPointsSemester1 > 0) { val semester1StartGradeObject = Grade( - profileId, - -101, - data.app.getString(R.string.grade_start_points), - 0xffbdbdbd.toInt(), - data.app.getString(R.string.grade_start_points_format, 1), - nameFormat.format(data.startPointsSemester1), - data.startPointsSemester1.toFloat(), - -1f, - 1, - -1, - 1 - ).apply { type = Grade.TYPE_POINT_SUM } + profileId = profileId, + id = -101, + name = nameFormat.format(data.startPointsSemester1), + type = TYPE_POINT_SUM, + value = data.startPointsSemester1.toFloat(), + weight = 0f, + color = 0xffbdbdbd.toInt(), + category = data.app.getString(R.string.grade_start_points), + description = data.app.getString(R.string.grade_start_points_format, 1), + comment = null, + semester = 1, + teacherId = -1, + subjectId = 1 + ) data.gradeList.add(semester1StartGradeObject) data.metadataList.add(Metadata( @@ -57,18 +60,20 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus, if (data.startPointsSemester2 > 0) { val semester2StartGradeObject = Grade( - profileId, - -102, - data.app.getString(R.string.grade_start_points), - 0xffbdbdbd.toInt(), - data.app.getString(R.string.grade_start_points_format, 2), - nameFormat.format(data.startPointsSemester2), - data.startPointsSemester2.toFloat(), - -1f, - 2, - -1, - 1 - ).apply { type = Grade.TYPE_POINT_SUM } + profileId = profileId, + id = -102, + name = nameFormat.format(data.startPointsSemester2), + type = TYPE_POINT_SUM, + value = data.startPointsSemester2.toFloat(), + weight = -1f, + color = 0xffbdbdbd.toInt(), + category = data.app.getString(R.string.grade_start_points), + description = data.app.getString(R.string.grade_start_points_format, 2), + comment = null, + semester = 2, + teacherId = -1, + subjectId = 1 + ) data.gradeList.add(semester2StartGradeObject) data.metadataList.add(Metadata( @@ -123,19 +128,20 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus, val valueTo = category?.valueTo ?: 0f val gradeObject = Grade( - profileId, - id, - categoryName, - color, - description, - name, - valueFrom, - -1f, - semester, - teacherId, - 1 + profileId = profileId, + id = id, + name = name, + type = TYPE_POINT_SUM, + value = valueFrom, + weight = -1f, + color = color, + category = categoryName, + description = description, + comment = null, + semester = semester, + teacherId = teacherId, + subjectId = 1 ).apply { - type = Grade.TYPE_POINT_SUM valueMax = valueTo } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiDescriptiveGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiDescriptiveGrades.kt index 413a9235..42e318e0 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiDescriptiveGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiDescriptiveGrades.kt @@ -10,8 +10,8 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Grade -import pl.szczodrzynski.edziennik.data.db.entity.Grade.TYPE_DESCRIPTIVE_TEXT -import pl.szczodrzynski.edziennik.data.db.entity.Grade.TYPE_TEXT +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_DESCRIPTIVE_TEXT +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_TEXT import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS @@ -53,20 +53,20 @@ class LibrusApiDescriptiveGrades(override val data: DataLibrus, val addedDate = Date.fromIso(grade.getString("AddDate") ?: return@forEach) val gradeObject = Grade( - profileId, - id, - category?.text ?: "", - category?.color ?: -1, - description, - " ", - 0f, - 0f, - semester, - teacherId, - subjectId - ).apply { - this.type = type - } + profileId = profileId, + id = id, + name = " ", + type = type, + value = 0f, + weight = 0f, + color = category?.color ?: -1, + category = category?.text, + description = description, + comment = null, + semester = semester, + teacherId = teacherId, + subjectId = subjectId + ) data.gradeList.add(gradeObject) data.metadataList.add(Metadata( diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiGrades.kt index 95140988..7ff42fde 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiGrades.kt @@ -6,7 +6,13 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Grade -import pl.szczodrzynski.edziennik.data.db.entity.Grade.* +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_NORMAL +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_FINAL +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_PROPOSED +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_FINAL +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_PROPOSED +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_FINAL +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_PROPOSED import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS @@ -54,32 +60,28 @@ class LibrusApiGrades(override val data: DataLibrus, } ?: "" val gradeObject = Grade( - profileId, - id, - category?.text ?: "", - category?.color ?: -1, - description, - name, - value, - weight, - semester, - teacherId, - subjectId + profileId = profileId, + id = id, + name = name, + type = when { + grade.getBoolean("IsConstituent") ?: false -> TYPE_NORMAL + grade.getBoolean("IsSemester") ?: false -> if (semester == 1) TYPE_SEMESTER1_FINAL else TYPE_SEMESTER2_FINAL + grade.getBoolean("IsSemesterProposition") ?: false -> if (semester == 1) TYPE_SEMESTER1_PROPOSED else TYPE_SEMESTER2_PROPOSED + grade.getBoolean("IsFinal") ?: false -> TYPE_YEAR_FINAL + grade.getBoolean("IsFinalProposition") ?: false -> TYPE_YEAR_PROPOSED + else -> TYPE_NORMAL + }, + value = value, + weight = weight, + color = category?.color ?: -1, + category = category?.text ?: "", + description = description, + comment = null, + semester = semester, + teacherId = teacherId, + subjectId = subjectId ) - when { - grade.getBoolean("IsConstituent") ?: false -> - gradeObject.type = TYPE_NORMAL - grade.getBoolean("IsSemester") ?: false -> // semester final - gradeObject.type = if (gradeObject.semester == 1) TYPE_SEMESTER1_FINAL else TYPE_SEMESTER2_FINAL - grade.getBoolean("IsSemesterProposition") ?: false -> // semester proposed - gradeObject.type = if (gradeObject.semester == 1) TYPE_SEMESTER1_PROPOSED else TYPE_SEMESTER2_PROPOSED - grade.getBoolean("IsFinal") ?: false -> // year final - gradeObject.type = TYPE_YEAR_FINAL - grade.getBoolean("IsFinalProposition") ?: false -> // year final - gradeObject.type = TYPE_YEAR_PROPOSED - } - grade.getJsonObject("Improvement")?.also { val historicalId = it.getLong("Id") data.gradeList.firstOrNull { grade -> grade.id == historicalId }?.also { grade -> diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiPointGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiPointGrades.kt index 613e69ce..fae45318 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiPointGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiPointGrades.kt @@ -10,7 +10,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Grade -import pl.szczodrzynski.edziennik.data.db.entity.Grade.TYPE_POINT_AVG +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_POINT_AVG import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS @@ -44,19 +44,20 @@ class LibrusApiPointGrades(override val data: DataLibrus, val addedDate = Date.fromIso(grade.getString("AddDate") ?: return@forEach) val gradeObject = Grade( - profileId, - id, - category?.text ?: "", - category?.color ?: -1, - "", - name, - value, - category?.weight ?: 0f, - semester, - teacherId, - subjectId + profileId = profileId, + id = id, + name = name, + type = TYPE_POINT_AVG, + value = value, + weight = category?.weight ?: 0f, + color = category?.color ?: -1, + category = category?.text ?: "", + description = null, + comment = null, + semester = semester, + teacherId = teacherId, + subjectId = subjectId ).apply { - type = TYPE_POINT_AVG valueMax = category?.valueTo ?: 0f } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiTextGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiTextGrades.kt index ec7e17bd..902e89d1 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiTextGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/data/api/LibrusApiTextGrades.kt @@ -10,7 +10,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Grade -import pl.szczodrzynski.edziennik.data.db.entity.Grade.TYPE_DESCRIPTIVE +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_DESCRIPTIVE import pl.szczodrzynski.edziennik.data.db.entity.GradeCategory import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS @@ -48,20 +48,20 @@ class LibrusApiTextGrades(override val data: DataLibrus, val addedDate = Date.fromIso(grade.getString("AddDate") ?: return@forEach) val gradeObject = Grade( - profileId, - id, - category?.text ?: "", - category?.color ?: -1, - description, - name, - 0f, - 0f, - semester, - teacherId, - subjectId - ).apply { - type = TYPE_DESCRIPTIVE - } + profileId = profileId, + id = id, + name = name, + type = TYPE_DESCRIPTIVE, + value = 0f, + weight = 0f, + color = category?.color ?: -1, + category = category?.text ?: "", + description = description, + comment = null, + semester = semester, + teacherId = teacherId, + subjectId = subjectId + ) data.gradeList.add(gradeObject) data.metadataList.add(Metadata( diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiGrades.kt index 6bd7fb57..609c895c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/api/MobidziennikApiGrades.kt @@ -7,7 +7,13 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.api import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidziennik import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Grade -import pl.szczodrzynski.edziennik.data.db.entity.Grade.* +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_NORMAL +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_FINAL +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_PROPOSED +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_FINAL +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_PROPOSED +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_FINAL +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_PROPOSED import pl.szczodrzynski.edziennik.data.db.entity.Metadata class MobidziennikApiGrades(val data: DataMobidziennik, rows: List) { @@ -61,18 +67,19 @@ class MobidziennikApiGrades(val data: DataMobidziennik, rows: List) { } val gradeObject = Grade( - data.profileId, - id, - category, - color, - description, - name, - value, - weight, - semester, - teacherId, - subjectId) - gradeObject.type = type + profileId = data.profileId, + id = id, + name = name, + type = type, + value = value, + weight = weight, + color = color, + category = category, + description = description, + comment = null, + semester = semester, + teacherId = teacherId, + subjectId = subjectId) if (data.profile?.empty == true) { addedDate = data.profile.dateSemester1Start.inMillis diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebGrades.kt index 2922815b..de058c91 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/mobidziennik/data/web/MobidziennikWebGrades.kt @@ -11,6 +11,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidzienn import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.ENDPOINT_MOBIDZIENNIK_WEB_GRADES import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.MobidziennikWeb import pl.szczodrzynski.edziennik.data.db.entity.Grade +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_NORMAL import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS import pl.szczodrzynski.edziennik.fixWhiteSpaces @@ -112,17 +113,19 @@ class MobidziennikWebGrades(override val data: DataMobidziennik, } val gradeObject = Grade( - profileId, - gradeId, - gradeCategory, - gradeColor, - "NLDŚR, $gradeDescription", - gradeName, - gradeValue, - 0f, - gradeSemester, - teacherId, - subjectId + profileId = profileId, + id = gradeId, + name = gradeName, + type = TYPE_NORMAL, + value = gradeValue, + weight = 0f, + color = gradeColor, + category = gradeCategory, + description = "NLDŚR, $gradeDescription", + comment = null, + semester = gradeSemester, + teacherId = teacherId, + subjectId = subjectId ) gradeObject.classAverage = gradeClassAverage diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/api/VulcanApiGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/api/VulcanApiGrades.kt index e6b939d0..f62778fc 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/api/VulcanApiGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/api/VulcanApiGrades.kt @@ -11,6 +11,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_API_ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanApi import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.db.entity.Grade +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_NORMAL import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS import java.text.DecimalFormat @@ -88,17 +89,19 @@ class VulcanApiGrades(override val data: DataVulcan, }.toInt() val gradeObject = Grade( - profileId, - id, - category, - color, - finalDescription, - name, - value ?: 0.0f, - weight, - data.studentSemesterNumber, - teacherId, - subjectId + profileId = profileId, + id = id, + name = name, + type = TYPE_NORMAL, + value = value ?: 0.0f, + weight = weight, + color = color, + category = category, + description = finalDescription, + comment = null, + semester = data.studentSemesterNumber, + teacherId = teacherId, + subjectId = subjectId ) data.gradeList.add(gradeObject) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/api/VulcanApiProposedGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/api/VulcanApiProposedGrades.kt index e5c73cae..ee1e250f 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/api/VulcanApiProposedGrades.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/vulcan/data/api/VulcanApiProposedGrades.kt @@ -8,6 +8,10 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_API_GRADES_SUMMARY import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanApi import pl.szczodrzynski.edziennik.data.db.entity.Grade +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_FINAL +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_PROPOSED +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_FINAL +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_PROPOSED import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.getJsonArray import pl.szczodrzynski.edziennik.getJsonObject @@ -53,23 +57,25 @@ class VulcanApiProposedGrades(override val data: DataVulcan, val color = Utils.getVulcanGradeColor(name) val gradeObject = Grade( - profileId, - id, - "", - color, - "", - name, - value, - 0f, - data.studentSemesterNumber, - -1, - subjectId + profileId = profileId, + id = id, + name = name, + type = if (data.studentSemesterNumber == 1) { + if (isFinal) TYPE_SEMESTER1_FINAL else TYPE_SEMESTER1_PROPOSED + } else { + if (isFinal) TYPE_SEMESTER2_FINAL else TYPE_SEMESTER2_PROPOSED + }, + value = value, + weight = 0f, + color = color, + category = "", + description = null, + comment = null, + semester = data.studentSemesterNumber, + teacherId = -1, + subjectId = subjectId ) - if (data.studentSemesterNumber == 1) { - gradeObject.type = if (isFinal) Grade.TYPE_SEMESTER1_FINAL else Grade.TYPE_SEMESTER1_PROPOSED - } else { - gradeObject.type = if (isFinal) Grade.TYPE_SEMESTER2_FINAL else Grade.TYPE_SEMESTER2_PROPOSED - } + data.gradeList.add(gradeObject) data.metadataList.add(Metadata( profileId, diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/AppDb.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/AppDb.kt index 8d521e83..57f9a40c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/AppDb.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/AppDb.kt @@ -42,7 +42,7 @@ import pl.szczodrzynski.edziennik.data.db.migration.* ConfigEntry::class, LibrusLesson::class, Metadata::class -], version = 77) +], version = 78) @TypeConverters( ConverterTime::class, ConverterDate::class, @@ -160,7 +160,8 @@ abstract class AppDb : RoomDatabase() { Migration74(), Migration75(), Migration76(), - Migration77() + Migration77(), + Migration78() ).allowMainThreadQueries().build() } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/MetadataDao.java b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/MetadataDao.java index 4e8d0700..845941de 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/MetadataDao.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/dao/MetadataDao.java @@ -63,8 +63,8 @@ public abstract class MetadataDao { @Transaction public void setSeen(int profileId, Object o, boolean seen) { if (o instanceof Grade) { - if (add(new Metadata(profileId, TYPE_GRADE, ((Grade) o).id, seen, false, 0)) == -1) { - updateSeen(profileId, TYPE_GRADE, ((Grade) o).id, seen); + if (add(new Metadata(profileId, TYPE_GRADE, ((Grade) o).getId(), seen, false, 0)) == -1) { + updateSeen(profileId, TYPE_GRADE, ((Grade) o).getId(), seen); } } if (o instanceof Attendance) { @@ -102,8 +102,8 @@ public abstract class MetadataDao { @Transaction public void setNotified(int profileId, Object o, boolean notified) { if (o instanceof Grade) { - if (add(new Metadata(profileId, TYPE_GRADE, ((Grade) o).id, false, notified, 0)) == -1) { - updateNotified(profileId, TYPE_GRADE, ((Grade) o).id, notified); + if (add(new Metadata(profileId, TYPE_GRADE, ((Grade) o).getId(), false, notified, 0)) == -1) { + updateNotified(profileId, TYPE_GRADE, ((Grade) o).getId(), notified); } } if (o instanceof Attendance) { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Grade.java b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Grade.java deleted file mode 100644 index 9d534e83..00000000 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Grade.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) Kacper Ziubryniewicz 2020-1-6 - */ - -package pl.szczodrzynski.edziennik.data.db.entity; - -import androidx.room.ColumnInfo; -import androidx.room.Entity; -import androidx.room.Ignore; -import androidx.room.Index; - -@Entity(tableName = "grades", - primaryKeys = {"profileId", "gradeId"}, - indices = {@Index(value = {"profileId"})}) -public class Grade { - public int profileId; - - @ColumnInfo(name = "gradeId") - public long id; - - @ColumnInfo(name = "gradeCategory") - public String category; - @ColumnInfo(name = "gradeColor") - public int color; - @ColumnInfo(name = "gradeDescription") - public String description; - @ColumnInfo(name = "gradeComment") - public String comment; - @ColumnInfo(name = "gradeName") - public String name; - @ColumnInfo(name = "gradeValue") - public float value; - @ColumnInfo(name = "gradeValueMax") - public float valueMax; - @ColumnInfo(name = "gradeWeight") - public float weight; - @ColumnInfo(name = "gradeSemester") - public int semester; - @ColumnInfo(name = "gradeClassAverage") - public float classAverage = -1; - public static final int TYPE_NORMAL = 0; - public static final int TYPE_SEMESTER1_PROPOSED = 1; - public static final int TYPE_SEMESTER1_FINAL = 2; - public static final int TYPE_SEMESTER2_PROPOSED = 3; - public static final int TYPE_SEMESTER2_FINAL = 4; - public static final int TYPE_YEAR_PROPOSED = 5; - public static final int TYPE_YEAR_FINAL = 6; - public static final int TYPE_POINT_AVG = 10; - public static final int TYPE_POINT_SUM = 20; - public static final int TYPE_DESCRIPTIVE = 30; - public static final int TYPE_DESCRIPTIVE_TEXT = 31; - public static final int TYPE_TEXT = 40; - @ColumnInfo(name = "gradeType") - public int type = TYPE_NORMAL; - @ColumnInfo(name = "gradePointGrade") - public boolean pointGrade = false; - - /** - * Applies for historical grades. It's the new/replacement grade's ID. - */ - @ColumnInfo(name = "gradeParentId") - public long parentId = -1; - - /** - * Applies for current grades. If the grade was worse and this is the improved one. - */ - @ColumnInfo(name = "gradeIsImprovement") - public boolean isImprovement = false; - - public long teacherId; - public long subjectId; - - @Ignore - public Grade() {} - - public Grade(int profileId, long id, String category, int color, String description, String name, float value, float weight, int semester, long teacherId, long subjectId) { - this.profileId = profileId; - this.id = id; - this.category = category; - this.color = color; - this.description = description; - this.name = name; - this.value = value; - this.weight = weight; - this.semester = semester; - this.teacherId = teacherId; - this.subjectId = subjectId; - } - - /*@Ignore - public Grade(int profileId, long id, String description, String name, float value, float weight, int semester, long teacherId, long categoryId, long subjectId) { - this.profileId = profileId; - this.id = id; - this.description = description; - this.name = name; - this.value = value; - this.weight = weight; - this.semester = semester; - this.teacherId = teacherId; - //this.categoryId = categoryId; - this.subjectId = subjectId; - }*/ -} - diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Grade.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Grade.kt new file mode 100644 index 00000000..bed7a191 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Grade.kt @@ -0,0 +1,85 @@ +/* + * Copyright (c) Kacper Ziubryniewicz 2020-1-6 + */ +package pl.szczodrzynski.edziennik.data.db.entity + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.Index + +/*public Grade(int profileId, long id, String category, int color, String description, String name, float value, float weight, int semester, long teacherId, long subjectId) { + this.profileId = profileId; + this.id = id; + this.category = category; + this.color = color; + this.description = description; + this.name = name; + this.value = value; + this.weight = weight; + this.semester = semester; + this.teacherId = teacherId; + this.subjectId = subjectId; + }*/ + +@Entity(tableName = "grades", + primaryKeys = ["profileId", "gradeId"], + indices = [Index(value = ["profileId"])]) +open class Grade( + val profileId: Int, + @ColumnInfo(name = "gradeId") + val id: Long, + @ColumnInfo(name = "gradeName") + var name: String, + @ColumnInfo(name = "gradeType") + var type: Int, + + @ColumnInfo(name = "gradeValue") + var value: Float, + @ColumnInfo(name = "gradeWeight") + var weight: Float, + @ColumnInfo(name = "gradeColor") + var color: Int, + @ColumnInfo(name = "gradeCategory") + var category: String?, + @ColumnInfo(name = "gradeDescription") + var description: String?, + @ColumnInfo(name = "gradeComment") + var comment: String?, + + @ColumnInfo(name = "gradeSemester") + val semester: Int, + val teacherId: Long, + val subjectId: Long +) { + companion object { + const val TYPE_NORMAL = 0 + const val TYPE_SEMESTER1_PROPOSED = 1 + const val TYPE_SEMESTER1_FINAL = 2 + const val TYPE_SEMESTER2_PROPOSED = 3 + const val TYPE_SEMESTER2_FINAL = 4 + const val TYPE_YEAR_PROPOSED = 5 + const val TYPE_YEAR_FINAL = 6 + const val TYPE_POINT_AVG = 10 + const val TYPE_POINT_SUM = 20 + const val TYPE_DESCRIPTIVE = 30 + const val TYPE_DESCRIPTIVE_TEXT = 31 + const val TYPE_TEXT = 40 + } + + @ColumnInfo(name = "gradeValueMax") + var valueMax: Float? = null + @ColumnInfo(name = "gradeClassAverage") + var classAverage: Float? = null + + /** + * Applies for historical grades. It's the new/replacement grade's ID. + */ + @ColumnInfo(name = "gradeParentId") + var parentId: Long? = null + /** + * Applies for current grades. If the grade was worse and this is the improved one. + */ + @ColumnInfo(name = "gradeIsImprovement") + var isImprovement = false +} + diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Profile.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Profile.kt index 7d9b7b8a..61777a8d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Profile.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/entity/Profile.kt @@ -53,15 +53,8 @@ open class Profile( const val REGISTRATION_UNSPECIFIED = 0 const val REGISTRATION_DISABLED = 1 const val REGISTRATION_ENABLED = 2 - const val COLOR_MODE_DEFAULT = 0 - const val COLOR_MODE_WEIGHTED = 1 const val AGENDA_DEFAULT = 0 const val AGENDA_CALENDAR = 1 - const val YEAR_1_AVG_2_AVG = 0 - const val YEAR_1_SEM_2_AVG = 1 - const val YEAR_1_AVG_2_SEM = 2 - const val YEAR_1_SEM_2_SEM = 3 - const val YEAR_ALL_GRADES = 4 } override var image: String? = null diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/full/GradeFull.java b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/full/GradeFull.java deleted file mode 100644 index 8a44157b..00000000 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/full/GradeFull.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) Kacper Ziubryniewicz 2020-1-6 - */ - -package pl.szczodrzynski.edziennik.data.db.full; - -import pl.szczodrzynski.edziennik.data.db.entity.Grade; - -public class GradeFull extends Grade { - //public String category = ""; - //public int color; - - public String subjectLongName = ""; - public String subjectShortName = ""; - - public String teacherFullName = ""; - - // metadata - public boolean seen; - public boolean notified; - public long addedDate; -} - diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/full/GradeFull.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/full/GradeFull.kt new file mode 100644 index 00000000..8cc80974 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/full/GradeFull.kt @@ -0,0 +1,26 @@ +/* + * Copyright (c) Kacper Ziubryniewicz 2020-1-6 + */ +package pl.szczodrzynski.edziennik.data.db.full + +import pl.szczodrzynski.edziennik.data.db.entity.Grade + +class GradeFull( + profileId: Int, id: Long, name: String, type: Int, + value: Float, weight: Float, color: Int, + category: String?, description: String?, comment: String?, + semester: Int, teacherId: Long, subjectId: Long +) : Grade( + profileId, id, name, type, + value, weight, color, + category, description, comment, + semester, teacherId, subjectId +) { + var subjectLongName: String? = null + var subjectShortName: String? = null + var teacherFullName: String? = null + // metadata + var seen = false + var notified = false + var addedDate: Long = 0 +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration78.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration78.kt new file mode 100644 index 00000000..584472fd --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/migration/Migration78.kt @@ -0,0 +1,44 @@ +package pl.szczodrzynski.edziennik.data.db.migration + +import androidx.room.migration.Migration +import androidx.sqlite.db.SupportSQLiteDatabase + +class Migration78 : Migration(77, 78) { + override fun migrate(database: SupportSQLiteDatabase) { + // grades migration to kotlin + database.execSQL("ALTER TABLE grades RENAME TO _grades;") + database.execSQL("""CREATE TABLE grades ( + profileId INTEGER NOT NULL, + gradeId INTEGER NOT NULL, + gradeName TEXT NOT NULL, + gradeType INTEGER NOT NULL, + gradeValue REAL NOT NULL, + gradeWeight REAL NOT NULL, + gradeColor INTEGER NOT NULL, + gradeCategory TEXT, + gradeDescription TEXT, + gradeComment TEXT, + gradeSemester INTEGER NOT NULL, + teacherId INTEGER NOT NULL, + subjectId INTEGER NOT NULL, + gradeValueMax REAL DEFAULT NULL, + gradeClassAverage REAL DEFAULT NULL, + gradeParentId INTEGER DEFAULT NULL, + gradeIsImprovement INTEGER NOT NULL, + PRIMARY KEY(profileId, gradeId) + );""") + database.execSQL("DROP INDEX IF EXISTS index_grades_profileId;") + database.execSQL("CREATE INDEX index_grades_profileId ON grades (profileId);") + database.execSQL("""INSERT INTO grades (profileId, gradeId, gradeName, gradeType, gradeValue, gradeWeight, gradeColor, gradeCategory, gradeDescription, gradeComment, gradeSemester, teacherId, subjectId, gradeValueMax, gradeClassAverage, gradeParentId, gradeIsImprovement) + SELECT profileId, gradeId, gradeName, gradeType, gradeValue, gradeWeight, gradeColor, + CASE gradeCategory WHEN '' THEN NULL WHEN ' ' THEN NULL ELSE gradeCategory END, + CASE gradeDescription WHEN '' THEN NULL WHEN ' ' THEN NULL ELSE gradeDescription END, + CASE gradeComment WHEN '' THEN NULL WHEN ' ' THEN NULL ELSE gradeComment END, + gradeSemester, teacherId, subjectId, + CASE gradeValueMax WHEN 0 THEN NULL ELSE gradeValueMax END, + CASE gradeClassAverage WHEN -1 THEN NULL ELSE gradeClassAverage END, + CASE gradeParentId WHEN -1 THEN NULL ELSE gradeParentId END, + gradeIsImprovement FROM _grades;""") + database.execSQL("DROP TABLE _grades;") + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradeDetailsDialog.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradeDetailsDialog.java deleted file mode 100644 index 04844644..00000000 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradeDetailsDialog.java +++ /dev/null @@ -1,129 +0,0 @@ -package pl.szczodrzynski.edziennik.ui.dialogs.grade; - -import android.content.Context; -import android.content.DialogInterface; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; -import android.os.AsyncTask; -import android.view.View; - -import androidx.core.graphics.ColorUtils; -import androidx.recyclerview.widget.LinearLayoutManager; - -import com.afollestad.materialdialogs.MaterialDialog; - -import java.text.DecimalFormat; -import java.util.List; - -import pl.szczodrzynski.edziennik.App; -import pl.szczodrzynski.edziennik.R; -import pl.szczodrzynski.edziennik.data.db.entity.Grade; -import pl.szczodrzynski.edziennik.data.db.full.GradeFull; -import pl.szczodrzynski.edziennik.databinding.DialogGradeDetailsBinding; -import pl.szczodrzynski.edziennik.ui.modules.grades.GradesListAdapter; -import pl.szczodrzynski.edziennik.utils.Colors; - -import static pl.szczodrzynski.edziennik.data.db.entity.Profile.COLOR_MODE_DEFAULT; - -public class GradeDetailsDialog { - private App app; - private Context context; - private int profileId; - - public GradeDetailsDialog(Context context) { - this.context = context; - this.profileId = App.Companion.getProfileId(); - } - public GradeDetailsDialog(Context context, int profileId) { - this.context = context; - this.profileId = profileId; - } - - public MaterialDialog dialog; - private DialogGradeDetailsBinding b; - private DialogInterface.OnDismissListener dismissListener; - public boolean callDismissListener = true; - - public GradeDetailsDialog withDismissListener(DialogInterface.OnDismissListener dismissListener) { - this.dismissListener = dismissListener; - return this; - } - public void performDismiss(DialogInterface dialogInterface) { - if (callDismissListener && dismissListener != null) { - dismissListener.onDismiss(dialogInterface); - } - callDismissListener = true; - } - - public void show(App _app, GradeFull grade) - { - this.app = _app; - dialog = new MaterialDialog.Builder(context) - .customView(R.layout.dialog_grade_details, true) - .positiveText(R.string.close) - .autoDismiss(false) - .onPositive((dialog, which) -> dialog.dismiss()) - .dismissListener(this::performDismiss) - .show(); - - View root = dialog.getCustomView(); - assert root != null; - - b = DialogGradeDetailsBinding.bind(root); - - b.setGrade(grade); - - int gradeColor; - if (App.Companion.getConfig().getFor(profileId).getGrades().getColorMode() == COLOR_MODE_DEFAULT) { - gradeColor = grade.color; - } - else { - gradeColor = Colors.gradeToColor(grade); - } - - DecimalFormat format = new DecimalFormat("#.##"); - if (grade.weight < 0) { - grade.weight *= -1; - } - if (grade.type == Grade.TYPE_DESCRIPTIVE || grade.type == Grade.TYPE_DESCRIPTIVE_TEXT || grade.type == Grade.TYPE_TEXT || grade.type == Grade.TYPE_POINT_SUM) { - b.setWeightText(null); - grade.weight = 0; - } - else { - if (grade.type == Grade.TYPE_POINT_AVG) { - b.setWeightText(app.getString(R.string.grades_max_points_format, format.format(grade.valueMax))); - } - else if (grade.weight == 0) { - b.setWeightText(app.getString(R.string.grades_weight_not_counted)); - } - else { - b.setWeightText(app.getString(R.string.grades_weight_format, format.format(grade.weight))); - } - } - - b.setCommentVisible(false); - - b.setDevMode(App.Companion.getDevMode()); - - b.gradeName.setTextColor(ColorUtils.calculateLuminance(gradeColor) > 0.3 ? 0xff000000 : 0xffffffff); - b.gradeName.getBackground().setColorFilter(new PorterDuffColorFilter(gradeColor, PorterDuff.Mode.MULTIPLY)); - - AsyncTask.execute(() -> { - - List historyList = app.db.gradeDao().getAllWithParentIdNow(profileId, grade.id); - - if (historyList.size() == 0) { - b.setHistoryVisible(false); - return; - } - b.setHistoryVisible(true); - b.gradeHistoryNest.post(() -> { - b.gradeHistoryNest.setNestedScrollingEnabled(false); - b.gradeHistoryList.setHasFixedSize(false); - b.gradeHistoryList.setNestedScrollingEnabled(false); - b.gradeHistoryList.setLayoutManager(new LinearLayoutManager(context)); - b.gradeHistoryList.setAdapter(new GradesListAdapter(context, historyList)); - }); - }); - } -} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradeDetailsDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradeDetailsDialog.kt new file mode 100644 index 00000000..e2659164 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/grade/GradeDetailsDialog.kt @@ -0,0 +1,83 @@ +package pl.szczodrzynski.edziennik.ui.dialogs.grade + +import androidx.appcompat.app.AlertDialog +import androidx.appcompat.app.AppCompatActivity +import androidx.core.graphics.ColorUtils +import androidx.recyclerview.widget.LinearLayoutManager +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import kotlinx.coroutines.* +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.data.db.full.GradeFull +import pl.szczodrzynski.edziennik.databinding.DialogGradeDetailsBinding +import pl.szczodrzynski.edziennik.setTintColor +import pl.szczodrzynski.edziennik.ui.modules.grades.GradesAdapter +import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration +import kotlin.coroutines.CoroutineContext + +class GradeDetailsDialog( + val activity: AppCompatActivity, + val grade: GradeFull, + val onShowListener: ((tag: String) -> Unit)? = null, + val onDismissListener: ((tag: String) -> Unit)? = null +) : CoroutineScope { + companion object { + private const val TAG = "GradeDetailsDialog" + } + + private lateinit var app: App + private lateinit var b: DialogGradeDetailsBinding + private lateinit var dialog: AlertDialog + + private val job = Job() + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + + // local variables go here + + init { run { + if (activity.isFinishing) + return@run + onShowListener?.invoke(TAG) + app = activity.applicationContext as App + b = DialogGradeDetailsBinding.inflate(activity.layoutInflater) + dialog = MaterialAlertDialogBuilder(activity) + .setView(b.root) + .setPositiveButton(R.string.close, null) + .setOnDismissListener { + onDismissListener?.invoke(TAG) + } + .show() + val manager = app.gradesManager + + val gradeColor = manager.getColor(grade) + b.grade = grade + b.weightText = manager.getWeightString(app, grade) + b.commentVisible = false + b.devMode = App.debugMode + b.gradeName.setTextColor(if (ColorUtils.calculateLuminance(gradeColor) > 0.3) -0x1000000 else -0x1) + b.gradeName.background.setTintColor(gradeColor) + + b.gradeValue = if (grade.weight == 0f || grade.value < 0f) -1f else manager.getGradeValue(grade) + + launch { + val historyList = withContext(Dispatchers.Default) { + app.db.gradeDao().getAllWithParentIdNow(App.profileId, grade.id) + } + if (historyList.isEmpty()) { + b.historyVisible = false + return@launch + } + b.historyVisible = true + //b.gradeHistoryNest.isNestedScrollingEnabled = false + b.gradeHistoryList.adapter = GradesAdapter(activity, { + GradeDetailsDialog(activity, it) + }).also { it.items = historyList.toMutableList() } + b.gradeHistoryList.apply { + setHasFixedSize(true) + layoutManager = LinearLayoutManager(context) + addItemDecoration(SimpleDividerItemDecoration(context)) + } + } + }} +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/GradesConfigDialog.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/GradesConfigDialog.kt index 9a2c5c65..666dec3c 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/GradesConfigDialog.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/dialogs/settings/GradesConfigDialog.kt @@ -6,14 +6,20 @@ package pl.szczodrzynski.edziennik.ui.dialogs.settings import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.isVisible import com.google.android.material.dialog.MaterialAlertDialogBuilder -import pl.szczodrzynski.edziennik.App -import pl.szczodrzynski.edziennik.MainActivity -import pl.szczodrzynski.edziennik.R -import pl.szczodrzynski.edziennik.config.ConfigGrades -import pl.szczodrzynski.edziennik.data.db.entity.Profile +import it.sephiroth.android.library.numberpicker.doOnStopTrackingTouch +import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.databinding.DialogConfigGradesBinding -import pl.szczodrzynski.edziennik.setOnSelectedListener +import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.COLOR_MODE_DEFAULT +import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.COLOR_MODE_WEIGHTED +import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.ORDER_BY_DATE_DESC +import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.ORDER_BY_SUBJECT_ASC +import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_1_AVG_2_AVG +import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_1_AVG_2_SEM +import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_1_SEM_2_AVG +import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_1_SEM_2_SEM +import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_ALL_GRADES class GradesConfigDialog( val activity: AppCompatActivity, @@ -42,6 +48,7 @@ class GradesConfigDialog( .setView(b.root) .setPositiveButton(R.string.ok) { dialog, _ -> dialog.dismiss() } .setOnDismissListener { + saveConfig() onDismissListener?.invoke(TAG) if (reloadOnDismiss) (activity as? MainActivity)?.reloadTarget() } @@ -52,42 +59,71 @@ class GradesConfigDialog( }} private fun loadConfig() { + b.customPlusCheckBox.isChecked = profileConfig.plusValue != null + b.customPlusValue.isVisible = b.customPlusCheckBox.isChecked + b.customMinusCheckBox.isChecked = profileConfig.minusValue != null + b.customMinusValue.isVisible = b.customMinusCheckBox.isChecked + + b.customPlusValue.progress = profileConfig.plusValue ?: 0.5f + b.customMinusValue.progress = profileConfig.minusValue ?: 0.25f + when (config.orderBy) { - ConfigGrades.ORDER_BY_DATE_DESC -> b.sortGradesByDateRadio - ConfigGrades.ORDER_BY_SUBJECT_ASC -> b.sortGradesBySubjectRadio + ORDER_BY_DATE_DESC -> b.sortGradesByDateRadio + ORDER_BY_SUBJECT_ASC -> b.sortGradesBySubjectRadio else -> null }?.isChecked = true when (profileConfig.colorMode) { - Profile.COLOR_MODE_DEFAULT -> b.gradeColorFromERegister - Profile.COLOR_MODE_WEIGHTED -> b.gradeColorByValue + COLOR_MODE_DEFAULT -> b.gradeColorFromERegister + COLOR_MODE_WEIGHTED -> b.gradeColorByValue else -> null }?.isChecked = true when (profileConfig.yearAverageMode) { - Profile.YEAR_ALL_GRADES -> b.gradeAverageMode4 - Profile.YEAR_1_AVG_2_AVG -> b.gradeAverageMode0 - Profile.YEAR_1_SEM_2_AVG -> b.gradeAverageMode1 - Profile.YEAR_1_AVG_2_SEM -> b.gradeAverageMode2 - Profile.YEAR_1_SEM_2_SEM -> b.gradeAverageMode3 + YEAR_ALL_GRADES -> b.gradeAverageMode4 + YEAR_1_AVG_2_AVG -> b.gradeAverageMode0 + YEAR_1_SEM_2_AVG -> b.gradeAverageMode1 + YEAR_1_AVG_2_SEM -> b.gradeAverageMode2 + YEAR_1_SEM_2_SEM -> b.gradeAverageMode3 else -> null }?.isChecked = true b.dontCountZeroToAverage.isChecked = !profileConfig.countZeroToAvg } + private fun saveConfig() { + profileConfig.plusValue = if (b.customPlusCheckBox.isChecked) b.customPlusValue.progress else null + profileConfig.minusValue = if (b.customMinusCheckBox.isChecked) b.customMinusValue.progress else null + } + private fun initView() { - b.sortGradesByDateRadio.setOnSelectedListener { config.orderBy = ConfigGrades.ORDER_BY_DATE_DESC } - b.sortGradesBySubjectRadio.setOnSelectedListener { config.orderBy = ConfigGrades.ORDER_BY_SUBJECT_ASC } + b.customPlusCheckBox.onChange { _, isChecked -> + b.customPlusValue.isVisible = isChecked + } + b.customMinusCheckBox.onChange { _, isChecked -> + b.customMinusValue.isVisible = isChecked + } - b.gradeColorFromERegister.setOnSelectedListener { profileConfig.colorMode = Profile.COLOR_MODE_DEFAULT } - b.gradeColorByValue.setOnSelectedListener { profileConfig.colorMode = Profile.COLOR_MODE_WEIGHTED } + // who the hell named those methods + // THIS SHIT DOES NOT EVEN WORK + b.customPlusValue.doOnStopTrackingTouch { + profileConfig.plusValue = it.progress + } + b.customMinusValue.doOnStopTrackingTouch { + profileConfig.minusValue = it.progress + } - b.gradeAverageMode4.setOnSelectedListener { profileConfig.yearAverageMode = Profile.YEAR_ALL_GRADES } - b.gradeAverageMode0.setOnSelectedListener { profileConfig.yearAverageMode = Profile.YEAR_1_AVG_2_AVG } - b.gradeAverageMode1.setOnSelectedListener { profileConfig.yearAverageMode = Profile.YEAR_1_SEM_2_AVG } - b.gradeAverageMode2.setOnSelectedListener { profileConfig.yearAverageMode = Profile.YEAR_1_AVG_2_SEM } - b.gradeAverageMode3.setOnSelectedListener { profileConfig.yearAverageMode = Profile.YEAR_1_SEM_2_SEM } + b.sortGradesByDateRadio.setOnSelectedListener { config.orderBy = ORDER_BY_DATE_DESC } + b.sortGradesBySubjectRadio.setOnSelectedListener { config.orderBy = ORDER_BY_SUBJECT_ASC } + + b.gradeColorFromERegister.setOnSelectedListener { profileConfig.colorMode = COLOR_MODE_DEFAULT } + b.gradeColorByValue.setOnSelectedListener { profileConfig.colorMode = COLOR_MODE_WEIGHTED } + + b.gradeAverageMode4.setOnSelectedListener { profileConfig.yearAverageMode = YEAR_ALL_GRADES } + b.gradeAverageMode0.setOnSelectedListener { profileConfig.yearAverageMode = YEAR_1_AVG_2_AVG } + b.gradeAverageMode1.setOnSelectedListener { profileConfig.yearAverageMode = YEAR_1_SEM_2_AVG } + b.gradeAverageMode2.setOnSelectedListener { profileConfig.yearAverageMode = YEAR_1_AVG_2_SEM } + b.gradeAverageMode3.setOnSelectedListener { profileConfig.yearAverageMode = YEAR_1_SEM_2_SEM } b.dontCountZeroToAverage.setOnCheckedChangeListener { _, isChecked -> profileConfig.countZeroToAvg = !isChecked } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradeView.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradeView.kt new file mode 100644 index 00000000..682bedd1 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradeView.kt @@ -0,0 +1,118 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2020-3-1. + */ + +package pl.szczodrzynski.edziennik.ui.modules.grades + +import android.annotation.SuppressLint +import android.content.Context +import android.graphics.Typeface +import android.text.TextUtils +import android.util.AttributeSet +import android.util.TypedValue.COMPLEX_UNIT_SP +import android.view.Gravity +import android.view.View +import android.view.ViewGroup.LayoutParams.WRAP_CONTENT +import android.widget.LinearLayout +import androidx.appcompat.widget.AppCompatTextView +import androidx.core.graphics.ColorUtils +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.data.db.entity.Grade +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_FINAL +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_PROPOSED +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_FINAL +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_PROPOSED +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_FINAL +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_PROPOSED +import pl.szczodrzynski.edziennik.dp +import pl.szczodrzynski.edziennik.resolveAttr +import pl.szczodrzynski.edziennik.setTintColor +import pl.szczodrzynski.edziennik.utils.managers.GradesManager + +class GradeView : AppCompatTextView { + + @JvmOverloads + constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : super(context, attrs, defStyleAttr) + + constructor(context: Context, grade: Grade, manager: GradesManager, periodGradesTextual: Boolean = false) : this(context, null) { + setGrade(grade, manager, false, periodGradesTextual) + } + + @SuppressLint("RestrictedApi") + fun setGrade(grade: Grade?, manager: GradesManager, bigView: Boolean = false, periodGradesTextual: Boolean = false) { + if (grade == null) { + visibility = View.GONE + return + } + visibility = View.VISIBLE + + val gradeName = grade.name + + val gradeColor = manager.getColor(grade) + + text = if (periodGradesTextual) + when (grade.type) { + TYPE_SEMESTER1_PROPOSED, TYPE_SEMESTER2_PROPOSED -> context.getString( + R.string.grade_semester_proposed_format, + gradeName + ) + TYPE_SEMESTER1_FINAL, TYPE_SEMESTER2_FINAL -> context.getString( + R.string.grade_semester_final_format, + gradeName + ) + TYPE_YEAR_PROPOSED -> context.getString( + R.string.grade_year_proposed_format, + gradeName + ) + TYPE_YEAR_FINAL -> context.getString( + R.string.grade_year_final_format, + gradeName + ) + else -> gradeName + } + else + gradeName + + setTextColor(when (grade.type) { + TYPE_SEMESTER1_PROPOSED, + TYPE_SEMESTER2_PROPOSED, + TYPE_YEAR_PROPOSED -> android.R.attr.textColorPrimary.resolveAttr(context) + else -> if (ColorUtils.calculateLuminance(gradeColor) > 0.3) + 0x99000000.toInt() + else + 0x99ffffff.toInt() + }) + + typeface = Typeface.create("serif-monospace", Typeface.BOLD) + setBackgroundResource(when (grade.type) { + TYPE_SEMESTER1_PROPOSED, + TYPE_SEMESTER2_PROPOSED, + TYPE_YEAR_PROPOSED -> if (bigView) R.drawable.bg_rounded_8dp_outline else R.drawable.bg_rounded_4dp_outline + else -> if (bigView) R.drawable.bg_rounded_8dp else R.drawable.bg_rounded_4dp + }) + background.setTintColor(gradeColor) + gravity = Gravity.CENTER + + if (bigView) { + setTextSize(COMPLEX_UNIT_SP, 24f) + setAutoSizeTextTypeUniformWithConfiguration( + 14, + 32, + 1, + COMPLEX_UNIT_SP + ) + setPadding(2.dp, 2.dp, 2.dp, 2.dp) + } + else { + setTextSize(COMPLEX_UNIT_SP, 16f) + setPadding(5.dp, 0, 5.dp, 0) + layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { + setMargins(0, 0, 5.dp, 0) + } + maxLines = 1 + ellipsize = TextUtils.TruncateAt.END + measure(WRAP_CONTENT, WRAP_CONTENT) + } + } + +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesAdapter.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesAdapter.kt new file mode 100644 index 00000000..0aa92184 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesAdapter.kt @@ -0,0 +1,187 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2020-2-29. + */ + +package pl.szczodrzynski.edziennik.ui.modules.grades + +import android.animation.ObjectAnimator +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.recyclerview.widget.RecyclerView +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.data.db.entity.Grade +import pl.szczodrzynski.edziennik.data.db.full.GradeFull +import pl.szczodrzynski.edziennik.onClick +import pl.szczodrzynski.edziennik.ui.modules.grades.models.* +import pl.szczodrzynski.edziennik.ui.modules.grades.viewholder.* + +class GradesAdapter( + val activity: AppCompatActivity, + var onGradeClick: ((item: GradeFull) -> Unit)? = null, + var onGradesEditorClick: ((subjectId: Long, semesterNumber: Int) -> Unit)? = null +) : RecyclerView.Adapter() { + companion object { + private const val TAG = "GradesAdapter" + private const val ITEM_TYPE_SUBJECT = 0 + private const val ITEM_TYPE_SEMESTER = 1 + private const val ITEM_TYPE_EMPTY = 2 + private const val ITEM_TYPE_GRADE = 3 + private const val ITEM_TYPE_STATS = 4 + const val STATE_CLOSED = 0 + const val STATE_OPENED = 1 + } + + var items = mutableListOf() + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + val inflater = LayoutInflater.from(parent.context) + return when (viewType) { + ITEM_TYPE_SUBJECT -> SubjectViewHolder(inflater, parent) + ITEM_TYPE_SEMESTER -> SemesterViewHolder(inflater, parent) + ITEM_TYPE_EMPTY -> EmptyViewHolder(inflater, parent) + ITEM_TYPE_GRADE -> GradeViewHolder(inflater, parent) + ITEM_TYPE_STATS -> StatsViewHolder(inflater, parent) + else -> throw IllegalArgumentException("Incorrect viewType") + } + } + + override fun getItemViewType(position: Int): Int { + return when (items[position]) { + is GradesSubject -> ITEM_TYPE_SUBJECT + is GradesSemester -> ITEM_TYPE_SEMESTER + is GradesEmpty -> ITEM_TYPE_EMPTY + is Grade -> ITEM_TYPE_GRADE + is GradesStats -> ITEM_TYPE_STATS + else -> throw IllegalArgumentException("Incorrect viewType") + } + } + + private val onClickListener = View.OnClickListener { view -> + val model = view.getTag(R.string.tag_key_model) + if (model is GradeFull) { + onGradeClick?.invoke(model) + return@OnClickListener + } + if (model !is ExpandableItemModel<*>) + return@OnClickListener + val position = items.indexOf(model) + if (position == -1) + return@OnClickListener + //val position = it.getTag(R.string.tag_key_position) as? Int ?: return@OnClickListener + + if (model is GradesSubject || model is GradesSemester) { + view.findViewById(R.id.dropdownIcon)?.let { dropdownIcon -> + ObjectAnimator.ofFloat( + dropdownIcon, + View.ROTATION, + if (model.state == STATE_CLOSED) 0f else 180f, + if (model.state == STATE_CLOSED) 180f else 0f + ).setDuration(200).start(); + } + } + if (model is GradesSubject) { + val preview = view.findViewById(R.id.previewContainer) + val summary = view.findViewById(R.id.yearSummary) + preview?.visibility = if (model.state == STATE_CLOSED) View.INVISIBLE else View.VISIBLE + summary?.visibility = if (model.state == STATE_CLOSED) View.VISIBLE else View.INVISIBLE + } + + if (model.state == STATE_CLOSED) { + + val subItems = if (model is GradesSemester && model.grades.isEmpty()) + listOf(GradesEmpty()) + else + model.items + + model.state = STATE_OPENED + items.addAll(position + 1, subItems.filterNotNull()) + notifyItemRangeInserted(position + 1, subItems.size) + /*notifyItemRangeChanged( + position + subItems.size, + items.size - (position + subItems.size) + )*/ + //notifyItemRangeChanged(position, items.size - position) + + if (model is GradesSubject) { + // auto expand first semester + if (model.semesters.isNotEmpty()) { + val semester = model.semesters.firstOrNull { it.grades.isNotEmpty() } ?: model.semesters.first() + val semesterIndex = model.semesters.indexOf(semester) + val grades = if (semester.grades.isEmpty()) + listOf(GradesEmpty()) + else + semester.grades + semester.state = STATE_OPENED + items.addAll(position + 2 + semesterIndex, grades) + notifyItemRangeInserted(position + 2 + semesterIndex, grades.size) + } + } + } + else { + val start = position + 1 + var end: Int = items.size + for (i in start until items.size) { + val model1 = items[i] + val level = if (model1 is GradesStats) 0 else (model1 as? ExpandableItemModel<*>)?.level ?: 3 + if (level <= model.level) { + end = i + break + } else { + if (model1 is ExpandableItemModel<*> && model1.state == STATE_OPENED) { + model1.state = STATE_CLOSED + } + } + } + + if (end != -1) { + items.subList(start, end).clear() + notifyItemRangeRemoved(start, end - start) + //notifyItemRangeChanged(start, end - start) + //notifyItemRangeChanged(position, items.size - position) + } + + model.state = STATE_CLOSED + } + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + val item = items[position] + if (holder !is BindableViewHolder<*>) + return + + val app = activity.applicationContext as App + + val viewType = when (holder) { + is SubjectViewHolder -> ITEM_TYPE_SUBJECT + is SemesterViewHolder -> ITEM_TYPE_SEMESTER + is EmptyViewHolder -> ITEM_TYPE_EMPTY + is GradeViewHolder -> ITEM_TYPE_GRADE + is StatsViewHolder -> ITEM_TYPE_STATS + else -> throw IllegalArgumentException("Incorrect viewType") + } + holder.itemView.setTag(R.string.tag_key_view_type, viewType) + holder.itemView.setTag(R.string.tag_key_position, position) + holder.itemView.setTag(R.string.tag_key_model, item) + + when { + holder is SubjectViewHolder && item is GradesSubject -> holder.onBind(activity, app, item, position) + holder is SemesterViewHolder && item is GradesSemester -> holder.onBind(activity, app, item, position) + holder is EmptyViewHolder && item is GradesEmpty -> holder.onBind(activity, app, item, position) + holder is GradeViewHolder && item is GradeFull -> holder.onBind(activity, app, item, position) + holder is StatsViewHolder && item is GradesStats -> holder.onBind(activity, app, item, position) + } + + if (holder is SemesterViewHolder && item is GradesSemester) { + holder.b.editButton.onClick { + onGradesEditorClick?.invoke(item.subjectId, item.number) + } + } + + holder.itemView.setOnClickListener(onClickListener) + } + + override fun getItemCount() = items.size +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesFragment.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesFragment.java deleted file mode 100644 index 7c48bcce..00000000 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesFragment.java +++ /dev/null @@ -1,513 +0,0 @@ -package pl.szczodrzynski.edziennik.ui.modules.grades; - -import android.os.AsyncTask; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ListView; -import android.widget.Toast; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.databinding.DataBindingUtil; -import androidx.fragment.app.Fragment; - -import com.afollestad.materialdialogs.MaterialDialog; -import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial; - -import java.util.ArrayList; -import java.util.List; - -import pl.szczodrzynski.edziennik.App; -import pl.szczodrzynski.edziennik.MainActivity; -import pl.szczodrzynski.edziennik.R; -import pl.szczodrzynski.edziennik.config.ProfileConfigGrades; -import pl.szczodrzynski.edziennik.data.db.entity.Grade; -import pl.szczodrzynski.edziennik.data.db.entity.Subject; -import pl.szczodrzynski.edziennik.data.db.full.GradeFull; -import pl.szczodrzynski.edziennik.databinding.FragmentGradesBinding; -import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog; -import pl.szczodrzynski.edziennik.utils.Themes; -import pl.szczodrzynski.edziennik.utils.models.ItemGradesSubjectModel; -import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem; -import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem; - -import static pl.szczodrzynski.edziennik.config.ConfigGrades.ORDER_BY_DATE_ASC; -import static pl.szczodrzynski.edziennik.config.ConfigGrades.ORDER_BY_DATE_DESC; -import static pl.szczodrzynski.edziennik.config.ConfigGrades.ORDER_BY_SUBJECT_ASC; -import static pl.szczodrzynski.edziennik.data.db.entity.Metadata.TYPE_GRADE; -import static pl.szczodrzynski.edziennik.data.db.entity.Profile.YEAR_1_AVG_2_AVG; -import static pl.szczodrzynski.edziennik.data.db.entity.Profile.YEAR_1_AVG_2_SEM; -import static pl.szczodrzynski.edziennik.data.db.entity.Profile.YEAR_1_SEM_2_AVG; -import static pl.szczodrzynski.edziennik.data.db.entity.Profile.YEAR_1_SEM_2_SEM; -import static pl.szczodrzynski.edziennik.data.db.entity.Profile.YEAR_ALL_GRADES; - -public class GradesFragment extends Fragment { - - private App app = null; - private MainActivity activity = null; - private FragmentGradesBinding b = null; - - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - activity = (MainActivity) getActivity(); - if (getActivity() == null || getContext() == null) - return null; - app = (App) activity.getApplication(); - getContext().getTheme().applyStyle(Themes.INSTANCE.getAppTheme(), true); - // activity, context and profile is valid - b = DataBindingUtil.inflate(inflater, R.layout.fragment_grades, container, false); - b.refreshLayout.setParent(activity.getSwipeRefreshLayout()); - b.refreshLayout.setNestedScrollingEnabled(true); - return b.getRoot(); - } - - ListView listView; - List subjectList; - - private String getRegisterCardAverageModeSubText() { - switch (App.Companion.getConfig().forProfile().getGrades().getYearAverageMode()) { - default: - case YEAR_1_AVG_2_AVG: - return getString(R.string.settings_register_avg_mode_0_short); - case YEAR_1_SEM_2_AVG: - return getString(R.string.settings_register_avg_mode_1_short); - case YEAR_1_AVG_2_SEM: - return getString(R.string.settings_register_avg_mode_2_short); - case YEAR_1_SEM_2_SEM: - return getString(R.string.settings_register_avg_mode_3_short); - case YEAR_ALL_GRADES: - return getString(R.string.settings_register_avg_mode_4_short); - } - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - if (app == null || activity == null || b == null || !isAdded()) - return; - - /*activity.getBottomSheet().setToggleGroupEnabled(true); - activity.getBottomSheet().toggleGroupRemoveItems(); - activity.getBottomSheet().setToggleGroupSelectionMode(NavBottomSheet.TOGGLE_GROUP_SORTING_ORDER); - activity.getBottomSheet().toggleGroupAddItem(0, getString(R.string.sort_by_date), (Drawable)null, SORT_MODE_DESCENDING); - activity.getBottomSheet().toggleGroupAddItem(1, getString(R.string.sort_by_subject), (Drawable)null, SORT_MODE_ASCENDING); - activity.getBottomSheet().setToggleGroupSortingOrderListener((id, sortMode) -> { - sortModeChanged = true; - if (id == 0 && sortMode == SORT_MODE_ASCENDING) { - app.appConfig.gradesOrderBy = ORDER_BY_DATE_ASC; - } - else if (id == 1 && sortMode == SORT_MODE_ASCENDING) { - app.appConfig.gradesOrderBy = ORDER_BY_SUBJECT_ASC; - } - else if (id == 0 && sortMode == SORT_MODE_DESCENDING) { - app.appConfig.gradesOrderBy = ORDER_BY_DATE_DESC; - } - else if (id == 1 && sortMode == SORT_MODE_DESCENDING) { - app.appConfig.gradesOrderBy = ORDER_BY_SUBJECT_DESC; - } - return null; - }); - activity.getBottomSheet().setToggleGroupTitle("Sortowanie"); - activity.getBottomSheet().toggleGroupCheck(0); - activity.getBottomSheet().setOnCloseListener(() -> { - if (sortModeChanged) { - sortModeChanged = false; - activity.reloadTarget(); - } - return null; - });*/ - - activity.getBottomSheet().prependItems( - new BottomSheetPrimaryItem(true) - .withTitle(R.string.menu_grades_averages) - .withDescription(R.string.menu_grades_averages_desc) - .withIcon(CommunityMaterial.Icon.cmd_chart_line) - .withOnClickListener(v3 -> { - activity.getBottomSheet().close(); - showAverages(); - }), - new BottomSheetPrimaryItem(true) - .withTitle(R.string.menu_grades_config) - .withIcon(CommunityMaterial.Icon2.cmd_settings_outline) - .withOnClickListener(v3 -> { - activity.getBottomSheet().close(); - new GradesConfigDialog(activity, true, null, null); - }), - new BottomSheetSeparatorItem(true), - new BottomSheetPrimaryItem(true) - .withTitle(R.string.menu_mark_as_read) - .withIcon(CommunityMaterial.Icon.cmd_eye_check_outline) - .withOnClickListener(v3 -> { - activity.getBottomSheet().close(); - AsyncTask.execute(() -> App.db.metadataDao().setAllSeen(App.Companion.getProfileId(), TYPE_GRADE, true)); - Toast.makeText(activity, R.string.main_menu_mark_as_read_success, Toast.LENGTH_SHORT).show(); - }) - ); - activity.gainAttention(); - - /*b.refreshLayout.setOnRefreshListener(() -> { - activity.syncCurrentFeature(MainActivity.DRAWER_ITEM_GRADES, b.refreshLayout); - });*/ - - listView = b.gradesRecyclerView; - //listView.setHasFixedSize(true); - //listView.setLayoutManager(new LinearLayoutManager(getContext())); - - long expandSubjectId = -1; - if (getArguments() != null) { - expandSubjectId = getArguments().getLong("gradesSubjectId", -1); - } - - /*b.gradesSwipeLayout.setOnRefreshListener(() -> { - Toast.makeText(activity, "Works!", Toast.LENGTH_LONG).show(); - // To keep animation for 4 seconds - new Handler().postDelayed(() -> { - // Stop animation (This will be after 3 seconds) - b.gradesSwipeLayout.setRefreshing(false); - }, 3000); - });*/ - - long finalExpandSubjectId = expandSubjectId; - String orderBy; - if (app.getConfig().getGrades().getOrderBy() == ORDER_BY_SUBJECT_ASC) { - orderBy = "subjectLongName ASC, addedDate DESC"; - } - else if (app.getConfig().getGrades().getOrderBy() == ORDER_BY_DATE_DESC) { - orderBy = "addedDate DESC"; - } - else if (app.getConfig().getGrades().getOrderBy() == ORDER_BY_DATE_ASC) { - orderBy = "addedDate ASC"; - } - else { - orderBy = "subjectLongName DESC, addedDate DESC"; - } - - App.db.gradeDao().getAllOrderBy(App.Companion.getProfileId(), orderBy).observe(this, grades -> { - if (app == null || activity == null || b == null || !isAdded()) - return; - - subjectList = new ArrayList<>(); - - ProfileConfigGrades config = app.getConfig().getFor(App.Companion.getProfileId()).getGrades(); - - // now we have all grades from the newest to the oldest - for (GradeFull grade: grades) { - ItemGradesSubjectModel model = ItemGradesSubjectModel.searchModelBySubjectId(subjectList, grade.subjectId); - if (model == null) { - model = new ItemGradesSubjectModel(app.getProfile(), - new Subject(App.Companion.getProfileId(), grade.subjectId, grade.subjectLongName, grade.subjectShortName), - new ArrayList<>(), - new ArrayList<>()); - subjectList.add(model); - if (model.subject != null && model.subject.id == finalExpandSubjectId) { - model.expandView = true; - } - model.colorMode = App.Companion.getConfig().forProfile().getGrades().getColorMode(); - model.yearAverageMode = App.Companion.getConfig().forProfile().getGrades().getYearAverageMode(); - } - if (!grade.seen && grade.semester == 1) { - model.semester1Unread++; - } - if (!grade.seen && grade.semester == 2) { - model.semester2Unread++; - } - // COUNT POINT GRADES - if (grade.type == Grade.TYPE_POINT_AVG) { - model.isPointSubject = true; - if (grade.semester == 1) { - model.gradeSumOverall += grade.value; - model.gradeCountOverall += grade.valueMax; - model.gradeSumSemester1 += grade.value; - model.gradeCountSemester1 += grade.valueMax; - model.semester1Average = model.gradeSumSemester1 / model.gradeCountSemester1 * 100; - model.grades1.add(grade); - } - if (grade.semester == 2) { - model.gradeSumOverall += grade.value; - model.gradeCountOverall += grade.valueMax; - model.gradeSumSemester2 += grade.value; - model.gradeCountSemester2 += grade.valueMax; - model.semester2Average = model.gradeSumSemester2 / model.gradeCountSemester2 * 100; - model.grades2.add(grade); - } - } - else if (grade.type == Grade.TYPE_POINT_SUM) { - model.isBehaviourSubject = true; - if (grade.semester == 1) { - model.semester1Average += grade.value; - model.yearAverage += grade.value; - model.grades1.add(grade); - } - if (grade.semester == 2) { - model.semester2Average += grade.value; - model.yearAverage += grade.value; - model.grades2.add(grade); - } - } - else if (grade.type == Grade.TYPE_NORMAL) { - model.isNormalSubject = true; - float weight = grade.weight; - if (weight < 0) { - // do not show *normal* grades with negative weight - these are historical grades - Iuczniowie - continue; - } - if (!config.getCountZeroToAvg() && grade.name.equals("0")) { - weight = 0; - } - float valueWeighted = grade.value * weight; - if (grade.semester == 1) { - model.gradeSumOverall += valueWeighted; - model.gradeCountOverall += weight; - model.gradeSumSemester1 += valueWeighted; - model.gradeCountSemester1 += weight; - model.semester1Average = model.gradeSumSemester1 / model.gradeCountSemester1; - if (grade.parentId == -1) { - // show only "current" grades - these which are not historical - model.grades1.add(grade); - } - } - if (grade.semester == 2) { - model.gradeSumOverall += valueWeighted; - model.gradeCountOverall += weight; - model.gradeSumSemester2 += valueWeighted; - model.gradeCountSemester2 += weight; - model.semester2Average = model.gradeSumSemester2 / model.gradeCountSemester2; - if (grade.parentId == -1) { - // show only "current" grades - these which are not historical - model.grades2.add(grade); - } - } - } - else if (grade.type == Grade.TYPE_SEMESTER1_PROPOSED) { - model.semester1Proposed = grade; - } - else if (grade.type == Grade.TYPE_SEMESTER1_FINAL) { - model.semester1Final = grade; - } - else if (grade.type == Grade.TYPE_SEMESTER2_PROPOSED) { - model.semester2Proposed = grade; - } - else if (grade.type == Grade.TYPE_SEMESTER2_FINAL) { - model.semester2Final = grade; - } - else if (grade.type == Grade.TYPE_YEAR_PROPOSED) { - model.yearProposed = grade; - } - else if (grade.type == Grade.TYPE_YEAR_FINAL) { - model.yearFinal = grade; - } - else { - // descriptive grades, text grades - model.isDescriptiveSubject = true; - if (grade.semester == 1) { - model.grades1.add(grade); - } - if (grade.semester == 2) { - model.grades2.add(grade); - } - } - } - - for (ItemGradesSubjectModel model: subjectList) { - if (model.isPointSubject) { - model.yearAverage = model.gradeSumOverall / model.gradeCountOverall * 100.0f; // map the point grade "average" % value from 0.0f-1.0f to 0%-100% - } - /*else if (model.isDescriptiveSubject && !model.isNormalSubject) { - // applies for only descriptive grades - do nothing. average is hidden - //model.isDescriptiveSubject = false; - //model.semester1Average = -1; - //model.semester2Average = -1; - //model.yearAverage = -1; - }*/ - else if (!model.isBehaviourSubject && model.isNormalSubject) { - // applies for normal grades & normal+descriptive grades - // calculate the normal grade average based on the user's setting - switch (App.Companion.getConfig().forProfile().getGrades().getYearAverageMode()) { - case YEAR_1_AVG_2_AVG: - model.yearAverage = (model.semester1Average + model.semester2Average) / 2; - break; - case YEAR_1_SEM_2_AVG: - model.yearAverage = model.semester1Final != null ? (model.semester1Final.value + model.semester2Average) / 2 : 0.0f; - break; - case YEAR_1_AVG_2_SEM: - model.yearAverage = model.semester2Final != null ? (model.semester1Average + model.semester2Final.value) / 2 : 0.0f; - break; - case YEAR_1_SEM_2_SEM: - model.yearAverage = model.semester1Final != null && model.semester2Final != null ? (model.semester1Final.value + model.semester2Final.value) / 2 : 0.0f; - break; - default: - case YEAR_ALL_GRADES: - model.yearAverage = model.gradeSumOverall / model.gradeCountOverall; - break; - } - } - } - - if (subjectList.size() > 0) { - GradesSubjectAdapter adapter; - if ((adapter = (GradesSubjectAdapter) listView.getAdapter()) != null) { - adapter.subjectList = subjectList; - adapter.notifyDataSetChanged(); - return; - } - adapter = new GradesSubjectAdapter(subjectList, activity); - listView.setAdapter(adapter); - listView.setVisibility(View.VISIBLE); - b.gradesNoData.setVisibility(View.GONE); - if (finalExpandSubjectId != -1) { - int subjectIndex = subjectList.indexOf(ItemGradesSubjectModel.searchModelBySubjectId(subjectList, finalExpandSubjectId)); - listView.setSelection(subjectIndex > 0 ? subjectIndex - 1 : subjectIndex); - } - } - else { - listView.setVisibility(View.GONE); - b.gradesNoData.setVisibility(View.VISIBLE); - } - }); - - } - - private int gradeFromAverage(float value) { - int grade = (int)Math.floor(value); - if (value % 1.0f >= 0.75f) - grade++; - return grade; - } - - public void showAverages() { - if (app == null || activity == null || b == null || !isAdded() || subjectList == null) - return; - - float semester1Sum = 0; - float semester1Count = 0; - float semester1ProposedSum = 0; - float semester1ProposedCount = 0; - float semester1FinalSum = 0; - float semester1FinalCount = 0; - - float semester2Sum = 0; - float semester2Count = 0; - float semester2ProposedSum = 0; - float semester2ProposedCount = 0; - float semester2FinalSum = 0; - float semester2FinalCount = 0; - - float yearSum = 0; - float yearCount = 0; - float yearProposedSum = 0; - float yearProposedCount = 0; - float yearFinalSum = 0; - float yearFinalCount = 0; - - for (ItemGradesSubjectModel subject: subjectList) { - // we cannot skip non-normal subjects because a point subject may also have a final grade - if (subject.isBehaviourSubject) - continue; - - // SEMESTER 1 GRADES & AVERAGES - if (subject.semester1Final != null && subject.semester1Final.value > 0) { // if final available, add to final grades & expected grades - semester1FinalSum += subject.semester1Final.value; - semester1FinalCount++; - semester1Sum += subject.semester1Final.value; - semester1Count++; - } - else if (subject.semester1Proposed != null && subject.semester1Proposed.value > 0) { // if final not available, add proposed to expected grades - semester1Sum += subject.semester1Proposed.value; - semester1Count++; - } - else if (!Float.isNaN(subject.semester1Average) - && subject.semester1Average > 0 - && !subject.isPointSubject) { // if final&proposed unavailable, calculate from avg - semester1Sum += gradeFromAverage(subject.semester1Average); - semester1Count++; - } - if (subject.semester1Proposed != null && subject.semester1Proposed.value > 0) { // add proposed to proposed grades even if final is available - semester1ProposedSum += subject.semester1Proposed.value; - semester1ProposedCount++; - } - - // SEMESTER 2 GRADES & AVERAGES - if (subject.semester2Final != null && subject.semester2Final.value > 0) { // if final available, add to final grades & expected grades - semester2FinalSum += subject.semester2Final.value; - semester2FinalCount++; - semester2Sum += subject.semester2Final.value; - semester2Count++; - } - else if (subject.semester2Proposed != null && subject.semester2Proposed.value > 0) { // if final not available, add proposed to expected grades - semester2Sum += subject.semester2Proposed.value; - semester2Count++; - } - else if (!Float.isNaN(subject.semester2Average) - && subject.semester2Average > 0 - && !subject.isPointSubject) { // if final&proposed unavailable, calculate from avg - semester2Sum += gradeFromAverage(subject.semester2Average); - semester2Count++; - } - if (subject.semester2Proposed != null && subject.semester2Proposed.value > 0) { // add proposed to proposed grades even if final is available - semester2ProposedSum += subject.semester2Proposed.value; - semester2ProposedCount++; - } - - // YEAR GRADES & AVERAGES - if (subject.yearFinal != null && subject.yearFinal.value > 0) { // if final available, add to final grades & expected grades - yearFinalSum += subject.yearFinal.value; - yearFinalCount++; - yearSum += subject.yearFinal.value; - yearCount++; - } - else if (subject.yearProposed != null && subject.yearProposed.value > 0) { // if final not available, add proposed to expected grades - yearSum += subject.yearProposed.value; - yearCount++; - } - else if (!Float.isNaN(subject.yearAverage) - && subject.yearAverage > 0 - && !subject.isPointSubject) { // if final&proposed unavailable, calculate from avg - yearSum += gradeFromAverage(subject.yearAverage); - yearCount++; - } - if (subject.yearProposed != null && subject.yearProposed.value > 0) { // add proposed to proposed grades even if final is available - yearProposedSum += subject.yearProposed.value; - yearProposedCount++; - } - } - - String semester1ExpectedAverageStr = semester1Count > semester1ProposedCount || semester1Count > semester1FinalCount ? getString(R.string.dialog_averages_expected_format, 1, semester1Sum / semester1Count) : ""; - String semester1ProposedAverageStr = semester1ProposedCount > 0 ? getString(R.string.dialog_averages_proposed_format, 1, semester1ProposedSum / semester1ProposedCount) : ""; - String semester1FinalAverageStr = semester1FinalCount > 0 ? getString(R.string.dialog_averages_final_format, 1, semester1FinalSum / semester1FinalCount) : ""; - - String semester2ExpectedAverageStr = semester2Count > semester2ProposedCount || semester2Count > semester2FinalCount ? getString(R.string.dialog_averages_expected_format, 2, semester2Sum / semester2Count) : ""; - String semester2ProposedAverageStr = semester2ProposedCount > 0 ? getString(R.string.dialog_averages_proposed_format, 2, semester2ProposedSum / semester2ProposedCount) : ""; - String semester2FinalAverageStr = semester2FinalCount > 0 ? getString(R.string.dialog_averages_final_format, 2, semester2FinalSum / semester2FinalCount) : ""; - - String yearExpectedAverageStr = yearCount > yearProposedCount || yearCount > yearFinalCount ? getString(R.string.dialog_averages_expected_yearly_format, yearSum / yearCount) : ""; - String yearProposedAverageStr = yearProposedCount > 0 ? getString(R.string.dialog_averages_proposed_yearly_format, yearProposedSum / yearProposedCount) : ""; - String yearFinalAverageStr = yearFinalCount > 0 ? getString(R.string.dialog_averages_final_yearly_format, yearFinalSum / yearFinalCount) : ""; - - if (semester1ExpectedAverageStr.isEmpty() && semester1ProposedAverageStr.isEmpty() && semester1FinalAverageStr.isEmpty()) { - semester1ExpectedAverageStr = getString(R.string.dialog_averages_unavailable_format, 1); - } - if (semester2ExpectedAverageStr.isEmpty() && semester2ProposedAverageStr.isEmpty() && semester2FinalAverageStr.isEmpty()) { - semester2ExpectedAverageStr = getString(R.string.dialog_averages_unavailable_format, 2); - } - if (yearExpectedAverageStr.isEmpty() && yearProposedAverageStr.isEmpty() && yearFinalAverageStr.isEmpty()) { - yearExpectedAverageStr = getString(R.string.dialog_averages_unavailable_yearly); - } - - new MaterialDialog.Builder(activity) - .title(R.string.dialog_averages_title) - .content(getString( - R.string.dialog_averages_format, - semester1ExpectedAverageStr, - semester1ProposedAverageStr, - semester1FinalAverageStr, - semester2ExpectedAverageStr, - semester2ProposedAverageStr, - semester2FinalAverageStr, - yearExpectedAverageStr, - yearProposedAverageStr, - yearFinalAverageStr)) - .positiveText(R.string.ok) - .show(); - } -} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesFragment.kt new file mode 100644 index 00000000..d58af876 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesFragment.kt @@ -0,0 +1,245 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2020-3-4. + */ + +package pl.szczodrzynski.edziennik.ui.modules.grades + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import androidx.lifecycle.Observer +import androidx.recyclerview.widget.LinearLayoutManager +import kotlinx.coroutines.* +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.MainActivity +import pl.szczodrzynski.edziennik.averageOrNull +import pl.szczodrzynski.edziennik.data.db.entity.Grade +import pl.szczodrzynski.edziennik.data.db.full.GradeFull +import pl.szczodrzynski.edziennik.databinding.GradesFragmentBinding +import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradeDetailsDialog +import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesAverages +import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesSemester +import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesStats +import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesSubject +import pl.szczodrzynski.edziennik.utils.managers.GradesManager +import kotlin.coroutines.CoroutineContext +import kotlin.math.max + +class GradesFragment : Fragment(), CoroutineScope { + companion object { + private const val TAG = "GradesFragment" + } + + private lateinit var app: App + private lateinit var activity: MainActivity + private lateinit var b: GradesFragmentBinding + + private val job: Job = Job() + override val coroutineContext: CoroutineContext + get() = job + Dispatchers.Main + + // local/private variables go here + private val adapter by lazy { + GradesAdapter(activity) + } + private val manager by lazy { app.gradesManager } + private val dontCountGrades by lazy { manager.dontCountGrades } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + activity = (getActivity() as MainActivity?) ?: return null + context ?: return null + app = activity.application as App + b = GradesFragmentBinding.inflate(inflater) + b.refreshLayout.setParent(activity.swipeRefreshLayout) + return b.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + if (!isAdded) + return + + app.db.gradeDao() + .getAllOrderBy(App.profileId, app.gradesManager.getOrderByString()) + .observe(this, Observer { grades -> + if (b.gradesRecyclerView.adapter == null) { + b.gradesRecyclerView.adapter = adapter + b.gradesRecyclerView.apply { + setHasFixedSize(true) + layoutManager = LinearLayoutManager(context) + //addItemDecoration(SimpleDividerItemDecoration(context)) + } + } + + launch(Dispatchers.Default) { + processGrades(grades) + } + + if (grades != null && grades.isNotEmpty()) { + b.gradesRecyclerView.visibility = View.VISIBLE + b.gradesNoData.visibility = View.GONE + } else { + b.gradesRecyclerView.visibility = View.GONE + b.gradesNoData.visibility = View.VISIBLE + } + }) + + adapter.onGradeClick = { + GradeDetailsDialog(activity, it) + } + + adapter.onGradesEditorClick = { subjectId, semesterNumber -> + + } + } + + private suspend fun processGrades(grades: List) { + val items = mutableListOf() + + var subjectId = -1L + var semesterNumber = 0 + var subject = GradesSubject(subjectId, "") + var semester = GradesSemester(0, 1) + + // grades returned by the query are ordered + // by the subject ID, so it's easier and probably + // a bit faster to build all the models + for (grade in grades) { + /*if (grade.parentId != null && grade.parentId != -1L) + continue // the grade is hidden as a new, improved one is available*/ + if (grade.subjectId != subjectId) { + subjectId = grade.subjectId + semesterNumber = 0 + + subject = items.firstOrNull { it.subjectId == subjectId } + ?: GradesSubject(grade.subjectId, grade.subjectLongName ?: "").also { + items += it + it.semester = 2 + } + } + if (grade.semester != semesterNumber) { + semesterNumber = grade.semester + + semester = subject.semesters.firstOrNull { it.number == semesterNumber } + ?: GradesSemester(subject.subjectId, grade.semester).also { subject.semesters += it } + } + + when (grade.type) { + Grade.TYPE_SEMESTER1_PROPOSED, + Grade.TYPE_SEMESTER2_PROPOSED -> semester.proposedGrade = grade + Grade.TYPE_SEMESTER1_FINAL, + Grade.TYPE_SEMESTER2_FINAL -> semester.finalGrade = grade + Grade.TYPE_YEAR_PROPOSED -> subject.proposedGrade = grade + Grade.TYPE_YEAR_FINAL -> subject.finalGrade = grade + else -> { + semester.grades += grade + countGrade(grade, subject.averages) + countGrade(grade, semester.averages) + } + } + + subject.lastAddedDate = max(subject.lastAddedDate, grade.addedDate) + } + + val stats = GradesStats() + + val sem1Expected = mutableListOf() + val sem2Expected = mutableListOf() + val yearlyExpected = mutableListOf() + val sem1Proposed = mutableListOf() + val sem2Proposed = mutableListOf() + val yearlyProposed = mutableListOf() + val sem1Final = mutableListOf() + val sem2Final = mutableListOf() + val yearlyFinal = mutableListOf() + + val sem1Point = mutableListOf() + val sem2Point = mutableListOf() + val yearlyPoint = mutableListOf() + + for (item in items) { + item.semesters.forEach { sem -> + manager.calculateAverages(sem.averages) + if (sem.number == 1) { + sem.proposedGrade?.value?.let { sem1Proposed += it } + sem.finalGrade?.value?.let { + sem1Final += it + sem1Expected += it + } ?: run { + sem.averages.normalAvg?.let { sem1Expected += manager.getRoundedGrade(it).toFloat() } + } + sem.averages.pointAvgPercent?.let { sem1Point += it } + } + if (sem.number == 2) { + sem.proposedGrade?.value?.let { sem2Proposed += it } + sem.finalGrade?.value?.let { + sem2Final += it + sem2Expected += it + } ?: run { + sem.averages.normalAvg?.let { sem2Expected += manager.getRoundedGrade(it).toFloat() } + } + sem.averages.pointAvgPercent?.let { sem2Point += it } + } + } + manager.calculateAverages(item.averages, item.semesters) + item.proposedGrade?.value?.let { yearlyProposed += it } + item.finalGrade?.value?.let { + yearlyFinal += it + yearlyExpected += it + } ?: run { + item.averages.normalAvg?.let { yearlyExpected += manager.getRoundedGrade(it).toFloat() } + } + item.averages.pointAvgPercent?.let { yearlyPoint += it } + } + + stats.normalSem1 = sem1Expected.averageOrNull()?.toFloat() ?: 0f + stats.normalSem1Proposed = sem1Proposed.averageOrNull()?.toFloat() ?: 0f + stats.normalSem1Final = sem1Final.averageOrNull()?.toFloat() ?: 0f + stats.sem1NotAllFinal = sem1Final.size < sem1Expected.size + stats.normalSem2 = sem2Expected.averageOrNull()?.toFloat() ?: 0f + stats.normalSem2Proposed = sem2Proposed.averageOrNull()?.toFloat() ?: 0f + stats.normalSem2Final = sem2Final.averageOrNull()?.toFloat() ?: 0f + stats.sem2NotAllFinal = sem2Final.size < sem2Expected.size + stats.normalYearly = yearlyExpected.averageOrNull()?.toFloat() ?: 0f + stats.normalYearlyProposed = yearlyProposed.averageOrNull()?.toFloat() ?: 0f + stats.normalYearlyFinal = yearlyFinal.averageOrNull()?.toFloat() ?: 0f + stats.yearlyNotAllFinal = yearlyFinal.size < yearlyExpected.size + + stats.pointSem1 = sem1Point.averageOrNull()?.toFloat() ?: 0f + 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 } + } + + adapter.items = items.toMutableList() + adapter.items.add(stats) + + withContext(Dispatchers.Main) { + adapter.notifyDataSetChanged() + } + } + + private fun countGrade(grade: Grade, averages: GradesAverages) { + val value = manager.getGradeValue(grade) + val weight = manager.getGradeWeight(dontCountGrades, grade) + when (grade.type) { + Grade.TYPE_NORMAL -> { + averages.normalSum += value + averages.normalCount ++ + averages.normalWeightedSum += value * weight + averages.normalWeightedCount += weight + } + Grade.TYPE_POINT_AVG -> { + averages.pointAvgSum += grade.value + averages.pointAvgMax += grade.valueMax ?: value + } + Grade.TYPE_POINT_SUM -> { + averages.pointSum += grade.value + } + } + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesListAdapter.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesListAdapter.java deleted file mode 100644 index a3035353..00000000 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesListAdapter.java +++ /dev/null @@ -1,143 +0,0 @@ -package pl.szczodrzynski.edziennik.ui.modules.grades; - -import android.content.Context; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.core.graphics.ColorUtils; -import androidx.recyclerview.widget.RecyclerView; - -import java.text.DecimalFormat; -import java.util.List; - -import pl.szczodrzynski.edziennik.App; -import pl.szczodrzynski.edziennik.R; -import pl.szczodrzynski.edziennik.data.db.entity.Grade; -import pl.szczodrzynski.edziennik.data.db.full.GradeFull; -import pl.szczodrzynski.edziennik.ui.dialogs.grade.GradeDetailsDialog; -import pl.szczodrzynski.edziennik.utils.Colors; -import pl.szczodrzynski.edziennik.utils.models.Date; - -import static pl.szczodrzynski.edziennik.data.db.entity.Profile.COLOR_MODE_DEFAULT; - -public class GradesListAdapter extends RecyclerView.Adapter { - private Context mContext; - private List gradeList; - - //getting the context and product list with constructor - public GradesListAdapter(Context mCtx, List gradeList) { - this.mContext = mCtx; - this.gradeList = gradeList; - } - - @NonNull - @Override - public GradesListAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - //inflating and returning our view holder - LayoutInflater inflater = LayoutInflater.from(mContext); - View view = inflater.inflate(R.layout.row_grades_list_item, parent, false); - return new GradesListAdapter.ViewHolder(view); - } - - @Override - public void onBindViewHolder(@NonNull GradesListAdapter.ViewHolder holder, int position) { - App app = (App) mContext.getApplicationContext(); - - GradeFull grade = gradeList.get(position); - - holder.root.setOnClickListener((v -> { - new GradeDetailsDialog(v.getContext(), App.Companion.getProfileId()).show(app, grade); - })); - - int gradeColor; - if (App.Companion.getConfig().forProfile().getGrades().getColorMode() == COLOR_MODE_DEFAULT) { - gradeColor = grade.color; - } - else { - gradeColor = Colors.gradeToColor(grade); - } - - holder.gradesListName.setText(grade.name); - holder.gradesListName.setSelected(true); - //holder.gradesListName.setTypeface(null, Typeface.BOLD); - holder.gradesListName.setTextColor(ColorUtils.calculateLuminance(gradeColor) > 0.3 ? 0xff000000 : 0xffffffff); - holder.gradesListName.getBackground().setColorFilter(new PorterDuffColorFilter(gradeColor, PorterDuff.Mode.MULTIPLY)); - - if (grade.description.trim().isEmpty()) { - holder.gradesListDescription.setText(grade.category); - holder.gradesListCategory.setText(grade.isImprovement ? app.getString(R.string.grades_improvement_category_format, "") : ""); - } - else { - holder.gradesListDescription.setText(grade.description); - holder.gradesListCategory.setText(grade.isImprovement ? app.getString(R.string.grades_improvement_category_format, grade.category) : grade.category); - } - - DecimalFormat format = new DecimalFormat("#.##"); - DecimalFormat formatWithZeroes = new DecimalFormat("#.00"); - - if (grade.weight < 0) { - grade.weight *= -1; - } - if (grade.type == Grade.TYPE_DESCRIPTIVE || grade.type == Grade.TYPE_DESCRIPTIVE_TEXT || grade.type == Grade.TYPE_TEXT || grade.type == Grade.TYPE_POINT_SUM) { - holder.gradesListWeight.setVisibility(View.GONE); - grade.weight = 0; - } - else { - holder.gradesListWeight.setVisibility(View.VISIBLE); - if (grade.type == Grade.TYPE_POINT_AVG) { - holder.gradesListWeight.setText(app.getString(R.string.grades_max_points_format, format.format(grade.valueMax))); - } - else if (grade.weight == 0) { - holder.gradesListWeight.setText(app.getString(R.string.grades_weight_not_counted)); - } - else { - holder.gradesListWeight.setText(app.getString(R.string.grades_weight_format, format.format(grade.weight) + (grade.classAverage != -1 ? ", " + formatWithZeroes.format(grade.classAverage) : ""))); - } - } - - - holder.gradesListTeacher.setText(grade.teacherFullName); - holder.gradesListAddedDate.setText(Date.fromMillis(grade.addedDate).getFormattedStringShort()); - - if (!grade.seen) { - holder.gradesListDescription.setBackground(mContext.getResources().getDrawable(R.drawable.bg_rounded_4dp)); - holder.gradesListDescription.getBackground().setColorFilter(new PorterDuffColorFilter(0x692196f3, PorterDuff.Mode.MULTIPLY)); - } - else { - holder.gradesListDescription.setBackground(null); - } - } - - @Override - public int getItemCount() { - return gradeList.size(); - } - - class ViewHolder extends RecyclerView.ViewHolder { - - View root; - TextView gradesListName; - TextView gradesListDescription; - TextView gradesListCategory; - TextView gradesListWeight; - TextView gradesListTeacher; - TextView gradesListAddedDate; - - ViewHolder(View itemView) { - super(itemView); - root = itemView.getRootView(); - gradesListName = itemView.findViewById(R.id.gradesListName); - gradesListDescription = itemView.findViewById(R.id.gradesListCategoryColumn); - gradesListCategory = itemView.findViewById(R.id.gradesListCategoryDescription); - gradesListWeight = itemView.findViewById(R.id.gradesListWeight); - gradesListTeacher = itemView.findViewById(R.id.gradesListTeacher); - gradesListAddedDate = itemView.findViewById(R.id.gradesListAddedDate); - } - } -} - diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesSubjectAdapter.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesSubjectAdapter.java deleted file mode 100644 index 905fdb89..00000000 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/GradesSubjectAdapter.java +++ /dev/null @@ -1,787 +0,0 @@ -package pl.szczodrzynski.edziennik.ui.modules.grades; - -import android.content.Context; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; -import android.graphics.Typeface; -import android.os.AsyncTask; -import android.os.Bundle; -import android.util.DisplayMetrics; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.animation.Animation; -import android.widget.ArrayAdapter; -import android.widget.LinearLayout; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.constraintlayout.widget.ConstraintLayout; -import androidx.core.graphics.ColorUtils; -import androidx.core.widget.NestedScrollView; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - -import com.mikepenz.iconics.view.IconicsImageView; - -import java.text.DecimalFormat; -import java.util.List; - -import pl.szczodrzynski.edziennik.App; -import pl.szczodrzynski.edziennik.MainActivity; -import pl.szczodrzynski.edziennik.R; -import pl.szczodrzynski.edziennik.data.db.AppDb; -import pl.szczodrzynski.edziennik.data.db.entity.Subject; -import pl.szczodrzynski.edziennik.data.db.full.GradeFull; -import pl.szczodrzynski.edziennik.utils.Anim; -import pl.szczodrzynski.edziennik.utils.Colors; -import pl.szczodrzynski.edziennik.utils.Utils; -import pl.szczodrzynski.edziennik.utils.models.ItemGradesSubjectModel; - -import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; -import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; -import static pl.szczodrzynski.edziennik.MainActivity.TARGET_GRADES_EDITOR; -import static pl.szczodrzynski.edziennik.data.db.entity.Profile.COLOR_MODE_DEFAULT; -import static pl.szczodrzynski.edziennik.data.db.entity.Profile.YEAR_1_AVG_2_SEM; -import static pl.szczodrzynski.edziennik.data.db.entity.Profile.YEAR_1_SEM_2_AVG; -import static pl.szczodrzynski.edziennik.data.db.entity.Profile.YEAR_1_SEM_2_SEM; - -public class GradesSubjectAdapter extends ArrayAdapter implements View.OnClickListener { - private static final String TAG = "GradesSubjectAdapter"; - private MainActivity activity; - public List subjectList; - - private void updateBadges(Context context, ItemGradesSubjectModel model) { - // do not need this since we have an Observer for unread counters.. - //((App)getContext().getApplicationContext()).saveRegister(); // I don't like this. - } - - private boolean invalidAvg(float avg) { - return avg == 0.0f || Float.isNaN(avg); - } - - private void updateSubjectSemesterBadges(ViewHolder holder, ItemGradesSubjectModel model) { - if (model.semester1Unread > 0 || model.semester2Unread > 0) { - holder.gradesSubjectTitle.setBackground(getContext().getResources().getDrawable(R.drawable.bg_rounded_4dp)); - holder.gradesSubjectTitle.getBackground().setColorFilter(new PorterDuffColorFilter(0x692196f3, PorterDuff.Mode.MULTIPLY)); - } - else { - holder.gradesSubjectTitle.setBackground(null); - } - if (model.semester1Unread > 0) { - holder.gradesSubjectSemester1Title.setBackground(getContext().getResources().getDrawable(R.drawable.bg_rounded_4dp)); - holder.gradesSubjectSemester1Title.getBackground().setColorFilter(new PorterDuffColorFilter(0x692196f3, PorterDuff.Mode.MULTIPLY)); - } - else { - holder.gradesSubjectSemester1Title.setBackground(null); - } - if (model.semester2Unread > 0) { - holder.gradesSubjectSemester2Title.setBackground(getContext().getResources().getDrawable(R.drawable.bg_rounded_4dp)); - holder.gradesSubjectSemester2Title.getBackground().setColorFilter(new PorterDuffColorFilter(0x692196f3, PorterDuff.Mode.MULTIPLY)); - } - else { - holder.gradesSubjectSemester2Title.setBackground(null); - } - } - - private boolean gradesSetAsRead(ViewHolder holder, ItemGradesSubjectModel model, int semester) { - boolean somethingChanged = false; - AppDb db = App.Companion.getDb(); - if (semester == 1) { - model.semester1Unread = 0; - for (GradeFull grade : model.grades1) { - if (!grade.seen) { - db.metadataDao().setSeen(App.Companion.getProfileId(), grade, somethingChanged = true); - } - } - if (model.semester1Proposed != null && !model.semester1Proposed.seen) - db.metadataDao().setSeen(App.Companion.getProfileId(), model.semester1Proposed, somethingChanged = true); - if (model.semester1Final != null && !model.semester1Final.seen) - db.metadataDao().setSeen(App.Companion.getProfileId(), model.semester1Final, somethingChanged = true); - } - else if (semester == 2) { - model.semester2Unread = 0; - for (GradeFull grade : model.grades2) { - if (!grade.seen) { - db.metadataDao().setSeen(App.Companion.getProfileId(), grade, somethingChanged = true); - } - } - if (model.semester2Proposed != null && !model.semester2Proposed.seen) - db.metadataDao().setSeen(App.Companion.getProfileId(), model.semester2Proposed, somethingChanged = true); - if (model.semester2Final != null && !model.semester2Final.seen) - db.metadataDao().setSeen(App.Companion.getProfileId(), model.semester2Final, somethingChanged = true); - if (model.yearProposed != null && !model.yearProposed.seen) - db.metadataDao().setSeen(App.Companion.getProfileId(), model.yearProposed, somethingChanged = true); - if (model.yearFinal != null && !model.yearFinal.seen) - db.metadataDao().setSeen(App.Companion.getProfileId(), model.yearFinal, somethingChanged = true); - } - if (somethingChanged) updateSubjectSemesterBadges(holder, model); - return somethingChanged; - } - - private void expandSubject(ViewHolder holder, ItemGradesSubjectModel model) { - Anim.fadeOut(holder.gradesSubjectPreviewContainer, 200, new Animation.AnimationListener() { - @Override public void onAnimationStart(Animation animation) { } - @Override public void onAnimationRepeat(Animation animation) { } - @Override - public void onAnimationEnd(Animation animation) { - boolean somethingChanged = false; - if (holder.gradesSubjectSemester1Container.getVisibility() != View.GONE) { - somethingChanged = gradesSetAsRead(holder, model, 1); - } - if (holder.gradesSubjectSemester2Container.getVisibility() != View.GONE) { - somethingChanged = gradesSetAsRead(holder, model, 2); - } - if (somethingChanged) updateBadges(getContext(), model); - //holder.gradesSubjectPreviewContent.setVisibility(View.INVISIBLE); - Anim.expand(holder.gradesSubjectContent, 500, null); - } - }); - } - - private void collapseSubject(ViewHolder holder, ItemGradesSubjectModel model) { - Anim.collapse(holder.gradesSubjectContent, 500, new Animation.AnimationListener() { - @Override public void onAnimationStart(Animation animation) { } - @Override public void onAnimationRepeat(Animation animation) { } - @Override - public void onAnimationEnd(Animation animation) { - //holder.gradesSubjectPreviewContent.setVisibility(View.VISIBLE); - Anim.fadeIn(holder.gradesSubjectPreviewContainer, 200, null); - } - }); - } - - class BuildGradeViews extends AsyncTask { - boolean findViews; - ItemGradesSubjectModel model; - //ViewGroup parent; - //int position; - ViewHolder holder; - - BuildGradeViews(ItemGradesSubjectModel model, ViewHolder holder, ViewGroup parent, int position, boolean findViews) { - this.model = model; - this.holder = holder; - this.findViews = findViews; - //this.parent = parent; - //this.position = position; - } - - protected Void doInBackground(Void... params) { - if (this.findViews) { - findViews(holder, holder.gradesSubjectRoot); - } - return null; - } - - protected void onPostExecute(Void aVoid) { - DecimalFormat df = new DecimalFormat("#.00"); - if (this.findViews) { - // TODO NIE WIEM CO TO ROBI XD - //this.viewHolder.semestrTitle1.setText(C0193R.string.semestr1); - //this.viewHolder.semestrTitle2.setText(C0193R.string.semestr2); - /*if (GradesSubjectAdapter.this.columns == 0) { - DisplayMetrics metrics = GradeListAdapterBySubject.this.context.getResources().getDisplayMetrics(); - if (GradeListAdapterBySubject.this.context.getResources().getBoolean(C0193R.bool.tablet)) { - GradeListAdapterBySubject.this.columns = ((int) ((((float) (this.parent.getWidth() / 2)) / metrics.density) - 30.0f)) / 58; - } else { - GradeListAdapterBySubject.this.columns = ((int) ((((float) this.parent.getWidth()) / metrics.density) - 30.0f)) / 58; - } - } - this.viewHolder.semestrGridView1.setColumnCount(GradeListAdapterBySubject.this.columns); - this.viewHolder.semestrGridView2.setColumnCount(GradeListAdapterBySubject.this.columns);*/ - } - if (model != null && model.subject != null && model.subject.id != holder.lastSubject) { - holder.gradesSubjectRoot.setBackground(Colors.getAdaptiveBackgroundDrawable(model.subject.color, model.subject.color)); - updateSubjectSemesterBadges(holder, model); - holder.gradesSubjectTitle.setText(model.subject.longName); - holder.gradesSubjectPreviewContent.removeAllViews(); - - if (model.expandView) { - // commented is without animations, do not use now (with unread badges) - //holder.gradesSubjectContent.setVisibility(View.VISIBLE); - //holder.gradesSubjectPreviewContent.setVisibility(View.INVISIBLE); - expandSubject(holder, model); - model.expandView = false; - } - int showSemester = model.profile.getCurrentSemester(); - - List gradeList = (showSemester == 1 ? model.grades1 : model.grades2); - if (gradeList.size() == 0) { - showSemester = (showSemester == 1 ? 2 : 1); - gradeList = (showSemester == 1 ? model.grades1 : model.grades2); - } - - App app = (App) getContext().getApplicationContext(); - - float scale = getContext().getResources().getDisplayMetrics().density; - int _5dp = (int) (5 * scale + 0.5f); - LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT); - layoutParams.setMargins(0, 0, _5dp, 0); - - DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics(); - int maxWidthPx = displayMetrics.widthPixels - Utils.dpToPx((app.getConfig().getUi().getMiniMenuVisible() ? 72 : 0)/*miniDrawer size*/ + 8 + 8/*left and right offsets*/ + 24/*ellipsize width*/); - int totalWidthPx = 0; - boolean ellipsized = false; - - if (showSemester != model.profile.getCurrentSemester()) { - // showing different semester, because of no grades in the selected one - holder.gradesSubjectPreviewSemester.setVisibility(View.VISIBLE); - holder.gradesSubjectPreviewSemester.setText(getContext().getString(R.string.grades_semester_header_format, showSemester)); - // decrease the max preview width. DONE below - /*holder.gradesSubjectPreviewSemester.measure(WRAP_CONTENT, WRAP_CONTENT); - maxWidthPx -= holder.gradesSubjectPreviewSemester.getMeasuredWidth(); - maxWidthPx -= _5dp;*/ - } - else { - holder.gradesSubjectPreviewSemester.setVisibility(View.GONE); - } - - - if (model.grades1.size() > 0) { - holder.gradesSubjectSemester1Nest.setNestedScrollingEnabled(false); - holder.gradesSubjectSemester1Content.setHasFixedSize(false); - holder.gradesSubjectSemester1Content.setNestedScrollingEnabled(false); - holder.gradesSubjectSemester1Content.setLayoutManager(new LinearLayoutManager(activity)); - holder.gradesSubjectSemester1Content.setAdapter(new GradesListAdapter(activity, model.grades1)); - holder.gradesSubjectSemester1Header.setVisibility(View.VISIBLE); - if (showSemester == 1) { - holder.gradesSubjectSemester1Container.setVisibility(View.VISIBLE); - } - else { - holder.gradesSubjectSemester1Container.setVisibility(View.GONE); - } - - if (model.isDescriptiveSubject && !model.isNormalSubject && !model.isPointSubject && !model.isBehaviourSubject) { - holder.gradesSubjectPreviewAverage.setVisibility(View.GONE); - holder.gradesSubjectSemester1Average.setVisibility(View.GONE); - } - else { - holder.gradesSubjectPreviewAverage.setVisibility(View.VISIBLE); - holder.gradesSubjectSemester1Average.setVisibility(View.VISIBLE); - int formatSingle = (model.isPointSubject ? R.string.grades_average_single_percent_format : model.isBehaviourSubject ? R.string.grades_average_single_point_format : R.string.grades_average_single_format); - int format = (model.isPointSubject ? R.string.grades_semester_average_percent_format : model.isBehaviourSubject ? R.string.grades_semester_average_point_format : R.string.grades_semester_average_format); - // PREVIEW AVERAGE - if (showSemester == 1) { - holder.gradesSubjectPreviewAverage.setText( - getContext().getString( - formatSingle, - invalidAvg(model.semester1Average) ? "-" : df.format(model.semester1Average) - ) - ); - } - // AVERAGE value - holder.gradesSubjectSemester1Average.setText( - getContext().getString( - format, - 1, - invalidAvg(model.semester1Average) ? "-" : df.format(model.semester1Average) - ) - ); - } - - // PROPOSED grade - if (model.semester1Proposed != null) { - holder.gradesSubjectSemester1Proposed.setVisibility(View.VISIBLE); - holder.gradesSubjectSemester1Proposed.setText(model.semester1Proposed.name); - holder.gradesSubjectSemester1Proposed.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.semester1Proposed.name), PorterDuff.Mode.MULTIPLY)); - holder.gradesSubjectSemester1Proposed.setTextColor(Colors.gradeNameToColor(model.semester1Proposed.name)); - if (showSemester == 1) { - holder.gradesSubjectPreviewProposed.setVisibility(View.VISIBLE); - holder.gradesSubjectPreviewProposed.setText(model.semester1Proposed.name); - holder.gradesSubjectPreviewProposed.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.semester1Proposed.name), PorterDuff.Mode.MULTIPLY)); - holder.gradesSubjectPreviewProposed.setTextColor(Colors.gradeNameToColor(model.semester1Proposed.name)); - } - } - else { - holder.gradesSubjectSemester1Proposed.setVisibility(View.GONE); - if (showSemester == 1) { - holder.gradesSubjectPreviewProposed.setVisibility(View.GONE); - } - } - // FINAL grade - if (model.semester1Final != null) { - holder.gradesSubjectSemester1Final.setVisibility(View.VISIBLE); - holder.gradesSubjectSemester1Final.setText(model.semester1Final.name); - holder.gradesSubjectSemester1Final.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.semester1Final.name), PorterDuff.Mode.MULTIPLY)); - if (showSemester == 1) { - holder.gradesSubjectPreviewFinal.setVisibility(View.VISIBLE); - holder.gradesSubjectPreviewFinal.setText(model.semester1Final.name); - holder.gradesSubjectPreviewFinal.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.semester1Final.name), PorterDuff.Mode.MULTIPLY)); - } - } - else { - holder.gradesSubjectSemester1Final.setVisibility(View.GONE); - if (showSemester == 1) { - holder.gradesSubjectPreviewFinal.setVisibility(View.GONE); - } - } - } - else { - holder.gradesSubjectSemester1Header.setVisibility(View.GONE); - holder.gradesSubjectSemester1Container.setVisibility(View.GONE); - } - - if (model.grades2.size() > 0) { - holder.gradesSubjectSemester2Nest.setNestedScrollingEnabled(false); - holder.gradesSubjectSemester2Content.setHasFixedSize(false); - holder.gradesSubjectSemester2Content.setNestedScrollingEnabled(false); - holder.gradesSubjectSemester2Content.setLayoutManager(new LinearLayoutManager(activity)); - holder.gradesSubjectSemester2Content.setAdapter(new GradesListAdapter(activity, model.grades2)); - holder.gradesSubjectSemester2Header.setVisibility(View.VISIBLE); - if (showSemester == 2) { - holder.gradesSubjectSemester2Container.setVisibility(View.VISIBLE); - } - else { - holder.gradesSubjectSemester2Container.setVisibility(View.GONE); - } - - if (model.isDescriptiveSubject && !model.isNormalSubject && !model.isPointSubject && !model.isBehaviourSubject) { - holder.gradesSubjectPreviewAverage.setVisibility(View.GONE); - holder.gradesSubjectSemester2Average.setVisibility(View.GONE); - } - else { - holder.gradesSubjectPreviewAverage.setVisibility(View.VISIBLE); - holder.gradesSubjectSemester2Average.setVisibility(View.VISIBLE); - // PREVIEW AVERAGE - int formatDouble = (model.isPointSubject ? R.string.grades_average_double_percent_format : model.isBehaviourSubject ? R.string.grades_average_double_point_format : R.string.grades_average_double_format); - int format = (model.isPointSubject ? R.string.grades_semester_average_percent_format : model.isBehaviourSubject ? R.string.grades_semester_average_point_format : R.string.grades_semester_average_format); - if (showSemester == 2) { - if (model.semester2Proposed != null || model.semester2Final != null) { - holder.gradesSubjectPreviewAverage.setText(invalidAvg(model.semester2Average) ? "-" : df.format(model.semester2Average)); - holder.gradesSubjectPreviewYearAverage.setText(invalidAvg(model.yearAverage) ? "-" : df.format(model.yearAverage)); - holder.gradesSubjectPreviewYearAverage.setVisibility(View.VISIBLE); - } - else { - holder.gradesSubjectPreviewAverage.setText( - getContext().getString( - formatDouble, - invalidAvg(model.semester2Average) ? "-" : df.format(model.semester2Average), - invalidAvg(model.yearAverage) ? "-" : df.format(model.yearAverage) - ) - ); - holder.gradesSubjectPreviewYearAverage.setVisibility(View.GONE); - } - } - // AVERAGE value - holder.gradesSubjectSemester2Average.setText( - getContext().getString( - format, - 2, - invalidAvg(model.semester2Average) ? "-" : df.format(model.semester2Average) - ) - ); - } - - // PROPOSED grade - if (model.semester2Proposed != null) { - holder.gradesSubjectSemester2Proposed.setVisibility(View.VISIBLE); - holder.gradesSubjectSemester2Proposed.setText(model.semester2Proposed.name); - holder.gradesSubjectSemester2Proposed.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.semester2Proposed.name), PorterDuff.Mode.MULTIPLY)); - holder.gradesSubjectSemester2Proposed.setTextColor(Colors.gradeNameToColor(model.semester2Proposed.name)); - if (showSemester == 2) { - holder.gradesSubjectPreviewProposed.setVisibility(View.VISIBLE); - holder.gradesSubjectPreviewProposed.setText(model.semester2Proposed.name); - holder.gradesSubjectPreviewProposed.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.semester2Proposed.name), PorterDuff.Mode.MULTIPLY)); - holder.gradesSubjectPreviewProposed.setTextColor(Colors.gradeNameToColor(model.semester2Proposed.name)); - } - } - else { - holder.gradesSubjectSemester2Proposed.setVisibility(View.GONE); - if (showSemester == 2) { - holder.gradesSubjectPreviewProposed.setVisibility(View.GONE); - } - } - // FINAL grade - if (model.semester2Final != null) { - holder.gradesSubjectSemester2Final.setVisibility(View.VISIBLE); - holder.gradesSubjectSemester2Final.setText(model.semester2Final.name); - holder.gradesSubjectSemester2Final.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.semester2Final.name), PorterDuff.Mode.MULTIPLY)); - if (showSemester == 2) { - holder.gradesSubjectPreviewFinal.setVisibility(View.VISIBLE); - holder.gradesSubjectPreviewFinal.setText(model.semester2Final.name); - holder.gradesSubjectPreviewFinal.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.semester2Final.name), PorterDuff.Mode.MULTIPLY)); - } - } - else { - holder.gradesSubjectSemester2Final.setVisibility(View.GONE); - if (showSemester == 2) { - holder.gradesSubjectPreviewFinal.setVisibility(View.GONE); - } - } - - if (model.isDescriptiveSubject && !model.isNormalSubject && !model.isPointSubject && !model.isBehaviourSubject) { - holder.gradesSubjectYearAverage.setVisibility(View.GONE); - } - else { - holder.gradesSubjectYearAverage.setVisibility(View.VISIBLE); - // AVERAGE value - int format = (model.isPointSubject ? R.string.grades_year_average_percent_format : model.isBehaviourSubject ? R.string.grades_year_average_point_format : R.string.grades_year_average_format); - holder.gradesSubjectYearAverage.setText( - getContext().getString( - format, - invalidAvg(model.yearAverage) ? "-" : df.format(model.yearAverage) - ) - ); - } - - // PROPOSED grade - if (model.yearProposed != null) { - holder.gradesSubjectYearProposed.setVisibility(View.VISIBLE); - holder.gradesSubjectYearProposed.setText(model.yearProposed.name); - holder.gradesSubjectYearProposed.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.yearProposed.name), PorterDuff.Mode.MULTIPLY)); - holder.gradesSubjectYearProposed.setTextColor(Colors.gradeNameToColor(model.yearProposed.name)); - if (showSemester == 2) { - holder.gradesSubjectPreviewYearProposed.setVisibility(View.VISIBLE); - holder.gradesSubjectPreviewYearProposed.setText(model.yearProposed.name); - holder.gradesSubjectPreviewYearProposed.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.yearProposed.name), PorterDuff.Mode.MULTIPLY)); - holder.gradesSubjectPreviewYearProposed.setTextColor(Colors.gradeNameToColor(model.yearProposed.name)); - } - } - else { - holder.gradesSubjectYearProposed.setVisibility(View.GONE); - if (showSemester == 2) { - holder.gradesSubjectPreviewYearProposed.setVisibility(View.GONE); - } - } - // FINAL grade - if (model.yearFinal != null) { - holder.gradesSubjectYearFinal.setVisibility(View.VISIBLE); - holder.gradesSubjectYearFinal.setText(model.yearFinal.name); - holder.gradesSubjectYearFinal.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.yearFinal.name), PorterDuff.Mode.MULTIPLY)); - if (showSemester == 2) { - holder.gradesSubjectPreviewYearFinal.setVisibility(View.VISIBLE); - holder.gradesSubjectPreviewYearFinal.setText(model.yearFinal.name); - holder.gradesSubjectPreviewYearFinal.getBackground().setColorFilter(new PorterDuffColorFilter(Colors.gradeNameToColor(model.yearFinal.name), PorterDuff.Mode.MULTIPLY)); - } - } - else { - holder.gradesSubjectYearFinal.setVisibility(View.GONE); - if (showSemester == 2) { - holder.gradesSubjectPreviewYearFinal.setVisibility(View.GONE); - } - } - } - else { - holder.gradesSubjectSemester2Header.setVisibility(View.GONE); - holder.gradesSubjectSemester2Container.setVisibility(View.GONE); - } - - // decrease the width by average, proposed, final and semester TextViews - holder.gradesSubjectPreviewContainer.measure(WRAP_CONTENT, MATCH_PARENT); - //Log.d(TAG, "gradesSubjectPreviewContainer "+holder.gradesSubjectPreviewContainer.getMeasuredWidth()); - - /*holder.gradesSubjectPreviewAverage.measure(WRAP_CONTENT, WRAP_CONTENT); - maxWidthPx -= holder.gradesSubjectPreviewAverage.getMeasuredWidth(); - maxWidthPx -= 2*_5dp; - if (holder.gradesSubjectPreviewProposed.getVisibility() == View.VISIBLE) { - holder.gradesSubjectPreviewProposed.measure(WRAP_CONTENT, WRAP_CONTENT); - maxWidthPx -= holder.gradesSubjectPreviewProposed.getMeasuredWidth(); - maxWidthPx -= _5dp; - } - if (holder.gradesSubjectPreviewFinal.getVisibility() == View.VISIBLE) { - holder.gradesSubjectPreviewFinal.measure(WRAP_CONTENT, WRAP_CONTENT); - maxWidthPx -= holder.gradesSubjectPreviewFinal.getMeasuredWidth(); - maxWidthPx -= _5dp; - }*/ - maxWidthPx -= holder.gradesSubjectPreviewContainer.getMeasuredWidth(); - maxWidthPx -= _5dp; - - for (GradeFull grade: gradeList) { - if (grade.semester != showSemester) - continue; - - int gradeColor; - if (model.colorMode == COLOR_MODE_DEFAULT) { - gradeColor = grade.color; - } else { - gradeColor = Colors.gradeToColor(grade); - } - - TextView gradeName = new TextView(activity); - gradeName.setText(grade.name); - gradeName.setTextColor(ColorUtils.calculateLuminance(gradeColor) > 0.25 ? 0xff000000 : 0xffffffff); - gradeName.setPadding(_5dp, 0, _5dp, 0); - gradeName.setBackgroundResource(R.drawable.bg_rounded_4dp); - gradeName.getBackground().setColorFilter(new PorterDuffColorFilter(gradeColor, PorterDuff.Mode.MULTIPLY)); - gradeName.setTypeface(null, Typeface.BOLD); - - gradeName.measure(WRAP_CONTENT, WRAP_CONTENT); - totalWidthPx += gradeName.getMeasuredWidth() + _5dp; - //Log.d(TAG, "totalWidthPx " + totalWidthPx); - if (totalWidthPx >= maxWidthPx) { - if (ellipsized) - continue; - ellipsized = true; - TextView ellipsisText = new TextView(activity); - ellipsisText.setText(R.string.ellipsis); - ellipsisText.setTextAppearance(activity, R.style.NavView_TextView); - ellipsisText.setTypeface(null, Typeface.BOLD); - ellipsisText.setPadding(0, 0, 0, 0); - holder.gradesSubjectPreviewContent.addView(ellipsisText, layoutParams); - } - else { - holder.gradesSubjectPreviewContent.addView(gradeName, layoutParams); - } - } - } - if (findViews) { - //Log.d("GradesSubjectAdapter", "runOnUiThread"); - //this.viewHolder.gradesSubjectContent.setTag(View.VISIBLE); - //this.viewHolder.gradesSubjectPreviewContainer.setTag(View.VISIBLE); - activity.runOnUiThread(() -> { - - holder.gradesSubjectRoot.setOnClickListener(v -> { - if (holder.gradesSubjectContent.getVisibility() == View.GONE) { - expandSubject(holder, model); - } - else { - collapseSubject(holder, model); - } - }); - - holder.gradesSubjectSemester1Header.setOnClickListener(v -> { - if (holder.gradesSubjectSemester1Container.getVisibility() == View.GONE) { - if (gradesSetAsRead(holder, model, 1)) updateBadges(getContext(), model); - - Anim.expand(holder.gradesSubjectSemester1Container, 500, null); - if (holder.gradesSubjectSemester2Container.getVisibility() != View.GONE) { - Anim.collapse(holder.gradesSubjectSemester2Container, 500, null); - } - } - else { - Anim.collapse(holder.gradesSubjectSemester1Container, 500, null); - } - }); - holder.gradesSubjectSemester2Header.setOnClickListener(v -> { - if (holder.gradesSubjectSemester2Container.getVisibility() == View.GONE) { - if (gradesSetAsRead(holder, model, 2)) updateBadges(getContext(), model); - - Anim.expand(holder.gradesSubjectSemester2Container, 500, null); - if (holder.gradesSubjectSemester1Container.getVisibility() != View.GONE) { - Anim.collapse(holder.gradesSubjectSemester1Container, 500, null); - } - } - else { - Anim.collapse(holder.gradesSubjectSemester2Container, 500, null); - } - }); - - // hide the grade simulator when there are point, behaviour or descriptive grades - if (model.isPointSubject || model.isBehaviourSubject || (model.isDescriptiveSubject && !model.isNormalSubject)) { - holder.gradesSubjectSemester1EditButton.setVisibility(View.GONE); - holder.gradesSubjectSemester2EditButton.setVisibility(View.GONE); - } - else { - holder.gradesSubjectSemester1EditButton.setVisibility(View.VISIBLE); - holder.gradesSubjectSemester1EditButton.setOnClickListener(v -> { - Bundle arguments = new Bundle(); - - if (model.subject != null) { - arguments.putLong("subjectId", model.subject.id); - } - arguments.putInt("semester", 1); - //d(TAG, "Model is " + model); - switch (model.yearAverageMode) { - case YEAR_1_SEM_2_AVG: - case YEAR_1_SEM_2_SEM: - arguments.putInt("averageMode", -1); - break; - default: - arguments.putInt("averageMode", model.semester2Final == null && model.yearAverageMode == YEAR_1_AVG_2_SEM ? -1 : model.yearAverageMode); - arguments.putFloat("yearAverageBefore", model.yearAverage); - arguments.putFloat("gradeSumOtherSemester", model.gradeSumSemester2); - arguments.putFloat("gradeCountOtherSemester", model.gradeCountSemester2); - arguments.putFloat("averageOtherSemester", model.semester2Average); - arguments.putFloat("finalOtherSemester", model.semester2Final == null ? -1 : model.semester2Final.value); - break; - } - - activity.loadTarget(TARGET_GRADES_EDITOR, arguments); - }); - holder.gradesSubjectSemester2EditButton.setVisibility(View.VISIBLE); - holder.gradesSubjectSemester2EditButton.setOnClickListener(v -> { - Bundle arguments = new Bundle(); - - if (model.subject != null) { - arguments.putLong("subjectId", model.subject.id); - } - arguments.putInt("semester", 2); - //d(TAG, "Model is " + model); - switch (model.yearAverageMode) { - case YEAR_1_AVG_2_SEM: - case YEAR_1_SEM_2_SEM: - arguments.putInt("averageMode", -1); - break; - default: - arguments.putInt("averageMode", model.semester1Final == null && model.yearAverageMode == YEAR_1_SEM_2_AVG ? -1 : model.yearAverageMode); - arguments.putFloat("yearAverageBefore", model.yearAverage); - arguments.putFloat("gradeSumOtherSemester", model.gradeSumSemester1); - arguments.putFloat("gradeCountOtherSemester", model.gradeCountSemester1); - arguments.putFloat("averageOtherSemester", model.semester1Average); - arguments.putFloat("finalOtherSemester", model.semester1Final == null ? -1 : model.semester1Final.value); - break; - } - - activity.loadTarget(TARGET_GRADES_EDITOR, arguments); - }); - } - - }); - } - if (model != null && model.subject != null) { - holder.lastSubject = model.subject.id; - } - super.onPostExecute(aVoid); - } - } - - //getting the context and product list with constructor - public GradesSubjectAdapter(List data, MainActivity context) { - super(context, R.layout.row_grades_subject_item, data); - this.activity = context; - this.subjectList = data; - } - - @Override - public void onClick(View v) { - int position = (Integer) v.getTag(); - Object object = getItem(position); - ItemGradesSubjectModel dataModel = (ItemGradesSubjectModel)object; - - } - - private void findViews(ViewHolder holder, View root) { - //holder.gradesSubjectRoot = root.findViewById(R.id.gradesSubjectRoot); - holder.gradesSubjectTitle = root.findViewById(R.id.gradesSubjectTitle); - holder.gradesSubjectExpandIndicator = root.findViewById(R.id.gradesSubjectExpandIndicator); - - holder.gradesSubjectPreviewContainer = root.findViewById(R.id.gradesSubjectPreviewContainer); - holder.gradesSubjectPreviewSemester = root.findViewById(R.id.gradesSubjectPreviewSemester); - holder.gradesSubjectPreviewContent = root.findViewById(R.id.gradesSubjectPreviewContent); - holder.gradesSubjectPreviewAverage = root.findViewById(R.id.gradesSubjectPreviewAverage); - holder.gradesSubjectPreviewProposed = root.findViewById(R.id.gradesSubjectPreviewProposed); - holder.gradesSubjectPreviewFinal = root.findViewById(R.id.gradesSubjectPreviewFinal); - holder.gradesSubjectPreviewYearAverage = root.findViewById(R.id.gradesSubjectPreviewYearAverage); - holder.gradesSubjectPreviewYearProposed = root.findViewById(R.id.gradesSubjectPreviewYearProposed); - holder.gradesSubjectPreviewYearFinal = root.findViewById(R.id.gradesSubjectPreviewYearFinal); - - holder.gradesSubjectContent = root.findViewById(R.id.gradesSubjectContent); - - holder.gradesSubjectSemester1Header = root.findViewById(R.id.gradesSubjectSemester1Header); - holder.gradesSubjectSemester1Title = root.findViewById(R.id.gradesSubjectSemester1Title); - holder.gradesSubjectSemester1ExpandIndicator = root.findViewById(R.id.gradesSubjectSemester1ExpandIndicator); - holder.gradesSubjectSemester1Average = root.findViewById(R.id.gradesSubjectSemester1Average); - holder.gradesSubjectSemester1Proposed = root.findViewById(R.id.gradesSubjectSemester1Proposed); - holder.gradesSubjectSemester1Final = root.findViewById(R.id.gradesSubjectSemester1Final); - holder.gradesSubjectSemester1EditButton = root.findViewById(R.id.gradesSubjectSemester1EditButton); - holder.gradesSubjectSemester1Container = root.findViewById(R.id.gradesSubjectSemester1Container); - holder.gradesSubjectSemester1Nest = root.findViewById(R.id.gradesSubjectSemester1Nest); - holder.gradesSubjectSemester1Content = root.findViewById(R.id.gradesSubjectSemester1Content); - - holder.gradesSubjectSemester2Header = root.findViewById(R.id.gradesSubjectSemester2Header); - holder.gradesSubjectSemester2Title = root.findViewById(R.id.gradesSubjectSemester2Title); - holder.gradesSubjectSemester2ExpandIndicator = root.findViewById(R.id.gradesSubjectSemester2ExpandIndicator); - holder.gradesSubjectSemester2Average = root.findViewById(R.id.gradesSubjectSemester2Average); - holder.gradesSubjectSemester2Proposed = root.findViewById(R.id.gradesSubjectSemester2Proposed); - holder.gradesSubjectSemester2Final = root.findViewById(R.id.gradesSubjectSemester2Final); - holder.gradesSubjectSemester2EditButton = root.findViewById(R.id.gradesSubjectSemester2EditButton); - holder.gradesSubjectSemester2Container = root.findViewById(R.id.gradesSubjectSemester2Container); - holder.gradesSubjectSemester2Nest = root.findViewById(R.id.gradesSubjectSemester2Nest); - holder.gradesSubjectSemester2Content = root.findViewById(R.id.gradesSubjectSemester2Content); - - holder.gradesSubjectYearAverage = root.findViewById(R.id.gradesSubjectYearAverage); - holder.gradesSubjectYearProposed = root.findViewById(R.id.gradesSubjectYearProposed); - holder.gradesSubjectYearFinal = root.findViewById(R.id.gradesSubjectYearFinal); - } - - @NonNull - @Override - public View getView(int position, View convertView, @NonNull ViewGroup parent) { - if (position >= subjectList.size()) { - return convertView; - } - ItemGradesSubjectModel model = subjectList.get(position); - if (model == null) { - //Toast.makeText(activity, "return convertView;", Toast.LENGTH_SHORT).show(); - return convertView; - } - ViewHolder holder; - if (convertView == null) { - try { - convertView = LayoutInflater.from(activity).inflate(R.layout.row_grades_subject_item, parent, false); - holder = new ViewHolder(); - holder.gradesSubjectRoot = convertView.findViewById(R.id.gradesSubjectRoot); - convertView.setTag(holder); - new BuildGradeViews(model, holder, parent, position, true).execute(); - return convertView; - } catch (Exception e) { - return new View(getContext()); - } - } - holder = (ViewHolder) convertView.getTag(); - Subject subject = model.subject; - holder.gradesSubjectTitle.setText(subject != null ? subject.longName : ""); - /*if (model.getNotSeen() > 0) { - viewHolder.notseen.setVisibility(0); - viewHolder.notseen.setText(model.getNotSeen() + ""); - } else { - viewHolder.notseen.setVisibility(8); - }*/ - new BuildGradeViews(model, holder, parent, position, false).execute(); - return convertView; - } - - public int getViewTypeCount() { - return getCount(); - } - - public int getItemViewType(int position) { - return position; - } - - class ViewHolder { - long lastSubject; - - TextView gradesSubjectTitle; - ConstraintLayout gradesSubjectRoot; - IconicsImageView gradesSubjectExpandIndicator; - - LinearLayout gradesSubjectPreviewContainer; - TextView gradesSubjectPreviewSemester; - LinearLayout gradesSubjectPreviewContent; - TextView gradesSubjectPreviewAverage; - TextView gradesSubjectPreviewProposed; - TextView gradesSubjectPreviewFinal; - TextView gradesSubjectPreviewYearAverage; - TextView gradesSubjectPreviewYearProposed; - TextView gradesSubjectPreviewYearFinal; - - LinearLayout gradesSubjectContent; - - LinearLayout gradesSubjectSemester1Header; - TextView gradesSubjectSemester1Title; - IconicsImageView gradesSubjectSemester1ExpandIndicator; - TextView gradesSubjectSemester1Average; - TextView gradesSubjectSemester1Proposed; - TextView gradesSubjectSemester1Final; - IconicsImageView gradesSubjectSemester1EditButton; - LinearLayout gradesSubjectSemester1Container; - NestedScrollView gradesSubjectSemester1Nest; - RecyclerView gradesSubjectSemester1Content; - - LinearLayout gradesSubjectSemester2Header; - TextView gradesSubjectSemester2Title; - IconicsImageView gradesSubjectSemester2ExpandIndicator; - TextView gradesSubjectSemester2Average; - TextView gradesSubjectSemester2Proposed; - TextView gradesSubjectSemester2Final; - IconicsImageView gradesSubjectSemester2EditButton; - LinearLayout gradesSubjectSemester2Container; - NestedScrollView gradesSubjectSemester2Nest; - RecyclerView gradesSubjectSemester2Content; - - TextView gradesSubjectYearAverage; - TextView gradesSubjectYearProposed; - TextView gradesSubjectYearFinal; - } -} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/editor/GradesEditorFragment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/editor/GradesEditorFragment.kt index 00dd33f0..b2ffdd71 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/editor/GradesEditorFragment.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/editor/GradesEditorFragment.kt @@ -14,13 +14,13 @@ import androidx.recyclerview.widget.LinearLayoutManager import com.afollestad.materialdialogs.MaterialDialog import pl.szczodrzynski.edziennik.* import pl.szczodrzynski.edziennik.data.db.entity.Grade -import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.YEAR_1_AVG_2_AVG -import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.YEAR_1_AVG_2_SEM -import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.YEAR_1_SEM_2_AVG -import pl.szczodrzynski.edziennik.data.db.entity.Profile.Companion.YEAR_ALL_GRADES import pl.szczodrzynski.edziennik.databinding.FragmentGradesEditorBinding import pl.szczodrzynski.edziennik.utils.Colors import pl.szczodrzynski.edziennik.utils.Themes +import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_1_AVG_2_AVG +import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_1_AVG_2_SEM +import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_1_SEM_2_AVG +import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.YEAR_ALL_GRADES import java.text.DecimalFormat import java.util.* import kotlin.math.floor diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/ExpandableItemModel.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/ExpandableItemModel.kt new file mode 100644 index 00000000..c52ba310 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/ExpandableItemModel.kt @@ -0,0 +1,12 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2020-2-29. + */ + +package pl.szczodrzynski.edziennik.ui.modules.grades.models + +import pl.szczodrzynski.edziennik.ui.modules.grades.GradesAdapter.Companion.STATE_CLOSED + +abstract class ExpandableItemModel(val items: MutableList) { + open var level: Int = 3 + var state: Int = STATE_CLOSED +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/GradesAverages.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/GradesAverages.kt new file mode 100644 index 00000000..185710d1 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/GradesAverages.kt @@ -0,0 +1,20 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2020-3-1. + */ + +package pl.szczodrzynski.edziennik.ui.modules.grades.models + +class GradesAverages { + var normalSum = 0f + var normalCount = 0 + var normalWeightedSum = 0f + var normalWeightedCount = 0f + + var pointSum = 0f + + var pointAvgSum = 0f + var pointAvgMax = 0f + + var normalAvg: Float? = null + var pointAvgPercent: Float? = null +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/GradesEmpty.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/GradesEmpty.kt new file mode 100644 index 00000000..4b726f3f --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/GradesEmpty.kt @@ -0,0 +1,7 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2020-3-1. + */ + +package pl.szczodrzynski.edziennik.ui.modules.grades.models + +class GradesEmpty diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/GradesSemester.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/GradesSemester.kt new file mode 100644 index 00000000..94d96acf --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/GradesSemester.kt @@ -0,0 +1,20 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2020-2-29. + */ + +package pl.szczodrzynski.edziennik.ui.modules.grades.models + +import pl.szczodrzynski.edziennik.data.db.entity.Grade +import pl.szczodrzynski.edziennik.data.db.full.GradeFull + +data class GradesSemester( + val subjectId: Long, + val number: Int, + val grades: MutableList = mutableListOf() +) : ExpandableItemModel(grades) { + override var level = 2 + + val averages = GradesAverages() + var proposedGrade: GradeFull? = null + var finalGrade: GradeFull? = null +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/GradesStats.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/GradesStats.kt new file mode 100644 index 00000000..76833b45 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/GradesStats.kt @@ -0,0 +1,25 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2020-3-3. + */ + +package pl.szczodrzynski.edziennik.ui.modules.grades.models + +class GradesStats { + var normalSem1 = 0f + var normalSem1Proposed = 0f + var normalSem1Final = 0f + var normalSem2 = 0f + var normalSem2Proposed = 0f + var normalSem2Final = 0f + var normalYearly = 0f + var normalYearlyProposed = 0f + var normalYearlyFinal = 0f + + var sem1NotAllFinal = false + var sem2NotAllFinal = false + var yearlyNotAllFinal = false + + var pointSem1 = 0f + var pointSem2 = 0f + var pointYearly = 0f +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/GradesSubject.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/GradesSubject.kt new file mode 100644 index 00000000..abd4ce47 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/models/GradesSubject.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2020-2-29. + */ + +package pl.szczodrzynski.edziennik.ui.modules.grades.models + +import pl.szczodrzynski.edziennik.data.db.full.GradeFull + +data class GradesSubject( + val subjectId: Long, + val subjectName: String, + val semesters: MutableList = mutableListOf() +) : ExpandableItemModel(semesters) { + override var level = 1 + + var lastAddedDate = 0L + var semester: Int = 1 + + val averages = GradesAverages() + var proposedGrade: GradeFull? = null + var finalGrade: GradeFull? = null +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/BindableViewHolder.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/BindableViewHolder.kt new file mode 100644 index 00000000..75dba275 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/BindableViewHolder.kt @@ -0,0 +1,12 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2020-2-29. + */ + +package pl.szczodrzynski.edziennik.ui.modules.grades.viewholder + +import androidx.appcompat.app.AppCompatActivity +import pl.szczodrzynski.edziennik.App + +interface BindableViewHolder { + fun onBind(activity: AppCompatActivity, app: App, item: T, position: Int) +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/EmptyViewHolder.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/EmptyViewHolder.kt new file mode 100644 index 00000000..3665e182 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/EmptyViewHolder.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2020-3-1. + */ + +package pl.szczodrzynski.edziennik.ui.modules.grades.viewholder + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.recyclerview.widget.RecyclerView +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.databinding.GradesItemEmptyBinding +import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesEmpty + +class EmptyViewHolder( + inflater: LayoutInflater, + parent: ViewGroup, + val b: GradesItemEmptyBinding = GradesItemEmptyBinding.inflate(inflater, parent, false) +) : RecyclerView.ViewHolder(b.root), BindableViewHolder { + companion object { + private const val TAG = "EmptyViewHolder" + } + + override fun onBind(activity: AppCompatActivity, app: App, item: GradesEmpty, position: Int) { + + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/GradeViewHolder.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/GradeViewHolder.kt new file mode 100644 index 00000000..6cb589a7 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/GradeViewHolder.kt @@ -0,0 +1,63 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2020-2-29. + */ + +package pl.szczodrzynski.edziennik.ui.modules.grades.viewholder + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.recyclerview.widget.RecyclerView +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.data.db.full.GradeFull +import pl.szczodrzynski.edziennik.databinding.GradesItemGradeBinding +import pl.szczodrzynski.edziennik.utils.models.Date + +class GradeViewHolder( + inflater: LayoutInflater, + parent: ViewGroup, + val b: GradesItemGradeBinding = GradesItemGradeBinding.inflate(inflater, parent, false) +) : RecyclerView.ViewHolder(b.root), BindableViewHolder { + companion object { + private const val TAG = "GradeViewHolder" + } + + @Suppress("PARAMETER_NAME_CHANGED_ON_OVERRIDE") + override fun onBind(activity: AppCompatActivity, app: App, grade: GradeFull, position: Int) { + val manager = app.gradesManager + + b.gradeName.setGrade(grade, manager, bigView = true) + + if (grade.description.isNullOrBlank()) { + b.gradeDescription.text = grade.category + b.gradeCategory.text = + if (grade.isImprovement) + app.getString(R.string.grades_improvement_category_format, "") + else + "" + } else { + b.gradeDescription.text = grade.description + b.gradeCategory.text = + if (grade.isImprovement) + app.getString(R.string.grades_improvement_category_format, grade.category) + else + grade.category + } + + b.gradeWeight.text = manager.getWeightString(activity, grade, showClassAverage = true) + + b.gradeTeacherName.text = grade.teacherFullName + b.gradeAddedDate.text = Date.fromMillis(grade.addedDate).let { + it.getRelativeString(app, 5) ?: it.formattedStringShort + } + + /*if (!grade.seen) { + b.gradeDescription.setBackground(mContext.getResources().getDrawable(R.drawable.bg_rounded_4dp)) + b.gradeDescription.getBackground() + .setColorFilter(PorterDuffColorFilter(0x692196f3, PorterDuff.Mode.MULTIPLY)) + } else { + b.gradeDescription.setBackground(null) + }*/ + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/SemesterViewHolder.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/SemesterViewHolder.kt new file mode 100644 index 00000000..7e8ef900 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/SemesterViewHolder.kt @@ -0,0 +1,39 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2020-2-29. + */ + +package pl.szczodrzynski.edziennik.ui.modules.grades.viewholder + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.recyclerview.widget.RecyclerView +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.databinding.GradesItemSemesterBinding +import pl.szczodrzynski.edziennik.setText +import pl.szczodrzynski.edziennik.ui.modules.grades.GradesAdapter +import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesSemester + +class SemesterViewHolder( + inflater: LayoutInflater, + parent: ViewGroup, + val b: GradesItemSemesterBinding = GradesItemSemesterBinding.inflate(inflater, parent, false) +) : RecyclerView.ViewHolder(b.root), BindableViewHolder { + companion object { + private const val TAG = "SemesterViewHolder" + } + + override fun onBind(activity: AppCompatActivity, app: App, item: GradesSemester, position: Int) { + val manager = app.gradesManager + b.semesterName.setText(R.string.grades_semester_format, item.number) + b.dropdownIcon.rotation = when (item.state) { + GradesAdapter.STATE_CLOSED -> 0f + else -> 180f + } + + b.average.text = manager.getAverageString(app, item.averages) + b.proposedGrade.setGrade(item.proposedGrade, manager) + b.finalGrade.setGrade(item.finalGrade, manager) + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/StatsViewHolder.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/StatsViewHolder.kt new file mode 100644 index 00000000..5aa1fc4d --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/StatsViewHolder.kt @@ -0,0 +1,142 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2020-3-3. + */ + +package pl.szczodrzynski.edziennik.ui.modules.grades.viewholder + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.core.view.isVisible +import androidx.recyclerview.widget.RecyclerView +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.databinding.GradesItemStatsBinding +import pl.szczodrzynski.edziennik.onClick +import pl.szczodrzynski.edziennik.ui.dialogs.settings.GradesConfigDialog +import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesStats +import java.text.DecimalFormat + +class StatsViewHolder( + inflater: LayoutInflater, + parent: ViewGroup, + val b: GradesItemStatsBinding = GradesItemStatsBinding.inflate(inflater, parent, false) +) : RecyclerView.ViewHolder(b.root), BindableViewHolder { + companion object { + private const val TAG = "StatsViewHolder" + } + + override fun onBind(activity: AppCompatActivity, app: App, item: GradesStats, position: Int) { + val manager = app.gradesManager + val showAverages = mutableListOf() + val showPoint = mutableListOf() + + getSemesterString(app, item.normalSem1, item.normalSem1Proposed, item.normalSem1Final, item.sem1NotAllFinal).let { (average, notice) -> + b.normalSemester1Layout.isVisible = average != null + b.normalSemester1Notice.isVisible = notice != null + b.normalSemester1.text = average + b.normalSemester1Notice.text = notice + if (average != null) + showAverages += 1 + } + getSemesterString(app, item.normalSem2, item.normalSem2Proposed, item.normalSem2Final, item.sem2NotAllFinal).let { (average, notice) -> + b.normalSemester2Layout.isVisible = average != null + b.normalSemester2Notice.isVisible = notice != null + b.normalSemester2.text = average + b.normalSemester2Notice.text = notice + if (average != null) + showAverages += 2 + } + getSemesterString(app, item.normalYearly, item.normalYearlyProposed, item.normalYearlyFinal, item.yearlyNotAllFinal).let { (average, notice) -> + b.normalYearlyLayout.isVisible = average != null + b.normalYearlyNotice.isVisible = notice != null + b.normalYearly.text = average + b.normalYearlyNotice.text = notice + if (average != null) + showAverages += 3 + } + + b.normalTitle.isVisible = showAverages.size > 0 + b.normalLayout.isVisible = showAverages.size > 0 + b.normalDivider.isVisible = showAverages.size > 0 + b.helpButton.isVisible = showAverages.size > 0 + b.normalDiv1.isVisible = showAverages.contains(1) && showAverages.contains(2) || showAverages.contains(1) && showAverages.contains(3) + b.normalDiv2.isVisible = showAverages.contains(2) && showAverages.contains(3) + + getSemesterString(app, 0f, 0f, item.pointSem1, false).let { (average, _) -> + b.pointSemester1Layout.isVisible = average != null + b.pointSemester1.text = average + if (average != null) + showPoint += 1 + } + getSemesterString(app, 0f, 0f, item.pointSem2, false).let { (average, _) -> + b.pointSemester2Layout.isVisible = average != null + b.pointSemester2.text = average + if (average != null) + showPoint += 2 + } + getSemesterString(app, 0f, 0f, item.pointYearly, false).let { (average, _) -> + b.pointYearlyLayout.isVisible = average != null + b.pointYearly.text = average + if (average != null) + showPoint += 3 + } + + b.pointTitle.isVisible = showPoint.size > 0 + b.pointLayout.isVisible = showPoint.size > 0 + b.pointDivider.isVisible = showPoint.size > 0 + b.pointDiv1.isVisible = showPoint.contains(1) && showPoint.contains(2) + b.pointDiv2.isVisible = showPoint.contains(2) && showPoint.contains(3) + + b.noData.isVisible = showAverages.isEmpty() && showPoint.isEmpty() + b.disclaimer.isVisible = !b.noData.isVisible + + b.helpButton.onClick { + MaterialAlertDialogBuilder(activity) + .setTitle(R.string.grades_stats_help_title) + .setMessage(R.string.grades_stats_help_text) + .setPositiveButton(R.string.ok, null) + .show() + } + + b.customValueDivider.isVisible = manager.plusValue != null || manager.minusValue != null + b.customValueLayout.isVisible = b.customValueDivider.isVisible + b.customValueButton.onClick { + GradesConfigDialog(activity, reloadOnDismiss = true) + } + } + + private fun getSemesterString(context: Context, expected: Float, proposed: Float, final: Float, notAllFinal: Boolean) : Pair { + val format = DecimalFormat("#.##") + + val average = when { + final != 0f -> final + proposed != 0f -> proposed + expected != 0f -> expected + else -> null + }?.let { + format.format(it) + } + + val notice = when { + final != 0f -> when { + notAllFinal -> if (expected != 0f) + context.getString(R.string.grades_stats_from_final, format.format(expected)) + else + context.getString(R.string.grades_stats_from_final_no_expected) + proposed != 0f -> context.getString(R.string.grades_stats_proposed_avg, format.format(proposed)) + else -> null + } + proposed != 0f -> if (expected != 0f) + context.getString(R.string.grades_stats_from_proposed, format.format(expected)) + else + context.getString(R.string.grades_stats_from_proposed_no_expected) + expected != 0f -> context.getString(R.string.grades_stats_expected) + else -> null + } + + return average to notice + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/SubjectViewHolder.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/SubjectViewHolder.kt new file mode 100644 index 00000000..f67a8c70 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/grades/viewholder/SubjectViewHolder.kt @@ -0,0 +1,134 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2020-2-29. + */ + +package pl.szczodrzynski.edziennik.ui.modules.grades.viewholder + +import android.text.TextUtils +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.ViewGroup.LayoutParams.WRAP_CONTENT +import android.widget.LinearLayout +import android.widget.TextView +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.view.ContextThemeWrapper +import androidx.core.view.get +import androidx.recyclerview.widget.RecyclerView +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.databinding.GradesItemSubjectBinding +import pl.szczodrzynski.edziennik.dp +import pl.szczodrzynski.edziennik.setText +import pl.szczodrzynski.edziennik.ui.modules.grades.GradeView +import pl.szczodrzynski.edziennik.ui.modules.grades.GradesAdapter.Companion.STATE_CLOSED +import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesSubject +import pl.szczodrzynski.edziennik.utils.Themes + +class SubjectViewHolder( + inflater: LayoutInflater, + parent: ViewGroup, + val b: GradesItemSubjectBinding = GradesItemSubjectBinding.inflate(inflater, parent, false) +) : RecyclerView.ViewHolder(b.root), BindableViewHolder { + companion object { + private const val TAG = "SubjectViewHolder" + } + + override fun onBind(activity: AppCompatActivity, app: App, item: GradesSubject, position: Int) { + val manager = app.gradesManager + val contextWrapper = ContextThemeWrapper(activity, Themes.themeInt) + + b.subjectName.text = item.subjectName + b.dropdownIcon.rotation = when (item.state) { + STATE_CLOSED -> 0f + else -> 180f + } + + b.previewContainer.visibility = if (item.state == STATE_CLOSED) View.VISIBLE else View.INVISIBLE + b.yearSummary.visibility = if (item.state == STATE_CLOSED) View.INVISIBLE else View.VISIBLE + + val gradesContainer = b.previewContainer[0] + b.previewContainer.removeAllViews() + b.gradesContainer.removeAllViews() + b.previewContainer.addView(gradesContainer) + + val firstSemester = item.semesters.firstOrNull() ?: return + + b.yearSummary.text = manager.getYearSummaryString(app, item.semesters.map { it.grades.size }.sum(), item.averages) + + if (firstSemester.number != item.semester) { + b.gradesContainer.addView(TextView(contextWrapper).apply { + setText(R.string.grades_preview_other_semester, firstSemester.number) + setPadding(0, 0, 5.dp, 0) + maxLines = 1 + ellipsize = TextUtils.TruncateAt.END + }) + } + + /*if (firstSemester.grades.isEmpty()) { + b.previewContainer.addView(TextView(app).apply { + setText(R.string.grades_no_grades_in_semester, firstSemester.number) + }) + }*/ + + for (grade in firstSemester.grades) { + b.gradesContainer.addView(GradeView( + contextWrapper, + grade, + manager, + periodGradesTextual = false + )) + } + + b.previewContainer.addView(TextView(contextWrapper).apply { + 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 + }) + + firstSemester.proposedGrade?.let { + b.previewContainer.addView(GradeView( + contextWrapper, + it, + manager + )) + } + firstSemester.finalGrade?.let { + b.previewContainer.addView(GradeView( + contextWrapper, + it, + manager + )) + } + + if (firstSemester.number == item.semester) { + b.previewContainer.addView(TextView(contextWrapper).apply { + text = manager.getAverageString(app, item.averages, nameSemester = true) + layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT).apply { + setMargins(0, 0, 8.dp, 0) + } + maxLines = 1 + ellipsize = TextUtils.TruncateAt.END + }) + + item.proposedGrade?.let { + b.previewContainer.addView(GradeView( + contextWrapper, + it, + manager + )) + } + item.finalGrade?.let { + b.previewContainer.addView(GradeView( + contextWrapper, + it, + manager + )) + } + } + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeGradesCard.kt b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeGradesCard.kt index 8c885e54..4897c8e7 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeGradesCard.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/cards/HomeGradesCard.kt @@ -28,7 +28,12 @@ import kotlinx.coroutines.Job import pl.szczodrzynski.edziennik.App import pl.szczodrzynski.edziennik.MainActivity import pl.szczodrzynski.edziennik.R -import pl.szczodrzynski.edziennik.data.db.entity.Grade.* +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_FINAL +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_PROPOSED +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_FINAL +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_PROPOSED +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_FINAL +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_PROPOSED import pl.szczodrzynski.edziennik.data.db.entity.Profile import pl.szczodrzynski.edziennik.data.db.entity.Subject import pl.szczodrzynski.edziennik.data.db.full.GradeFull @@ -39,6 +44,7 @@ import pl.szczodrzynski.edziennik.ui.modules.home.HomeCardAdapter import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment import pl.szczodrzynski.edziennik.utils.Colors import pl.szczodrzynski.edziennik.utils.Utils +import pl.szczodrzynski.edziennik.utils.managers.GradesManager.Companion.COLOR_MODE_DEFAULT import pl.szczodrzynski.edziennik.utils.models.ItemGradesSubjectModel import kotlin.coroutines.CoroutineContext @@ -122,7 +128,7 @@ class HomeGradesCard( subject.grades1.onEach { grade -> val gradeColor = when (App.config.forProfile().grades.colorMode) { - Profile.COLOR_MODE_DEFAULT -> grade.color + COLOR_MODE_DEFAULT -> grade.color else -> Colors.gradeToColor(grade) } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java index 1fd274f3..58b67473 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/settings/SettingsNewFragment.java @@ -64,14 +64,14 @@ import static android.app.Activity.RESULT_OK; import static pl.szczodrzynski.edziennik.ExtensionsKt.initDefaultLocale; import static pl.szczodrzynski.edziennik.data.db.entity.Profile.REGISTRATION_DISABLED; import static pl.szczodrzynski.edziennik.data.db.entity.Profile.REGISTRATION_ENABLED; -import static pl.szczodrzynski.edziennik.data.db.entity.Profile.YEAR_1_AVG_2_AVG; -import static pl.szczodrzynski.edziennik.data.db.entity.Profile.YEAR_1_AVG_2_SEM; -import static pl.szczodrzynski.edziennik.data.db.entity.Profile.YEAR_1_SEM_2_AVG; -import static pl.szczodrzynski.edziennik.data.db.entity.Profile.YEAR_1_SEM_2_SEM; -import static pl.szczodrzynski.edziennik.data.db.entity.Profile.YEAR_ALL_GRADES; import static pl.szczodrzynski.edziennik.utils.Utils.d; import static pl.szczodrzynski.edziennik.utils.Utils.getRealPathFromURI; import static pl.szczodrzynski.edziennik.utils.Utils.getResizedBitmap; +import static pl.szczodrzynski.edziennik.utils.managers.GradesManager.YEAR_1_AVG_2_AVG; +import static pl.szczodrzynski.edziennik.utils.managers.GradesManager.YEAR_1_AVG_2_SEM; +import static pl.szczodrzynski.edziennik.utils.managers.GradesManager.YEAR_1_SEM_2_AVG; +import static pl.szczodrzynski.edziennik.utils.managers.GradesManager.YEAR_1_SEM_2_SEM; +import static pl.szczodrzynski.edziennik.utils.managers.GradesManager.YEAR_ALL_GRADES; public class SettingsNewFragment extends MaterialAboutFragment { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/utils/Colors.java b/app/src/main/java/pl/szczodrzynski/edziennik/utils/Colors.java index 65bc6626..1f6c7ad3 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/utils/Colors.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/Colors.java @@ -117,17 +117,17 @@ public class Colors { public static int gradeToColor(Grade grade) { - if (grade.type == Grade.TYPE_POINT_SUM) { - return grade.value < 0 ? 0xfff44336 : grade.value > 0 ? 0xff4caf50 : 0xffbdbdbd; + if (grade.getType() == Grade.TYPE_POINT_SUM) { + return grade.getValue() < 0 ? 0xfff44336 : grade.getValue() > 0 ? 0xff4caf50 : 0xffbdbdbd; } - else if (grade.type == Grade.TYPE_POINT_AVG) { - return Color.parseColor("#"+gradeValueToColorStr(grade.value/grade.valueMax*100)); + else if (grade.getType() == Grade.TYPE_POINT_AVG) { + return Color.parseColor("#"+gradeValueToColorStr(grade.getValue()/grade.getValueMax()*100)); } - else if (grade.type == Grade.TYPE_DESCRIPTIVE || grade.type == Grade.TYPE_DESCRIPTIVE_TEXT || grade.type == Grade.TYPE_TEXT) { - return grade.color; + else if (grade.getType() == Grade.TYPE_DESCRIPTIVE || grade.getType() == Grade.TYPE_DESCRIPTIVE_TEXT || grade.getType() == Grade.TYPE_TEXT) { + return grade.getColor(); } else { - return Color.parseColor("#"+gradeNameToColorStr(grade.name)); + return Color.parseColor("#"+gradeNameToColorStr(grade.getName())); } } 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 new file mode 100644 index 00000000..294264a5 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/utils/managers/GradesManager.kt @@ -0,0 +1,227 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2020-3-1. + */ + +package pl.szczodrzynski.edziennik.utils.managers + +import android.content.Context +import pl.szczodrzynski.edziennik.* +import pl.szczodrzynski.edziennik.data.db.entity.Grade +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_NORMAL +import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_POINT_AVG +import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesAverages +import pl.szczodrzynski.edziennik.ui.modules.grades.models.GradesSemester +import pl.szczodrzynski.edziennik.utils.Colors +import java.text.DecimalFormat +import kotlin.math.floor + +class GradesManager(val app: App) { + companion object { + const val ORDER_BY_DATE_DESC = 0 + const val ORDER_BY_SUBJECT_ASC = 1 + const val ORDER_BY_DATE_ASC = 2 + const val ORDER_BY_SUBJECT_DESC = 3 + const val YEAR_1_AVG_2_AVG = 0 + const val YEAR_1_SEM_2_AVG = 1 + const val YEAR_1_AVG_2_SEM = 2 + const val YEAR_1_SEM_2_SEM = 3 + const val YEAR_ALL_GRADES = 4 + const val COLOR_MODE_DEFAULT = 0 + const val COLOR_MODE_WEIGHTED = 1 + } + + private val gradeRegex by lazy { """([0-6])([+-])?""".toRegex() } + private val format = DecimalFormat("#.##") + + val orderBy + get() = app.config.grades.orderBy + val yearAverageMode + get() = app.config.forProfile().grades.yearAverageMode + val colorMode + get() = app.config.forProfile().grades.colorMode + val plusValue + get() = app.config.forProfile().grades.plusValue + val minusValue + get() = app.config.forProfile().grades.minusValue + val dontCountGrades + get() = app.config.forProfile().grades.dontCountGrades + + + fun getOrderByString() = when (orderBy) { + ORDER_BY_SUBJECT_ASC -> "subjectLongName ASC, gradeSemester DESC, addedDate DESC" + ORDER_BY_DATE_ASC -> "subjectId ASC, gradeSemester DESC, addedDate ASC" + ORDER_BY_SUBJECT_DESC -> "subjectLongName DESC, gradeSemester DESC, addedDate DESC" + else -> "subjectId ASC, gradeSemester DESC, addedDate DESC" + } + + fun getWeightString(context: Context, grade: Grade, showClassAverage: Boolean = false) = when (grade.type) { + TYPE_NORMAL -> if (grade.weight == 0f) + context.getString(R.string.grades_weight_not_counted) + else + if (showClassAverage && (grade.classAverage ?: 0f) != 0f) + context.getString(R.string.grades_weight_format, format.format(grade.weight)+", "+format.format(grade.classAverage)) + else + context.getString(R.string.grades_weight_format, format.format(grade.weight)) + TYPE_POINT_AVG -> context.getString(R.string.grades_max_points_format, format.format(grade.valueMax)) + else -> null + } + + private fun gradeNameToColorStr(grade: String): String? { + when (grade.toLowerCase()) { + "+", "++", "+++" -> + return "4caf50" + "-", "-,", "-,-,", "np", "np.", "npnp", "np,", "np,np,", "bs", "nk" -> + return "ff7043" + "1-", "1", "f" -> + return "ff0000" + "1+", "ef" -> + return "ff3d00" + "2-", "2", "e" -> + return "ff9100" + "2+", "de" -> + return "ffab00" + "3-", "3", "d" -> + return "ffff00" + "3+", "cd" -> + return "c6ff00" + "4-", "4", "c" -> + return "76ff03" + "4+", "bc" -> + return "64dd17" + "5-", "5", "b" -> + return "00c853" + "5+", "ab" -> + return "00bfa5" + "6-", "6", "a" -> + return "2196f3" + "6+", "a+" -> + return "0091ea" + } + return "bdbdbd" + } + + fun getRoundedGrade(value: Float): Int { + return floor(value.toDouble()).toInt() + if (value % 1.0f >= 0.75) 1 else 0 + } + + fun getGradeValue(grade: Grade): Float { + gradeRegex.find(grade.name)?.let { + var value = it[1].toFloatOrNull() ?: return grade.value + if (it[2] == "+") + value += plusValue ?: return grade.value + if (it[2] == "-") + value -= minusValue ?: return grade.value + return value + } + return grade.value + } + + fun getGradeWeight(dontCountGrades: List, grade: Grade): Float { + if (grade.name.toLowerCase() in dontCountGrades) + return 0f + return grade.weight + } + + fun getColor(grade: Grade): Int { + return Colors.gradeToColor(grade) + } + + fun calculateAverages(averages: GradesAverages, semesters: List? = null) { + if (averages.pointAvgMax != 0f) + averages.pointAvgPercent = averages.pointAvgSum / averages.pointAvgMax * 100f + + if (averages.normalCount <= 0f) { + // no grades to count + return + } + + if (semesters == null || yearAverageMode == YEAR_ALL_GRADES) { + // counting average for one semester + // or yearly, but just averaging every grade + averages.normalAvg = when { + averages.normalWeightedCount > 0f -> { + averages.normalWeightedSum / averages.normalWeightedCount + } + averages.normalSum > 0f && averages.normalCount > 0f -> { + averages.normalSum / averages.normalCount + } + else -> null + } + return + } + + val yearAverageMode = yearAverageMode + averages.normalAvg = when (yearAverageMode) { + YEAR_1_AVG_2_AVG -> { + semesters.mapNotNull { it.averages.normalAvg }.average().toFloat() + } + else -> { + if (semesters.size >= 2) { + val sem1 = semesters.firstOrNull { it.number == 1 } + val sem2 = semesters.firstOrNull { it.number == 2 } + when (yearAverageMode) { + YEAR_1_SEM_2_AVG -> { + ifNotNull(sem1?.finalGrade?.value, sem2?.averages?.normalAvg) { s1, s2 -> + (s1 + s2) / 2f + } + } + YEAR_1_AVG_2_SEM -> { + ifNotNull(sem1?.averages?.normalAvg, sem2?.finalGrade?.value) { s1, s2 -> + (s1 + s2) / 2f + } + } + YEAR_1_SEM_2_SEM -> { + ifNotNull(sem1?.finalGrade?.value, sem2?.finalGrade?.value) { s1, s2 -> + (s1 + s2) / 2f + } + } + else -> null + } + } + else null + } + } + } + + fun getAverageString(context: Context, averages: GradesAverages, nameSemester: Boolean = false, showSemester: Int? = null, noAverageRes: Int? = null): CharSequence? { + val averageString = when { + averages.normalAvg != null -> String.format("%.2f", averages.normalAvg) + averages.pointSum != 0f -> context.getString(R.string.grades_average_value_sum_format, format.format(averages.pointSum)) + averages.pointAvgPercent != null -> context.getString( + R.string.grades_average_value_point_format, + format.format(averages.pointAvgSum), + format.format(averages.pointAvgMax), + format.format(averages.pointAvgPercent) + ) + else -> return noAverageRes?.let { context.getString(it) } + }.asColoredSpannable(android.R.attr.textColorSecondary.resolveAttr(context)) + + return if (nameSemester) { + context.getString( + if (showSemester == null) + R.string.grades_average_year_format + else + R.string.grades_average_semester_format, + showSemester ?: 0, + averageString + ) + } + else { + when { + averages.normalAvg != null -> context.getString(R.string.grades_average_normal_format, averageString) + averages.pointSum != 0f -> context.getString(R.string.grades_average_sum_format, averageString) + averages.pointAvgPercent != null -> context.getString(R.string.grades_average_point_format, averageString) + else -> null + } + } + } + + fun getYearSummaryString(context: Context, gradeCount: Int, averages: GradesAverages): CharSequence { + val gradeCountString = context.plural(R.plurals.grades_format, gradeCount) + return context.getString( + R.string.grades_year_summary_format, + gradeCountString, + getAverageString(context, averages, noAverageRes = R.string.grades_average_no) + ) + } +} 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 3ca6aec8..5f889bfb 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 @@ -313,7 +313,7 @@ public class Date implements Comparable { @Nullable public String getRelativeString(Context context, int maxDiff) { int diffDays = Date.diffDays(this, Date.getToday()); - if (maxDiff != 0 && diffDays > maxDiff) { + if (maxDiff != 0 && Math.abs(diffDays) > maxDiff) { return null; } return dayDiffString(context, diffDays); diff --git a/app/src/main/res/drawable/bg_rounded_4dp_outline.xml b/app/src/main/res/drawable/bg_rounded_4dp_outline.xml index d22dc338..b3a51d1a 100644 --- a/app/src/main/res/drawable/bg_rounded_4dp_outline.xml +++ b/app/src/main/res/drawable/bg_rounded_4dp_outline.xml @@ -3,7 +3,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> + - - \ No newline at end of file + diff --git a/app/src/main/res/drawable/bg_rounded_8dp.xml b/app/src/main/res/drawable/bg_rounded_8dp.xml index c30f3c42..30184e04 100644 --- a/app/src/main/res/drawable/bg_rounded_8dp.xml +++ b/app/src/main/res/drawable/bg_rounded_8dp.xml @@ -5,4 +5,4 @@ - \ No newline at end of file + diff --git a/app/src/main/res/drawable/ic_no_grades.xml b/app/src/main/res/drawable/ic_no_grades.xml new file mode 100644 index 00000000..61bab8e3 --- /dev/null +++ b/app/src/main/res/drawable/ic_no_grades.xml @@ -0,0 +1,16 @@ + + + + + + diff --git a/app/src/main/res/layout/dialog_config_grades.xml b/app/src/main/res/layout/dialog_config_grades.xml index ce22c0ac..205e59f4 100644 --- a/app/src/main/res/layout/dialog_config_grades.xml +++ b/app/src/main/res/layout/dialog_config_grades.xml @@ -3,7 +3,8 @@ ~ Copyright (c) Kacper Ziubryniewicz 2020-1-20 --> - + @@ -14,10 +15,62 @@ android:orientation="vertical" android:padding="24dp"> + + + + + + + + + + + + + + @@ -29,20 +82,22 @@ android:id="@+id/sortGradesByDateRadio" android:layout_width="match_parent" android:layout_height="wrap_content" - android:text="@string/dialog_grades_config_sort_by_date"/> + android:minHeight="0dp" + android:text="@string/dialog_grades_config_sort_by_date" /> @@ -54,20 +109,22 @@ android:id="@+id/gradeColorFromERegister" android:layout_width="match_parent" android:layout_height="wrap_content" + android:minHeight="0dp" android:text="@string/dialog_grades_config_color_from_eregister"/> @@ -79,30 +136,35 @@ android:id="@+id/gradeAverageMode4" android:layout_width="match_parent" android:layout_height="wrap_content" + android:minHeight="0dp" android:text="@string/settings_register_avg_mode_4"/> @@ -118,6 +180,7 @@ android:id="@+id/dontCountZeroToAverage" android:layout_width="match_parent" android:layout_height="wrap_content" + android:minHeight="0dp" android:text="@string/settings_register_dont_count_zero_text"/> diff --git a/app/src/main/res/layout/dialog_grade_details.xml b/app/src/main/res/layout/dialog_grade_details.xml index 3a3d6173..4f8f0dda 100644 --- a/app/src/main/res/layout/dialog_grade_details.xml +++ b/app/src/main/res/layout/dialog_grade_details.xml @@ -28,238 +28,252 @@ + - + android:layout_height="wrap_content"> - - + android:orientation="vertical" + android:paddingLeft="24dp" + android:paddingTop="24dp" + android:paddingRight="24dp"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:orientation="horizontal"> - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/grades_fragment.xml b/app/src/main/res/layout/grades_fragment.xml new file mode 100644 index 00000000..a9702e8c --- /dev/null +++ b/app/src/main/res/layout/grades_fragment.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/grades_item_empty.xml b/app/src/main/res/layout/grades_item_empty.xml new file mode 100644 index 00000000..3ae82483 --- /dev/null +++ b/app/src/main/res/layout/grades_item_empty.xml @@ -0,0 +1,21 @@ + + + + + + + + + diff --git a/app/src/main/res/layout/grades_item_grade.xml b/app/src/main/res/layout/grades_item_grade.xml new file mode 100644 index 00000000..417d295f --- /dev/null +++ b/app/src/main/res/layout/grades_item_grade.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/grades_item_semester.xml b/app/src/main/res/layout/grades_item_semester.xml new file mode 100644 index 00000000..25d8f03a --- /dev/null +++ b/app/src/main/res/layout/grades_item_semester.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/grades_item_stats.xml b/app/src/main/res/layout/grades_item_stats.xml new file mode 100644 index 00000000..4bffa927 --- /dev/null +++ b/app/src/main/res/layout/grades_item_stats.xml @@ -0,0 +1,334 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +