forked from github/wulkanowy-mirror
Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
4d67de8e5f | |||
f983a23b1a | |||
6a1851da13 | |||
8dbbea2138 | |||
f6226e6b53 | |||
43d13db07c | |||
82210c37e3 | |||
b5cc32d59f | |||
d943d03266 | |||
6eca8c42f5 | |||
af989ba9f6 | |||
4a65a5b192 | |||
bbbafdfe70 | |||
a82e11d694 | |||
4dc5fc65ac | |||
7463cf6253 | |||
d799ec7ac9 | |||
254719f22f |
@ -27,8 +27,8 @@ android {
|
||||
testApplicationId "io.github.tests.wulkanowy"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 34
|
||||
versionCode 153
|
||||
versionName "2.5.4"
|
||||
versionCode 157
|
||||
versionName "2.5.8"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
resValue "string", "app_name", "Wulkanowy"
|
||||
@ -165,7 +165,7 @@ play {
|
||||
track = 'production'
|
||||
releaseStatus = ReleaseStatus.IN_PROGRESS
|
||||
userFraction = 0.99d
|
||||
updatePriority = 1
|
||||
updatePriority = 4
|
||||
enabled.set(false)
|
||||
}
|
||||
|
||||
@ -195,7 +195,7 @@ ext {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'io.github.wulkanowy:sdk:2.5.4'
|
||||
implementation 'io.github.wulkanowy:sdk:2.5.8'
|
||||
|
||||
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
|
||||
|
||||
|
2559
app/schemas/io.github.wulkanowy.data.db.AppDatabase/64.json
Normal file
2559
app/schemas/io.github.wulkanowy.data.db.AppDatabase/64.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -23,6 +23,7 @@ class WulkanowySdkFactory @Inject constructor(
|
||||
) {
|
||||
|
||||
private val eduOneMutex = Mutex()
|
||||
private val migrationFailedStudentIds = mutableSetOf<Long>()
|
||||
|
||||
private val sdk = Sdk().apply {
|
||||
androidVersion = android.os.Build.VERSION.RELEASE
|
||||
@ -78,14 +79,24 @@ class WulkanowySdkFactory @Inject constructor(
|
||||
private suspend fun checkEduOneAndMigrateIfNecessary(student: Student): Boolean {
|
||||
if (student.isEduOne != null) return student.isEduOne
|
||||
|
||||
if (student.id in migrationFailedStudentIds) {
|
||||
Timber.i("Migration eduOne: skipping because of previous failure")
|
||||
return false
|
||||
}
|
||||
|
||||
eduOneMutex.withLock {
|
||||
if (student.id in migrationFailedStudentIds) {
|
||||
Timber.i("Migration eduOne: skipping because of previous failure")
|
||||
return false
|
||||
}
|
||||
|
||||
val studentFromDatabase = studentDb.loadById(student.id)
|
||||
if (studentFromDatabase?.isEduOne != null) {
|
||||
Timber.d("Migration eduOne: already done")
|
||||
Timber.i("Migration eduOne: already done")
|
||||
return studentFromDatabase.isEduOne
|
||||
}
|
||||
|
||||
Timber.d("Migration eduOne: flag missing. Running migration...")
|
||||
Timber.i("Migration eduOne: flag missing. Running migration...")
|
||||
val initializedSdk = buildSdk(
|
||||
student = student,
|
||||
semester = null,
|
||||
@ -96,11 +107,12 @@ class WulkanowySdkFactory @Inject constructor(
|
||||
.getOrNull()
|
||||
|
||||
if (newCurrentStudent == null) {
|
||||
Timber.d("Migration eduOne: failed, so skipping")
|
||||
Timber.i("Migration eduOne: failed, so skipping")
|
||||
migrationFailedStudentIds.add(student.id)
|
||||
return false
|
||||
}
|
||||
|
||||
Timber.d("Migration eduOne: success. New isEduOne flag: ${newCurrentStudent.isEduOne}")
|
||||
Timber.i("Migration eduOne: success. New isEduOne flag: ${newCurrentStudent.isEduOne}")
|
||||
|
||||
val studentIsEduOne = StudentIsEduOne(
|
||||
id = student.id,
|
||||
|
@ -177,6 +177,7 @@ import javax.inject.Singleton
|
||||
AutoMigration(from = 60, to = 61),
|
||||
AutoMigration(from = 61, to = 62),
|
||||
AutoMigration(from = 62, to = 63, spec = Migration63::class),
|
||||
AutoMigration(from = 63, to = 64),
|
||||
],
|
||||
version = AppDatabase.VERSION_SCHEMA,
|
||||
exportSchema = true
|
||||
@ -185,7 +186,7 @@ import javax.inject.Singleton
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
|
||||
companion object {
|
||||
const val VERSION_SCHEMA = 63
|
||||
const val VERSION_SCHEMA = 64
|
||||
|
||||
fun getMigrations(sharedPrefProvider: SharedPrefProvider, appInfo: AppInfo) = arrayOf(
|
||||
Migration2(),
|
||||
|
@ -8,6 +8,6 @@ import kotlinx.coroutines.flow.Flow
|
||||
@Dao
|
||||
interface MobileDeviceDao : BaseDao<MobileDevice> {
|
||||
|
||||
@Query("SELECT * FROM MobileDevices WHERE user_login_id = :userLoginId ORDER BY date DESC")
|
||||
fun loadAll(userLoginId: Int): Flow<List<MobileDevice>>
|
||||
@Query("SELECT * FROM MobileDevices WHERE user_login_id = :studentId ORDER BY date DESC")
|
||||
fun loadAll(studentId: Int): Flow<List<MobileDevice>>
|
||||
}
|
||||
|
@ -10,6 +10,6 @@ import javax.inject.Singleton
|
||||
@Singleton
|
||||
interface SchoolAnnouncementDao : BaseDao<SchoolAnnouncement> {
|
||||
|
||||
@Query("SELECT * FROM SchoolAnnouncements WHERE user_login_id = :userLoginId ORDER BY date DESC")
|
||||
fun loadAll(userLoginId: Int): Flow<List<SchoolAnnouncement>>
|
||||
@Query("SELECT * FROM SchoolAnnouncements WHERE user_login_id = :studentId ORDER BY date DESC")
|
||||
fun loadAll(studentId: Int): Flow<List<SchoolAnnouncement>>
|
||||
}
|
||||
|
@ -14,6 +14,6 @@ interface SemesterDao : BaseDao<Semester> {
|
||||
@Insert(onConflict = OnConflictStrategy.IGNORE)
|
||||
suspend fun insertSemesters(items: List<Semester>): List<Long>
|
||||
|
||||
@Query("SELECT * FROM Semesters WHERE student_id = :studentId AND class_id = :classId")
|
||||
@Query("SELECT * FROM Semesters WHERE (student_id = :studentId AND class_id = :classId) OR (student_id = :studentId AND class_id = 0)")
|
||||
suspend fun loadAll(studentId: Int, classId: Int): List<Semester>
|
||||
}
|
||||
|
@ -47,11 +47,11 @@ abstract class StudentDao {
|
||||
abstract suspend fun loadAll(): List<Student>
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT * FROM Students JOIN Semesters ON Students.student_id = Semesters.student_id AND Students.class_id = Semesters.class_id")
|
||||
@Query("SELECT * FROM Students JOIN Semesters ON (Students.student_id = Semesters.student_id AND Students.class_id = Semesters.class_id) OR (Students.student_id = Semesters.student_id AND Semesters.class_id = 0)")
|
||||
abstract suspend fun loadStudentsWithSemesters(): Map<Student, List<Semester>>
|
||||
|
||||
@Transaction
|
||||
@Query("SELECT * FROM Students JOIN Semesters ON Students.student_id = Semesters.student_id AND Students.class_id = Semesters.class_id WHERE Students.id = :id")
|
||||
@Query("SELECT * FROM Students JOIN Semesters ON (Students.student_id = Semesters.student_id AND Students.class_id = Semesters.class_id) OR (Students.student_id = Semesters.student_id AND Semesters.class_id = 0) WHERE Students.id = :id")
|
||||
abstract suspend fun loadStudentWithSemestersById(id: Long): Map<Student, List<Semester>>
|
||||
|
||||
@Query("UPDATE Students SET is_current = 1 WHERE id = :id")
|
||||
|
@ -33,7 +33,13 @@ data class GradeSummary(
|
||||
@ColumnInfo(name = "points_sum")
|
||||
val pointsSum: String,
|
||||
|
||||
val average: Double
|
||||
@ColumnInfo(name = "points_sum_all_year")
|
||||
val pointsSumAllYear: String?,
|
||||
|
||||
val average: Double,
|
||||
|
||||
@ColumnInfo(name = "average_all_year")
|
||||
val averageAllYear: Double? = null,
|
||||
) {
|
||||
@PrimaryKey(autoGenerate = true)
|
||||
var id: Long = 0
|
||||
|
@ -9,8 +9,8 @@ import java.time.Instant
|
||||
@Entity(tableName = "MobileDevices")
|
||||
data class MobileDevice(
|
||||
|
||||
@ColumnInfo(name = "user_login_id")
|
||||
val userLoginId: Int,
|
||||
@ColumnInfo(name = "user_login_id") // todo: change column name
|
||||
val studentId: Int,
|
||||
|
||||
@ColumnInfo(name = "device_id")
|
||||
val deviceId: Int,
|
||||
|
@ -9,8 +9,8 @@ import java.time.LocalDate
|
||||
@Entity(tableName = "SchoolAnnouncements")
|
||||
data class SchoolAnnouncement(
|
||||
|
||||
@ColumnInfo(name = "user_login_id")
|
||||
val userLoginId: Int,
|
||||
@ColumnInfo(name = "user_login_id") // todo: change column name
|
||||
val studentId: Int,
|
||||
|
||||
val date: LocalDate,
|
||||
|
||||
|
@ -49,6 +49,7 @@ data class Student(
|
||||
@ColumnInfo(name = "student_id")
|
||||
val studentId: Int,
|
||||
|
||||
@Deprecated("not available in VULCAN anymore")
|
||||
@ColumnInfo(name = "user_login_id")
|
||||
val userLoginId: Int,
|
||||
|
||||
|
@ -8,7 +8,7 @@ import io.github.wulkanowy.sdk.pojo.LastAnnouncement as SdkLastAnnouncement
|
||||
@JvmName("mapDirectorInformationToEntities")
|
||||
fun List<SdkDirectorInformation>.mapToEntities(student: Student) = map {
|
||||
SchoolAnnouncement(
|
||||
userLoginId = student.userLoginId,
|
||||
studentId = student.studentId,
|
||||
date = it.date,
|
||||
subject = it.subject,
|
||||
content = it.content,
|
||||
@ -19,7 +19,7 @@ fun List<SdkDirectorInformation>.mapToEntities(student: Student) = map {
|
||||
@JvmName("mapLastAnnouncementsToEntities")
|
||||
fun List<SdkLastAnnouncement>.mapToEntities(student: Student) = map {
|
||||
SchoolAnnouncement(
|
||||
userLoginId = student.userLoginId,
|
||||
studentId = student.studentId,
|
||||
date = it.date,
|
||||
subject = it.subject,
|
||||
content = it.content,
|
||||
|
@ -37,9 +37,11 @@ fun List<SdkGradeSummary>.mapToEntities(semester: Semester) = map {
|
||||
predictedGrade = it.predicted,
|
||||
finalGrade = it.final,
|
||||
pointsSum = it.pointsSum,
|
||||
pointsSumAllYear = it.pointsSumAllYear,
|
||||
proposedPoints = it.proposedPoints,
|
||||
finalPoints = it.finalPoints,
|
||||
average = it.average
|
||||
average = it.average,
|
||||
averageAllYear = it.averageAllYear,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ import io.github.wulkanowy.sdk.pojo.Token as SdkToken
|
||||
|
||||
fun List<SdkDevice>.mapToEntities(student: Student) = map {
|
||||
MobileDevice(
|
||||
userLoginId = student.userLoginId,
|
||||
studentId = student.studentId,
|
||||
date = it.createDate.toInstant(),
|
||||
deviceId = it.id,
|
||||
name = it.name
|
||||
|
@ -38,7 +38,7 @@ class MobileDeviceRepository @Inject constructor(
|
||||
val isExpired = refreshHelper.shouldBeRefreshed(getRefreshKey(cacheKey, student))
|
||||
it.isEmpty() || forceRefresh || isExpired
|
||||
},
|
||||
query = { mobileDb.loadAll(student.userLoginId) },
|
||||
query = { mobileDb.loadAll(student.studentId) },
|
||||
fetch = {
|
||||
wulkanowySdkFactory.create(student, semester)
|
||||
.getRegisteredDevices()
|
||||
|
@ -37,7 +37,7 @@ class SchoolAnnouncementRepository @Inject constructor(
|
||||
it.isEmpty() || forceRefresh || isExpired
|
||||
},
|
||||
query = {
|
||||
schoolAnnouncementDb.loadAll(student.userLoginId)
|
||||
schoolAnnouncementDb.loadAll(student.studentId)
|
||||
},
|
||||
fetch = {
|
||||
val sdk = wulkanowySdkFactory.create(student)
|
||||
@ -57,7 +57,7 @@ class SchoolAnnouncementRepository @Inject constructor(
|
||||
)
|
||||
|
||||
fun getSchoolAnnouncementFromDatabase(student: Student): Flow<List<SchoolAnnouncement>> {
|
||||
return schoolAnnouncementDb.loadAll(student.userLoginId)
|
||||
return schoolAnnouncementDb.loadAll(student.studentId)
|
||||
}
|
||||
|
||||
suspend fun updateSchoolAnnouncement(schoolAnnouncement: List<SchoolAnnouncement>) =
|
||||
|
@ -64,7 +64,10 @@ class SemesterRepository @Inject constructor(
|
||||
.getSemesters()
|
||||
.mapToEntities(student.studentId)
|
||||
|
||||
if (new.isEmpty()) return Timber.i("Empty semester list!")
|
||||
if (new.isEmpty()) {
|
||||
Timber.i("Empty semester list from SDK!")
|
||||
return
|
||||
}
|
||||
|
||||
val old = semesterDb.loadAll(student.studentId, student.classId)
|
||||
semesterDb.removeOldAndSaveNew(
|
||||
|
@ -26,5 +26,7 @@ private fun generateSummary(subject: String, predicted: String, final: String) =
|
||||
proposedPoints = "",
|
||||
finalPoints = "",
|
||||
pointsSum = "",
|
||||
average = .0
|
||||
average = .0,
|
||||
pointsSumAllYear = null,
|
||||
averageAllYear = null,
|
||||
)
|
||||
|
@ -19,6 +19,6 @@ val debugSchoolAnnouncementItems = listOf(
|
||||
private fun generateAnnouncement(subject: String, content: String) = SchoolAnnouncement(
|
||||
subject = subject,
|
||||
content = content,
|
||||
userLoginId = 0,
|
||||
studentId = 0,
|
||||
date = LocalDate.now()
|
||||
)
|
||||
|
@ -266,7 +266,9 @@ class GradeAverageProvider @Inject constructor(
|
||||
proposedPoints = "",
|
||||
finalPoints = "",
|
||||
pointsSum = "",
|
||||
average = .0
|
||||
pointsSumAllYear = null,
|
||||
average = .0,
|
||||
averageAllYear = null,
|
||||
)
|
||||
}
|
||||
|
||||
@ -294,13 +296,15 @@ class GradeAverageProvider @Inject constructor(
|
||||
proposedPoints = "",
|
||||
finalPoints = "",
|
||||
pointsSum = "",
|
||||
pointsSumAllYear = null,
|
||||
average = when {
|
||||
calcAverage -> details
|
||||
.updateModifiers(student, params)
|
||||
.calcAverage(isOptionalArithmeticAverage = params.isOptionalArithmeticAverage)
|
||||
|
||||
else -> .0
|
||||
}
|
||||
},
|
||||
averageAllYear = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -96,9 +96,11 @@ class GradeDetailsAdapter @Inject constructor() : BaseExpandableAdapter<Recycler
|
||||
ViewType.HEADER.id -> HeaderViewHolder(
|
||||
HeaderGradeDetailsBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
|
||||
ViewType.ITEM.id -> ItemViewHolder(
|
||||
ItemGradeDetailsBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
}
|
||||
@ -110,6 +112,7 @@ class GradeDetailsAdapter @Inject constructor() : BaseExpandableAdapter<Recycler
|
||||
header = items[position].value as GradeDetailsHeader,
|
||||
position = position
|
||||
)
|
||||
|
||||
is ItemViewHolder -> bindItemViewHolder(
|
||||
holder = holder,
|
||||
grade = items[position].value as Grade
|
||||
@ -133,6 +136,10 @@ class GradeDetailsAdapter @Inject constructor() : BaseExpandableAdapter<Recycler
|
||||
maxLines = if (expandedPositions[headerPosition]) 2 else 1
|
||||
}
|
||||
gradeHeaderAverage.text = formatAverage(header.average, root.context.resources)
|
||||
with(gradeHeaderAverageAllYear) {
|
||||
isVisible = header.averageAllYear != null && header.averageAllYear != .0
|
||||
text = formatAverageAllYear(header.averageAllYear, root.context.resources)
|
||||
}
|
||||
gradeHeaderPointsSum.text =
|
||||
context.getString(R.string.grade_points_sum, header.pointsSum)
|
||||
gradeHeaderPointsSum.isVisible = !header.pointsSum.isNullOrEmpty()
|
||||
@ -233,6 +240,13 @@ class GradeDetailsAdapter @Inject constructor() : BaseExpandableAdapter<Recycler
|
||||
resources.getString(R.string.grade_average, average)
|
||||
}
|
||||
|
||||
private fun formatAverageAllYear(average: Double?, resources: Resources) =
|
||||
if (average == null || average == .0) {
|
||||
resources.getString(R.string.grade_no_average)
|
||||
} else {
|
||||
resources.getString(R.string.grade_average_year, average)
|
||||
}
|
||||
|
||||
private class HeaderViewHolder(val binding: HeaderGradeDetailsBinding) :
|
||||
RecyclerView.ViewHolder(binding.root)
|
||||
|
||||
|
@ -13,6 +13,7 @@ data class GradeDetailsItem(
|
||||
data class GradeDetailsHeader(
|
||||
val subject: String,
|
||||
val average: Double?,
|
||||
val averageAllYear: Double?,
|
||||
val pointsSum: String?,
|
||||
val grades: List<GradeDetailsItem>
|
||||
) {
|
||||
|
@ -226,8 +226,9 @@ class GradeDetailsPresenter @Inject constructor(
|
||||
GradeDetailsHeader(
|
||||
subject = gradeSubject.subject,
|
||||
average = gradeSubject.average,
|
||||
averageAllYear = gradeSubject.summary.averageAllYear,
|
||||
pointsSum = gradeSubject.points,
|
||||
grades = subItems
|
||||
grades = subItems,
|
||||
).apply {
|
||||
newGrades = gradeSubject.grades.filter { grade -> !grade.isRead }.size
|
||||
}, ViewType.HEADER
|
||||
|
@ -3,6 +3,7 @@ package io.github.wulkanowy.ui.modules.grade.summary
|
||||
import android.annotation.SuppressLint
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.github.wulkanowy.R
|
||||
@ -65,37 +66,55 @@ class GradeSummaryAdapter @Inject constructor(
|
||||
val gradeSummaries = items
|
||||
.filter { it.gradeDescriptive == null }
|
||||
.map { it.gradeSummary }
|
||||
val isSecondSemester = items.any { item ->
|
||||
item.gradeSummary.let { it.averageAllYear != null && it.averageAllYear != .0 }
|
||||
}
|
||||
|
||||
val context = binding.root.context
|
||||
val finalItemsCount = gradeSummaries.count { isGradeValid(it.finalGrade) }
|
||||
val calculatedItemsCount = gradeSummaries.count { value -> value.average != 0.0 }
|
||||
val calculatedSemesterItemsCount = gradeSummaries.count { value -> value.average != 0.0 }
|
||||
val calculatedAnnualItemsCount =
|
||||
gradeSummaries.count { value -> value.averageAllYear != 0.0 }
|
||||
val allItemsCount = gradeSummaries.count { !it.subject.equals("zachowanie", true) }
|
||||
val finalAverage = gradeSummaries.calcFinalAverage(
|
||||
preferencesRepository.gradePlusModifier,
|
||||
preferencesRepository.gradeMinusModifier
|
||||
plusModifier = preferencesRepository.gradePlusModifier,
|
||||
minusModifier = preferencesRepository.gradeMinusModifier,
|
||||
)
|
||||
val calculatedAverage = gradeSummaries.filter { value -> value.average != 0.0 }
|
||||
val calculatedSemesterAverage = gradeSummaries.filter { value -> value.average != 0.0 }
|
||||
.map { values -> values.average }
|
||||
.reversed() // fix average precision
|
||||
.average()
|
||||
.let { if (it.isNaN()) 0.0 else it }
|
||||
val calculatedAnnualAverage = gradeSummaries.filter { value -> value.averageAllYear != 0.0 }
|
||||
.mapNotNull { values -> values.averageAllYear }
|
||||
.reversed() // fix average precision
|
||||
.average()
|
||||
.let { if (it.isNaN()) 0.0 else it }
|
||||
|
||||
with(binding) {
|
||||
gradeSummaryScrollableHeaderCalculated.text = formatAverage(calculatedSemesterAverage)
|
||||
gradeSummaryScrollableHeaderCalculatedAnnual.text =
|
||||
formatAverage(calculatedAnnualAverage)
|
||||
gradeSummaryScrollableHeaderFinal.text = formatAverage(finalAverage)
|
||||
gradeSummaryScrollableHeaderCalculated.text = formatAverage(calculatedAverage)
|
||||
gradeSummaryScrollableHeaderFinalSubjectCount.text =
|
||||
context.getString(
|
||||
R.string.grade_summary_from_subjects,
|
||||
finalItemsCount,
|
||||
allItemsCount
|
||||
)
|
||||
gradeSummaryScrollableHeaderCalculatedSubjectCount.text = context.getString(
|
||||
gradeSummaryScrollableHeaderFinalSubjectCount.text = context.getString(
|
||||
R.string.grade_summary_from_subjects,
|
||||
calculatedItemsCount,
|
||||
finalItemsCount,
|
||||
allItemsCount
|
||||
)
|
||||
gradeSummaryScrollableHeaderCalculatedSubjectCount.text = context.getString(
|
||||
R.string.grade_summary_from_subjects,
|
||||
calculatedSemesterItemsCount,
|
||||
allItemsCount
|
||||
)
|
||||
gradeSummaryScrollableHeaderCalculatedSubjectCountAnnual.text = context.getString(
|
||||
R.string.grade_summary_from_subjects,
|
||||
calculatedAnnualItemsCount,
|
||||
allItemsCount
|
||||
)
|
||||
gradeSummaryScrollableHeaderCalculatedAnnualContainer.isVisible = isSecondSemester
|
||||
|
||||
gradeSummaryCalculatedAverageHelp.setOnClickListener { onCalculatedHelpClickListener() }
|
||||
gradeSummaryCalculatedAverageHelpAnnual.setOnClickListener { onCalculatedHelpClickListener() }
|
||||
gradeSummaryFinalAverageHelp.setOnClickListener { onFinalHelpClickListener() }
|
||||
}
|
||||
}
|
||||
@ -107,7 +126,12 @@ class GradeSummaryAdapter @Inject constructor(
|
||||
with(binding) {
|
||||
gradeSummaryItemTitle.text = gradeSummary.subject
|
||||
gradeSummaryItemPoints.text = gradeSummary.pointsSum
|
||||
|
||||
gradeSummaryItemAverage.text = formatAverage(gradeSummary.average, "")
|
||||
gradeSummaryItemAverageAllYear.text = gradeSummary.averageAllYear?.let {
|
||||
formatAverage(it, "")
|
||||
}
|
||||
|
||||
gradeSummaryItemPredicted.text =
|
||||
"${gradeSummary.predictedGrade} ${gradeSummary.proposedPoints}".trim()
|
||||
gradeSummaryItemFinal.text =
|
||||
@ -116,6 +140,12 @@ class GradeSummaryAdapter @Inject constructor(
|
||||
root.context.getString(R.string.all_no_data)
|
||||
}
|
||||
|
||||
gradeSummaryItemAverageContainer.isVisible = gradeSummary.average != .0
|
||||
gradeSummaryItemAverageDivider.isVisible = gradeSummaryItemAverageContainer.isVisible
|
||||
gradeSummaryItemAverageAllYearContainer.isGone =
|
||||
gradeSummary.averageAllYear == null || gradeSummary.averageAllYear == .0
|
||||
gradeSummaryItemAverageAllYearDivider.isGone =
|
||||
gradeSummaryItemAverageAllYearContainer.isGone
|
||||
gradeSummaryItemFinalDivider.isVisible = gradeDescriptive == null
|
||||
gradeSummaryItemPredictedDivider.isVisible = gradeDescriptive == null
|
||||
gradeSummaryItemPointsDivider.isVisible = gradeDescriptive == null
|
||||
@ -123,6 +153,7 @@ class GradeSummaryAdapter @Inject constructor(
|
||||
gradeSummaryItemFinalContainer.isVisible = gradeDescriptive == null
|
||||
gradeSummaryItemDescriptiveContainer.isVisible = gradeDescriptive != null
|
||||
gradeSummaryItemPointsContainer.isVisible = gradeSummary.pointsSum.isNotBlank()
|
||||
gradeSummaryItemPointsDivider.isVisible = gradeSummaryItemPointsContainer.isVisible
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,19 +19,23 @@ class LoginStudentSelectAdapter @Inject constructor() :
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||
val inflater = LayoutInflater.from(parent.context)
|
||||
return when (LoginStudentSelectItemType.values()[viewType]) {
|
||||
return when (LoginStudentSelectItemType.entries[viewType]) {
|
||||
LoginStudentSelectItemType.EMPTY_SYMBOLS_HEADER -> EmptySymbolsHeaderViewHolder(
|
||||
ItemLoginStudentSelectEmptySymbolHeaderBinding.inflate(inflater, parent, false),
|
||||
)
|
||||
|
||||
LoginStudentSelectItemType.SYMBOL_HEADER -> SymbolsHeaderViewHolder(
|
||||
ItemLoginStudentSelectHeaderSymbolBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
|
||||
LoginStudentSelectItemType.SCHOOL_HEADER -> SchoolHeaderViewHolder(
|
||||
ItemLoginStudentSelectHeaderSchoolBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
|
||||
LoginStudentSelectItemType.STUDENT -> StudentViewHolder(
|
||||
ItemLoginStudentSelectStudentBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
|
||||
LoginStudentSelectItemType.HELP -> HelpViewHolder(
|
||||
ItemLoginStudentSelectHelpBinding.inflate(inflater, parent, false)
|
||||
)
|
||||
@ -98,9 +102,11 @@ class LoginStudentSelectAdapter @Inject constructor() :
|
||||
with(binding) {
|
||||
loginStudentSelectHeaderSchoolName.text = buildString {
|
||||
append(item.unit.schoolName.trim())
|
||||
append(" (")
|
||||
append(item.unit.schoolShortName)
|
||||
append(")")
|
||||
if (item.unit.schoolShortName.isNotBlank()) {
|
||||
append(" (")
|
||||
append(item.unit.schoolShortName)
|
||||
append(")")
|
||||
}
|
||||
}
|
||||
loginStudentSelectHeaderSchoolDetails.isVisible = item.unit.students.isEmpty()
|
||||
loginStudentSelectHeaderSchoolError.text = item.unit.error?.message
|
||||
@ -170,9 +176,11 @@ class LoginStudentSelectAdapter @Inject constructor() :
|
||||
oldItem is LoginStudentSelectItem.SymbolHeader && newItem is LoginStudentSelectItem.SymbolHeader -> {
|
||||
oldItem.symbol == newItem.symbol
|
||||
}
|
||||
|
||||
oldItem is LoginStudentSelectItem.Student && newItem is LoginStudentSelectItem.Student -> {
|
||||
oldItem.student == newItem.student
|
||||
}
|
||||
|
||||
else -> oldItem == newItem
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ import io.github.wulkanowy.data.pojos.RegisterUser
|
||||
import io.github.wulkanowy.data.repositories.SchoolsRepository
|
||||
import io.github.wulkanowy.data.repositories.StudentRepository
|
||||
import io.github.wulkanowy.data.resourceFlow
|
||||
import io.github.wulkanowy.sdk.scrapper.exception.StudentGraduateException
|
||||
import io.github.wulkanowy.sdk.scrapper.login.InvalidSymbolException
|
||||
import io.github.wulkanowy.services.sync.SyncManager
|
||||
import io.github.wulkanowy.ui.base.BasePresenter
|
||||
@ -108,8 +109,8 @@ class LoginStudentSelectPresenter @Inject constructor(
|
||||
}
|
||||
|
||||
private fun createItems(): List<LoginStudentSelectItem> = buildList {
|
||||
val notEmptySymbols = registerUser.symbols.filter { it.schools.isNotEmpty() }
|
||||
val emptySymbols = registerUser.symbols.filter { it.schools.isEmpty() }
|
||||
val notEmptySymbols = registerUser.symbols.filter { it.shouldShowOnTop() }
|
||||
val emptySymbols = registerUser.symbols.filter { !it.shouldShowOnTop() }
|
||||
|
||||
if (emptySymbols.isNotEmpty() && notEmptySymbols.isNotEmpty() && emptySymbols.any { it.symbol == loginData.userEnteredSymbol }) {
|
||||
add(createEmptySymbolItem(emptySymbols.first { it.symbol == loginData.userEnteredSymbol }))
|
||||
@ -127,6 +128,10 @@ class LoginStudentSelectPresenter @Inject constructor(
|
||||
add(helpItem)
|
||||
}
|
||||
|
||||
private fun RegisterSymbol.shouldShowOnTop(): Boolean {
|
||||
return schools.isNotEmpty() || error is StudentGraduateException
|
||||
}
|
||||
|
||||
private fun createNotEmptySymbolItems(
|
||||
notEmptySymbols: List<RegisterSymbol>,
|
||||
students: List<StudentWithSemesters>,
|
||||
|
@ -23,7 +23,7 @@ fun getRefreshKey(name: String, semester: Semester): String {
|
||||
}
|
||||
|
||||
fun getRefreshKey(name: String, student: Student): String {
|
||||
return "${name}_${student.userLoginId}"
|
||||
return "${name}_${student.studentId}"
|
||||
}
|
||||
|
||||
fun getRefreshKey(name: String, mailbox: Mailbox?, folder: MessageFolder): String {
|
||||
|
@ -1,5 +1,5 @@
|
||||
Wersja 2.5.4
|
||||
Wersja 2.5.8
|
||||
|
||||
— naprawiliśmy kolejnych kilka błędów związanych z obsługą dziennika eduOne (tak, nie umiemy za jednym razem)
|
||||
— obeszliśmy próby blokowania Wulkanowego przez firmę VULCAN, o czymś pewnie zapomnieliśmy, ale nie miejcie nam tego za złe
|
||||
|
||||
Pełna lista zmian: https://github.com/wulkanowy/wulkanowy/releases
|
||||
|
@ -45,13 +45,30 @@
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/gradeHeaderPointsSum"
|
||||
app:layout_constraintEnd_toStartOf="@id/gradeHeaderAverageAllYear"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="@id/gradeHeaderSubject"
|
||||
app:layout_constraintTop_toBottomOf="@+id/gradeHeaderSubject"
|
||||
tools:text="Average: 6,00" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/gradeHeaderAverageAllYear"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:textSize="12sp"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintEnd_toStartOf="@id/gradeHeaderPointsSum"
|
||||
app:layout_constraintStart_toEndOf="@+id/gradeHeaderAverage"
|
||||
app:layout_constraintTop_toBottomOf="@+id/gradeHeaderSubject"
|
||||
tools:text="Roczna: 5,00"
|
||||
tools:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/gradeHeaderPointsSum"
|
||||
android:layout_width="wrap_content"
|
||||
@ -64,7 +81,7 @@
|
||||
android:textSize="12sp"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintEnd_toStartOf="@id/gradeHeaderNumber"
|
||||
app:layout_constraintStart_toEndOf="@+id/gradeHeaderAverage"
|
||||
app:layout_constraintStart_toEndOf="@+id/gradeHeaderAverageAllYear"
|
||||
app:layout_constraintTop_toBottomOf="@+id/gradeHeaderSubject"
|
||||
tools:text="Points: 123/200 (61,5%)" />
|
||||
|
||||
|
@ -20,20 +20,80 @@
|
||||
android:id="@+id/gradeSummaryItemTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="40dp"
|
||||
android:layout_weight="1"
|
||||
android:textSize="17sp"
|
||||
tools:text="@tools:sample/lorem" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/gradeSummaryItemAverageContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="35dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/grade_summary_average_semester"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/gradeSummaryItemAverage"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="25dp"
|
||||
android:gravity="end"
|
||||
android:textSize="12sp"
|
||||
tools:text="4.74" />
|
||||
tools:text="2,50" />
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/gradeSummaryItemAverageDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@drawable/ic_all_divider" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/gradeSummaryItemAverageAllYearContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="35dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/grade_summary_average_year"
|
||||
android:textSize="14sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/gradeSummaryItemAverageAllYear"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="25dp"
|
||||
android:gravity="end"
|
||||
android:textSize="12sp"
|
||||
tools:text="4,50" />
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/gradeSummaryItemAverageAllYearDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@drawable/ic_all_divider" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/gradeSummaryItemPointsContainer"
|
||||
android:layout_width="match_parent"
|
||||
@ -63,9 +123,9 @@
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/gradeSummaryItemPointsDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:id="@+id/gradeSummaryItemPointsDivider"
|
||||
android:background="@drawable/ic_all_divider" />
|
||||
|
||||
<LinearLayout
|
||||
@ -97,8 +157,8 @@
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:id="@+id/gradeSummaryItemPredictedDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@drawable/ic_all_divider" />
|
||||
|
||||
@ -131,9 +191,9 @@
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/gradeSummaryItemFinalDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:id="@+id/gradeSummaryItemFinalDivider"
|
||||
android:background="@drawable/ic_all_divider" />
|
||||
|
||||
<LinearLayout
|
||||
|
@ -10,10 +10,11 @@
|
||||
tools:context=".ui.modules.grade.summary.GradeSummaryAdapter">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="150dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginEnd="15dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
@ -21,9 +22,9 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:minLines="2"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/grade_summary_calculated_average"
|
||||
android:textSize="16sp" />
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
@ -61,9 +62,64 @@
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="150dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/gradeSummaryScrollableHeaderCalculatedAnnualContainer"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_marginEnd="15dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:minLines="2"
|
||||
android:text="@string/grade_summary_calculated_average_annual"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/gradeSummaryScrollableHeaderCalculatedAnnual"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:textSize="21sp"
|
||||
tools:text="6,00" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/gradeSummaryCalculatedAverageHelpAnnual"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@+string/grade_summary_calculated_average_help_dialog_title"
|
||||
app:srcCompat="@drawable/ic_help"
|
||||
app:tint="?colorOnBackground" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/gradeSummaryScrollableHeaderCalculatedSubjectCountAnnual"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:textSize="13sp"
|
||||
tools:text="from 8 subjects" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="20dp"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
@ -71,9 +127,9 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:minLines="2"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/grade_summary_final_average"
|
||||
android:textSize="16sp" />
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
@ -103,8 +159,8 @@
|
||||
<TextView
|
||||
android:id="@+id/gradeSummaryScrollableHeaderFinalSubjectCount"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
android:gravity="center_horizontal"
|
||||
android:textSize="13sp"
|
||||
tools:text="from 5 subjects" />
|
||||
|
@ -113,13 +113,17 @@
|
||||
<string name="grade_comment">Komentarz</string>
|
||||
<string name="grade_number_new_items">Ilość nowych ocen: %1$d</string>
|
||||
<string name="grade_average">Średnia: %1$.2f</string>
|
||||
<string name="grade_average_year">Roczna: %1$.2f</string>
|
||||
<string name="grade_points_sum">Punkty: %s</string>
|
||||
<string name="grade_no_average">Brak średniej</string>
|
||||
<string name="grade_summary_average_semester">Średnia semestralna</string>
|
||||
<string name="grade_summary_average_year">Średnia roczna</string>
|
||||
<string name="grade_summary_points">Suma punktów</string>
|
||||
<string name="grade_summary_final_grade">Ocena końcowa</string>
|
||||
<string name="grade_summary_predicted_grade">Przewidywana ocena</string>
|
||||
<string name="grade_summary_descriptive">Ocena opisowa</string>
|
||||
<string name="grade_summary_calculated_average">Obliczona średnia</string>
|
||||
<string name="grade_summary_calculated_average">Obliczona średnia semestralna</string>
|
||||
<string name="grade_summary_calculated_average_annual">Obliczona średnia roczna</string>
|
||||
<string name="grade_summary_calculated_average_help_dialog_title">Jak działa obliczona średnia?</string>
|
||||
<string name="grade_summary_calculated_average_help_dialog_message">Obliczona średnia jest średnią arytmetyczną obliczoną ze średnich przedmiotów. Pozwala ona na poznanie przybliżonej średniej końcowej. Jest obliczana w sposób wybrany przez użytkownika w ustawieniach aplikacji. Zaleca się wybranie odpowiedniej opcji. Dzieje się tak dlatego, że obliczanie średnich w szkołach różni się. Dodatkowo, jeśli twoja szkoła ma włączone średnie przedmiotów na stronie dziennika Vulcan, aplikacja pobiera je i ich nie oblicza. Można to zmienić, wymuszając obliczanie średniej w ustawieniach aplikacji.\n\n<b>Średnia ocen tylko z wybranego semestru</b>:\n1. Obliczanie średniej arytmetycznej każdego przedmiotu w danym semestrze\n2. Zsumowanie obliczonych średnich\n3. Obliczanie średniej arytmetycznej zsumowanych średnich\n\n<b>Średnia ze średnich z obu semestrów</b>:\n1.Obliczanie średniej arytmetycznej każdego przedmiotu w semestrze 1 i 2\n2. Obliczanie średniej arytmetycznej obliczonych średnich w semestrze 1 i 2 każdego przedmiotu.\n3. Zsumowanie obliczonych średnich\n4. Obliczanie średniej arytmetycznej zsumowanych średnich\n\n<b>Średnia wszystkich ocen z całego roku:</b>\n1. Obliczanie średniej arytmetycznej z każdego przedmiotu w ciągu całego roku. Końcowa ocena w 1 semestrze jest bez znaczenia.\n2. Zsumowanie obliczonych średnich\n3. Obliczanie średniej arytmetycznej z zsumowanych średnich</string>
|
||||
<string name="grade_summary_final_average_help_dialog_title">Jak działa końcowa średnia?</string>
|
||||
|
@ -126,13 +126,17 @@
|
||||
<string name="grade_comment">Comment</string>
|
||||
<string name="grade_number_new_items">Number of new ratings: %1$d</string>
|
||||
<string name="grade_average">Average: %1$.2f</string>
|
||||
<string name="grade_average_year">Annual: %1$.2f</string>
|
||||
<string name="grade_points_sum">Points: %s</string>
|
||||
<string name="grade_no_average">No average</string>
|
||||
<string name="grade_summary_average_semester">Semester average</string>
|
||||
<string name="grade_summary_average_year">Annual average</string>
|
||||
<string name="grade_summary_points">Total points</string>
|
||||
<string name="grade_summary_final_grade">Final grade</string>
|
||||
<string name="grade_summary_predicted_grade">Predicted grade</string>
|
||||
<string name="grade_summary_descriptive">Descriptive grade</string>
|
||||
<string name="grade_summary_calculated_average">Calculated average</string>
|
||||
<string name="grade_summary_calculated_average">Calculated semester average</string>
|
||||
<string name="grade_summary_calculated_average_annual">Calculated annual average</string>
|
||||
<string name="grade_summary_calculated_average_help_dialog_title">How does Calculated Average work?</string>
|
||||
<string name="grade_summary_calculated_average_help_dialog_message">The Calculated Average is the arithmetic average calculated from the subjects averages. It allows you to know the approximate final average. It is calculated in a way selected by the user in the application settings. It is recommended that you choose the appropriate option. This is because the calculation of school averages differs. Additionally, if your school reports the average of the subjects on the Vulcan page, the application downloads them and does not calculate these averages. This can be changed by forcing the calculation of the average in the application settings.\n\n<b>Average of grades only from selected semester</b>:\n1. Calculating the weighted average for each subject in a given semester\n2.Adding calculated averages\n3. Calculation of the arithmetic average of the summed averages\n\n<b>Average of averages from both semesters</b>:\n1.Calculating the weighted average for each subject in semester 1 and 2\n2. Calculating the arithmetic average of the calculated averages for semesters 1 and 2 for each subject.\n3. Adding calculated averages\n4. Calculation of the arithmetic average of the summed averages\n\n<b>Average of grades from the whole year:</b>\n1. Calculating weighted average over the year for each subject. The final average in the 1st semester is irrelevant.\n2. Adding calculated averages\n3. Calculating the arithmetic average of summed averages</string>
|
||||
<string name="grade_summary_final_average_help_dialog_title">How does the Final Average work?</string>
|
||||
|
@ -1679,7 +1679,9 @@ class GradeAverageProviderTest {
|
||||
finalPoints = "",
|
||||
finalGrade = "",
|
||||
predictedGrade = "",
|
||||
position = 0
|
||||
position = 0,
|
||||
pointsSumAllYear = null,
|
||||
averageAllYear = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -23,13 +23,15 @@ class GradeExtensionTest {
|
||||
|
||||
@Test
|
||||
fun calcWeightedAverage() {
|
||||
assertEquals(3.47, listOf(
|
||||
createGrade(5.0, 6.0, 0.33),
|
||||
createGrade(5.0, 5.0, -0.33),
|
||||
createGrade(4.0, 1.0, 0.0),
|
||||
createGrade(1.0, 9.0, 0.5),
|
||||
createGrade(0.0, .0, 0.0)
|
||||
).calcAverage(false), 0.005)
|
||||
assertEquals(
|
||||
3.47, listOf(
|
||||
createGrade(5.0, 6.0, 0.33),
|
||||
createGrade(5.0, 5.0, -0.33),
|
||||
createGrade(4.0, 1.0, 0.0),
|
||||
createGrade(1.0, 9.0, 0.5),
|
||||
createGrade(0.0, .0, 0.0)
|
||||
).calcAverage(false), 0.005
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -86,7 +88,11 @@ class GradeExtensionTest {
|
||||
assertEquals(-.25, createGrade(5.0, .0, -.33).changeModifier(.0, .25).modifier, .0)
|
||||
}
|
||||
|
||||
private fun createGrade(value: Double, weightValue: Double = .0, modifier: Double = 0.25): Grade {
|
||||
private fun createGrade(
|
||||
value: Double,
|
||||
weightValue: Double = .0,
|
||||
modifier: Double = 0.25
|
||||
): Grade {
|
||||
return Grade(
|
||||
semesterId = 1,
|
||||
studentId = 1,
|
||||
@ -116,7 +122,9 @@ class GradeExtensionTest {
|
||||
proposedPoints = "",
|
||||
finalPoints = "",
|
||||
pointsSum = "",
|
||||
average = .0
|
||||
average = .0,
|
||||
pointsSumAllYear = null,
|
||||
averageAllYear = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user