add: custom attendance percentage

This commit is contained in:
sadorowo 2024-02-29 09:40:29 +01:00
parent c1687f5856
commit 4d74c252c8
18 changed files with 105 additions and 35 deletions

View File

@ -6,7 +6,7 @@
* hide bad grades (1, 1+, 2, 2+, 2-)
* hide bad attendance (everything except present/excused attendance)
* hide comments
* fake attendance (always 100%)
* fake attendance
To get to the hidden panel, go to the "More" tab and then long-press the "Settings" tile.

View File

@ -2,6 +2,8 @@ package io.github.wulkanowy.data.repositories
import android.content.Context
import android.content.SharedPreferences
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.annotation.StringRes
import androidx.core.content.edit
import com.fredporciuncula.flow.preferences.FlowSharedPreferences
@ -283,6 +285,18 @@ class PreferencesRepository @Inject constructor(
selectedHiddenSettingTilesPreference.set(filteredValue)
}
var attendancePercentage: Float?
get() {
val value = attendancePercentagePreference.get()
return if (value == context.resources.getInteger(R.integer.pref_default_attendance_percentage).toFloat()) {
null
} else {
value
}
}
set(value) = value?.let { attendancePercentagePreference.set(it) }
?: attendancePercentagePreference.delete()
private val selectedDashboardTilesPreference: Preference<Set<String>>
get() {
val defaultSet =
@ -301,6 +315,12 @@ class PreferencesRepository @Inject constructor(
return flowSharedPref.getStringSet(prefKey, defaultSet)
}
private val attendancePercentagePreference: Preference<Float>
get() = flowSharedPref.getFloat(
context.getString(R.string.pref_key_attendance_percentage),
context.resources.getInteger(R.integer.pref_default_attendance_percentage).toFloat()
)
var dismissedAdminMessageIds: List<Int>
get() = sharedPref.getStringSet(PREF_KEY_ADMIN_DISMISSED_MESSAGE_IDS, emptySet())
.orEmpty()

View File

@ -8,7 +8,6 @@ import io.github.wulkanowy.data.db.entities.AttendanceSummary
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.databinding.ItemAttendanceSummaryBinding
import io.github.wulkanowy.databinding.ScrollableHeaderAttendanceSummaryBinding
import io.github.wulkanowy.ui.modules.dashboard.DashboardItem
import io.github.wulkanowy.utils.calculatePercentage
import io.github.wulkanowy.utils.getFormattedName
import java.time.Month
@ -20,9 +19,7 @@ class AttendanceSummaryAdapter @Inject constructor(
) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val fake = preferencesRepository
.selectedHiddenSettingTiles
.contains(DashboardItem.HiddenSettingTile.ATTENDANCE)
private val attendancePercentage = preferencesRepository.attendancePercentage
private enum class ViewType(val id: Int) {
HEADER(1),
@ -56,7 +53,10 @@ class AttendanceSummaryAdapter @Inject constructor(
}
private fun bindHeaderViewHolder(binding: ScrollableHeaderAttendanceSummaryBinding) {
binding.attendanceSummaryScrollableHeaderPercentage.text = formatPercentage(items.calculatePercentage(fake))
binding.attendanceSummaryScrollableHeaderPercentage.text = formatPercentage(
attendancePercentage?.toDouble() ?:
items.calculatePercentage()
)
}
private fun bindItemViewHolder(binding: ItemAttendanceSummaryBinding, position: Int) {
@ -68,8 +68,8 @@ class AttendanceSummaryAdapter @Inject constructor(
else -> item.month.getFormattedName()
}
attendanceSummaryPercentage.text = when (position) {
-1 -> formatPercentage(items.calculatePercentage(fake))
else -> formatPercentage(item.calculatePercentage(fake))
-1 -> formatPercentage(attendancePercentage?.toDouble() ?: item.calculatePercentage())
else -> formatPercentage(attendancePercentage?.toDouble() ?: item.calculatePercentage())
}
attendanceSummaryPresent.text = item.presence.toString()

View File

@ -284,9 +284,7 @@ class DashboardPresenter @Inject constructor(
private fun loadHorizontalGroup(student: Student, forceRefresh: Boolean) {
flow {
val fake = preferencesRepository
.selectedHiddenSettingTiles
.contains(DashboardItem.HiddenSettingTile.ATTENDANCE)
val attendancePercentage = preferencesRepository.attendancePercentage
val selectedTiles = selectedDashboardTiles
val flowSuccess = flowOf(Resource.Success(null))
@ -339,7 +337,7 @@ class DashboardPresenter @Inject constructor(
} else null
},
attendancePercentage = DashboardItem.HorizontalGroup.Cell(
data = attendanceResource.dataOrNull?.calculatePercentage(fake),
data = attendancePercentage?.toDouble() ?: attendanceResource.dataOrNull?.calculatePercentage(),
error = attendanceResource.errorOrNull != null,
isLoading = attendanceResource is Resource.Loading,
),

View File

@ -1,12 +1,17 @@
package io.github.wulkanowy.ui.modules.more
import android.os.Bundle
import android.text.InputFilter
import android.text.InputType
import android.text.Spanned
import android.view.View
import android.widget.EditText
import androidx.appcompat.app.AlertDialog
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint
import io.github.wulkanowy.R
import io.github.wulkanowy.data.repositories.PreferencesRepository
import io.github.wulkanowy.databinding.FragmentMoreBinding
import io.github.wulkanowy.ui.base.BaseFragment
import io.github.wulkanowy.ui.modules.Destination
@ -17,6 +22,24 @@ import io.github.wulkanowy.ui.modules.message.MessageFragment
import timber.log.Timber
import javax.inject.Inject
private class AttendancePercentageFilter : InputFilter {
override fun filter(
source: CharSequence?,
start: Int,
end: Int,
dest: Spanned?,
dstart: Int,
dend: Int
): CharSequence? {
val input = dest.toString() + source.toString()
val floatRepresentation = input.toFloatOrNull()
if (floatRepresentation != null && floatRepresentation in 0.0..100.0) return null
return ""
}
}
@AndroidEntryPoint
class MoreFragment : BaseFragment<FragmentMoreBinding>(R.layout.fragment_more), MoreView,
MainView.TitledView, MainView.MainChildView {
@ -27,6 +50,9 @@ class MoreFragment : BaseFragment<FragmentMoreBinding>(R.layout.fragment_more),
@Inject
lateinit var moreAdapter: MoreAdapter
@Inject
lateinit var preferencesRepository: PreferencesRepository
companion object {
fun newInstance() = MoreFragment()
}
@ -80,19 +106,44 @@ class MoreFragment : BaseFragment<FragmentMoreBinding>(R.layout.fragment_more),
}
override fun showHiddenSettings(data: List<DashboardItem.HiddenSettingTile>) {
val badGradesEntries = requireContext().resources.getStringArray(R.array.hidden_settings_bad_grades_entries)
val entries = requireContext().resources.getStringArray(R.array.hidden_settings_entries)
val values = requireContext().resources.getStringArray(R.array.hidden_settings_values)
val selectedItemsState = values.map { value -> data.any { it.name == value } }
val attendancePercentage = preferencesRepository.attendancePercentage
val badGrades = preferencesRepository.badGrades
val input = EditText(requireContext()).apply {
setPadding(40, 20, 40, 20)
hint = requireContext().getString(R.string.pref_hidden_settings_hint)
filters = arrayOf(AttendancePercentageFilter())
inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL
}
// enable only if attendance modifier is enabled
val attendanceModifierEnabled = data.any { it == DashboardItem.HiddenSettingTile.ATTENDANCE }
input.isEnabled = attendanceModifierEnabled
if (attendancePercentage != null) input.setText(attendancePercentage.toString())
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.pref_hidden_settings_title)
.setMultiChoiceItems(entries, selectedItemsState.toBooleanArray()) { _, _, _ -> }
.setMultiChoiceItems(entries, selectedItemsState.toBooleanArray()) { dialog, index, _ ->
// if attendance modifier is enabled, enable text input
if (index == values.indexOf(DashboardItem.HiddenSettingTile.ATTENDANCE.name))
input.isEnabled = (dialog as AlertDialog).listView.checkedItemPositions[index]
}
.setView(input)
.setPositiveButton(android.R.string.ok) { dialog, _ ->
val selectedState = (dialog as AlertDialog).listView.checkedItemPositions
val selectedValues = values.filterIndexed { index, _ -> selectedState[index] }
val inputAttendancePercentage = selectedValues
.find { it == DashboardItem.HiddenSettingTile.ATTENDANCE.name }
?.let { input.text.toString().toFloatOrNull() }
Timber.i("Selected hidden settings: $selectedValues")
presenter.onHiddenSettingsSelected(selectedValues)
presenter.onHiddenSettingsSelected(selectedValues, inputAttendancePercentage)
}
.setNegativeButton(android.R.string.cancel) { _, _ -> }
.show()

View File

@ -45,11 +45,13 @@ class MorePresenter @Inject constructor(
}
}
fun onHiddenSettingsSelected(selectedItems: List<String>) {
fun onHiddenSettingsSelected(selectedItems: List<String>, attendance: Float?) {
preferencesRepository.selectedHiddenSettingTiles = selectedItems.map {
DashboardItem.HiddenSettingTile.valueOf(it)
}
preferencesRepository.attendancePercentage = attendance
view?.restartApp()
}

View File

@ -19,18 +19,10 @@ private inline val AttendanceSummary.allAbsences: Double
inline val Attendance.isExcusableOrNotExcused: Boolean
get() = (excusable || ((absence || lateness) && !excused)) && excuseStatus == null
fun AttendanceSummary.calculatePercentage(fake: Boolean = false) = if (fake) {
100.0
} else {
calculatePercentage(allPresences, allAbsences)
}
fun AttendanceSummary.calculatePercentage() = calculatePercentage(allPresences, allAbsences)
fun List<AttendanceSummary>.calculatePercentage(fake: Boolean = false): Double {
return if (fake) {
100.0
} else {
calculatePercentage(sumOf { it.allPresences }, sumOf { it.allAbsences })
}
fun List<AttendanceSummary>.calculatePercentage(): Double {
return calculatePercentage(sumOf { it.allPresences }, sumOf { it.allAbsences })
}
private fun calculatePercentage(presence: Double, absence: Double): Double {

View File

@ -72,6 +72,6 @@
<item>Špatné hodnocení</item>
<item>Špatná účast</item>
<item>Poznámky</item>
<item>Falešná 100% účast</item>
<item>Falešná účast</item>
</string-array>
</resources>

View File

@ -71,6 +71,6 @@
<item>Bad grades</item>
<item>Bad attendance</item>
<item>Notes</item>
<item>Fake 100% attendance</item>
<item>Fake attendance</item>
</string-array>
</resources>

View File

@ -71,6 +71,6 @@
<item>Bad grades</item>
<item>Bad attendance</item>
<item>Notes</item>
<item>Fake 100% attendance</item>
<item>Fake attendance</item>
</string-array>
</resources>

View File

@ -71,6 +71,6 @@
<item>Bad grades</item>
<item>Bad attendance</item>
<item>Notes</item>
<item>Fake 100% attendance</item>
<item>Fake attendance</item>
</string-array>
</resources>

View File

@ -71,6 +71,6 @@
<item>Słabe oceny</item>
<item>Słaba frekwencja</item>
<item>Uwagi</item>
<item>Fałszywa 100% frekwencja</item>
<item>Fałszywa frekwencja</item>
</string-array>
</resources>

View File

@ -71,6 +71,6 @@
<item>Плохие оценки</item>
<item>Плохая посещаемость</item>
<item>Примечания</item>
<item>Фейковая 100% посещаемость</item>
<item>Фейковая посещаемость</item>
</string-array>
</resources>

View File

@ -71,6 +71,6 @@
<item>Zlé známky</item>
<item>Zlá účasť</item>
<item>Poznámky</item>
<item>Falošná 100% účasť</item>
<item>Falošná účasť</item>
</string-array>
</resources>

View File

@ -71,6 +71,6 @@
<item>Погані оцінки</item>
<item>Погана відвідуваність</item>
<item>Примітки</item>
<item>Фальшива 100% явка</item>
<item>Фальшива явка</item>
</string-array>
</resources>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="pref_default_attendance_percentage">-1</integer>
</resources>

View File

@ -161,7 +161,7 @@
<item>Bad grades</item>
<item>Bad attendance</item>
<item>Notes</item>
<item>Fake 100% attendance</item>
<item>Fake attendance</item>
</string-array>
<string-array name="hidden_settings_values" translatable="false">
<item>BAD_GRADES</item>

View File

@ -865,4 +865,7 @@
<string name="error_feature_disabled">Feature disabled by your school</string>
<string name="error_feature_not_available">Feature not available. Login in a mode other than Mobile API</string>
<string name="error_field_required">This field is required</string>
<string name="pref_hidden_settings_hint">Attendance percentage</string>
<string name="pref_key_attendance_percentage">attendance_percentage</string>
<string name="pref_hidden_settings_bad_grades_title">Bad grades</string>
</resources>