forked from github/wulkanowy-mirror
Fix OOM in grade statistics (#1192)
This commit is contained in:
parent
9139febbdf
commit
1afa7ecf3c
@ -5,10 +5,9 @@ import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
|||||||
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
|
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.data.pojos.GradeStatisticsItem
|
import io.github.wulkanowy.data.pojos.GradeStatisticsItem
|
||||||
import io.github.wulkanowy.ui.modules.grade.statistics.ViewType
|
|
||||||
import io.github.wulkanowy.sdk.pojo.GradeStatisticsSubject as SdkGradeStatisticsSubject
|
|
||||||
import io.github.wulkanowy.sdk.pojo.GradeStatisticsSemester as SdkGradeStatisticsSemester
|
|
||||||
import io.github.wulkanowy.sdk.pojo.GradePointsStatistics as SdkGradePointsStatistics
|
import io.github.wulkanowy.sdk.pojo.GradePointsStatistics as SdkGradePointsStatistics
|
||||||
|
import io.github.wulkanowy.sdk.pojo.GradeStatisticsSemester as SdkGradeStatisticsSemester
|
||||||
|
import io.github.wulkanowy.sdk.pojo.GradeStatisticsSubject as SdkGradeStatisticsSubject
|
||||||
|
|
||||||
@JvmName("mapToEntitiesSubject")
|
@JvmName("mapToEntitiesSubject")
|
||||||
fun List<SdkGradeStatisticsSubject>.mapToEntities(semester: Semester) = map {
|
fun List<SdkGradeStatisticsSubject>.mapToEntities(semester: Semester) = map {
|
||||||
@ -51,7 +50,7 @@ fun List<SdkGradePointsStatistics>.mapToEntities(semester: Semester) = map {
|
|||||||
|
|
||||||
fun List<GradePartialStatistics>.mapPartialToStatisticItems() = filterNot { it.classAmounts.isEmpty() }.map {
|
fun List<GradePartialStatistics>.mapPartialToStatisticItems() = filterNot { it.classAmounts.isEmpty() }.map {
|
||||||
GradeStatisticsItem(
|
GradeStatisticsItem(
|
||||||
type = ViewType.PARTIAL,
|
type = GradeStatisticsItem.DataType.PARTIAL,
|
||||||
average = it.classAverage,
|
average = it.classAverage,
|
||||||
partial = it,
|
partial = it,
|
||||||
points = null,
|
points = null,
|
||||||
@ -61,7 +60,7 @@ fun List<GradePartialStatistics>.mapPartialToStatisticItems() = filterNot { it.c
|
|||||||
|
|
||||||
fun List<GradeSemesterStatistics>.mapSemesterToStatisticItems() = filterNot { it.amounts.isEmpty() }.map {
|
fun List<GradeSemesterStatistics>.mapSemesterToStatisticItems() = filterNot { it.amounts.isEmpty() }.map {
|
||||||
GradeStatisticsItem(
|
GradeStatisticsItem(
|
||||||
type = ViewType.SEMESTER,
|
type = GradeStatisticsItem.DataType.SEMESTER,
|
||||||
partial = null,
|
partial = null,
|
||||||
points = null,
|
points = null,
|
||||||
average = "",
|
average = "",
|
||||||
@ -71,7 +70,7 @@ fun List<GradeSemesterStatistics>.mapSemesterToStatisticItems() = filterNot { it
|
|||||||
|
|
||||||
fun List<GradePointsStatistics>.mapPointsToStatisticsItems() = map {
|
fun List<GradePointsStatistics>.mapPointsToStatisticsItems() = map {
|
||||||
GradeStatisticsItem(
|
GradeStatisticsItem(
|
||||||
type = ViewType.POINTS,
|
type = GradeStatisticsItem.DataType.POINTS,
|
||||||
partial = null,
|
partial = null,
|
||||||
semester = null,
|
semester = null,
|
||||||
average = "",
|
average = "",
|
||||||
|
@ -3,11 +3,10 @@ package io.github.wulkanowy.data.pojos
|
|||||||
import io.github.wulkanowy.data.db.entities.GradePartialStatistics
|
import io.github.wulkanowy.data.db.entities.GradePartialStatistics
|
||||||
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
||||||
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
|
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
|
||||||
import io.github.wulkanowy.ui.modules.grade.statistics.ViewType
|
|
||||||
|
|
||||||
data class GradeStatisticsItem(
|
data class GradeStatisticsItem(
|
||||||
|
|
||||||
val type: ViewType,
|
val type: DataType,
|
||||||
|
|
||||||
val average: String,
|
val average: String,
|
||||||
|
|
||||||
@ -16,4 +15,11 @@ data class GradeStatisticsItem(
|
|||||||
val semester: GradeSemesterStatistics?,
|
val semester: GradeSemesterStatistics?,
|
||||||
|
|
||||||
val points: GradePointsStatistics?
|
val points: GradePointsStatistics?
|
||||||
)
|
|
||||||
|
) {
|
||||||
|
enum class DataType {
|
||||||
|
SEMESTER,
|
||||||
|
PARTIAL,
|
||||||
|
POINTS,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -22,6 +22,7 @@ import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
|||||||
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
|
import io.github.wulkanowy.data.db.entities.GradeSemesterStatistics
|
||||||
import io.github.wulkanowy.data.pojos.GradeStatisticsItem
|
import io.github.wulkanowy.data.pojos.GradeStatisticsItem
|
||||||
import io.github.wulkanowy.databinding.ItemGradeStatisticsBarBinding
|
import io.github.wulkanowy.databinding.ItemGradeStatisticsBarBinding
|
||||||
|
import io.github.wulkanowy.databinding.ItemGradeStatisticsHeaderBinding
|
||||||
import io.github.wulkanowy.databinding.ItemGradeStatisticsPieBinding
|
import io.github.wulkanowy.databinding.ItemGradeStatisticsPieBinding
|
||||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -29,12 +30,16 @@ import javax.inject.Inject
|
|||||||
class GradeStatisticsAdapter @Inject constructor() :
|
class GradeStatisticsAdapter @Inject constructor() :
|
||||||
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
|
||||||
|
var currentDataType = GradeStatisticsItem.DataType.PARTIAL
|
||||||
|
|
||||||
var items = emptyList<GradeStatisticsItem>()
|
var items = emptyList<GradeStatisticsItem>()
|
||||||
|
|
||||||
var theme: String = "vulcan"
|
var theme: String = "vulcan"
|
||||||
|
|
||||||
var showAllSubjectsOnList: Boolean = false
|
var showAllSubjectsOnList: Boolean = false
|
||||||
|
|
||||||
|
var onDataTypeChangeListener: () -> Unit = {}
|
||||||
|
|
||||||
private val vulcanGradeColors = listOf(
|
private val vulcanGradeColors = listOf(
|
||||||
6 to R.color.grade_vulcan_six,
|
6 to R.color.grade_vulcan_six,
|
||||||
5 to R.color.grade_vulcan_five,
|
5 to R.color.grade_vulcan_five,
|
||||||
@ -62,37 +67,90 @@ class GradeStatisticsAdapter @Inject constructor() :
|
|||||||
"6, 6-", "5, 5-, 5+", "4, 4-, 4+", "3, 3-, 3+", "2, 2-, 2+", "1, 1+"
|
"6, 6-", "5, 5-, 5+", "4, 4-, 4+", "3, 3-, 3+", "2, 2-, 2+", "1, 1+"
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun getItemCount() = if (showAllSubjectsOnList) items.size else (if (items.isEmpty()) 0 else 1)
|
override fun getItemCount() =
|
||||||
|
(if (showAllSubjectsOnList) items.size else (if (items.isEmpty()) 0 else 1)) + 1
|
||||||
|
|
||||||
override fun getItemViewType(position: Int) = items[position].type.id
|
override fun getItemViewType(position: Int) =
|
||||||
|
if (position == 0) {
|
||||||
|
ViewType.HEADER.id
|
||||||
|
} else {
|
||||||
|
when (items[position - 1].type) {
|
||||||
|
GradeStatisticsItem.DataType.PARTIAL -> ViewType.PARTIAL.id
|
||||||
|
GradeStatisticsItem.DataType.POINTS -> ViewType.POINTS.id
|
||||||
|
GradeStatisticsItem.DataType.SEMESTER -> ViewType.SEMESTER.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
val inflater = LayoutInflater.from(parent.context)
|
val inflater = LayoutInflater.from(parent.context)
|
||||||
return when (viewType) {
|
return when (viewType) {
|
||||||
ViewType.PARTIAL.id -> PartialViewHolder(ItemGradeStatisticsPieBinding.inflate(inflater, parent, false))
|
ViewType.PARTIAL.id -> PartialViewHolder(
|
||||||
ViewType.SEMESTER.id -> SemesterViewHolder(ItemGradeStatisticsPieBinding.inflate(inflater, parent, false))
|
ItemGradeStatisticsPieBinding.inflate(inflater, parent, false)
|
||||||
ViewType.POINTS.id -> PointsViewHolder(ItemGradeStatisticsBarBinding.inflate(inflater, parent, false))
|
)
|
||||||
|
ViewType.SEMESTER.id -> SemesterViewHolder(
|
||||||
|
ItemGradeStatisticsPieBinding.inflate(inflater, parent, false)
|
||||||
|
)
|
||||||
|
ViewType.POINTS.id -> PointsViewHolder(
|
||||||
|
ItemGradeStatisticsBarBinding.inflate(inflater, parent, false)
|
||||||
|
)
|
||||||
|
ViewType.HEADER.id -> HeaderViewHolder(
|
||||||
|
ItemGradeStatisticsHeaderBinding.inflate(inflater, parent, false)
|
||||||
|
)
|
||||||
else -> throw IllegalStateException()
|
else -> throw IllegalStateException()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
|
val index = position - 1
|
||||||
|
|
||||||
when (holder) {
|
when (holder) {
|
||||||
is PartialViewHolder -> bindPartialChart(holder.binding, items[position].partial!!)
|
is PartialViewHolder -> bindPartialChart(holder.binding, items[index].partial!!)
|
||||||
is SemesterViewHolder -> bindSemesterChart(holder.binding, items[position].semester!!)
|
is SemesterViewHolder -> bindSemesterChart(holder.binding, items[index].semester!!)
|
||||||
is PointsViewHolder -> bindBarChart(holder.binding, items[position].points!!)
|
is PointsViewHolder -> bindBarChart(holder.binding, items[index].points!!)
|
||||||
|
is HeaderViewHolder -> bindHeader(holder.binding)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindPartialChart(binding: ItemGradeStatisticsPieBinding, partials: GradePartialStatistics) {
|
private fun bindHeader(binding: ItemGradeStatisticsHeaderBinding) {
|
||||||
|
binding.gradeStatisticsTypeSwitch.check(
|
||||||
|
when (currentDataType) {
|
||||||
|
GradeStatisticsItem.DataType.PARTIAL -> R.id.gradeStatisticsTypePartial
|
||||||
|
GradeStatisticsItem.DataType.SEMESTER -> R.id.gradeStatisticsTypeSemester
|
||||||
|
GradeStatisticsItem.DataType.POINTS -> R.id.gradeStatisticsTypePoints
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
binding.gradeStatisticsTypeSwitch.setOnCheckedChangeListener { _, checkedId ->
|
||||||
|
currentDataType = when (checkedId) {
|
||||||
|
R.id.gradeStatisticsTypePartial -> GradeStatisticsItem.DataType.PARTIAL
|
||||||
|
R.id.gradeStatisticsTypeSemester -> GradeStatisticsItem.DataType.SEMESTER
|
||||||
|
R.id.gradeStatisticsTypePoints -> GradeStatisticsItem.DataType.POINTS
|
||||||
|
else -> GradeStatisticsItem.DataType.PARTIAL
|
||||||
|
}
|
||||||
|
onDataTypeChangeListener()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun bindPartialChart(
|
||||||
|
binding: ItemGradeStatisticsPieBinding,
|
||||||
|
partials: GradePartialStatistics
|
||||||
|
) {
|
||||||
bindPieChart(binding, partials.subject, partials.classAverage, partials.classAmounts)
|
bindPieChart(binding, partials.subject, partials.classAverage, partials.classAmounts)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindSemesterChart(binding: ItemGradeStatisticsPieBinding, semester: GradeSemesterStatistics) {
|
private fun bindSemesterChart(
|
||||||
|
binding: ItemGradeStatisticsPieBinding,
|
||||||
|
semester: GradeSemesterStatistics
|
||||||
|
) {
|
||||||
bindPieChart(binding, semester.subject, semester.average, semester.amounts)
|
bindPieChart(binding, semester.subject, semester.average, semester.amounts)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindPieChart(binding: ItemGradeStatisticsPieBinding, subject: String, average: String, amounts: List<Int>) {
|
private fun bindPieChart(
|
||||||
|
binding: ItemGradeStatisticsPieBinding,
|
||||||
|
subject: String,
|
||||||
|
average: String,
|
||||||
|
amounts: List<Int>
|
||||||
|
) {
|
||||||
with(binding.gradeStatisticsPieTitle) {
|
with(binding.gradeStatisticsPieTitle) {
|
||||||
text = subject
|
text = subject
|
||||||
visibility = if (items.size == 1 || !showAllSubjectsOnList) GONE else VISIBLE
|
visibility = if (items.size == 1 || !showAllSubjectsOnList) GONE else VISIBLE
|
||||||
@ -114,7 +172,8 @@ class GradeStatisticsAdapter @Inject constructor() :
|
|||||||
valueTextSize = 12f
|
valueTextSize = 12f
|
||||||
sliceSpace = 1f
|
sliceSpace = 1f
|
||||||
valueTextColor = Color.WHITE
|
valueTextColor = Color.WHITE
|
||||||
val grades = amounts.mapIndexed { grade, amount -> (grade + 1) to amount }.filterNot { it.second == 0 }
|
val grades = amounts.mapIndexed { grade, amount -> (grade + 1) to amount }
|
||||||
|
.filterNot { it.second == 0 }
|
||||||
setColors(grades.reversed().map { (grade, _) ->
|
setColors(grades.reversed().map { (grade, _) ->
|
||||||
gradeColors.single { color -> color.first == grade }.second
|
gradeColors.single { color -> color.first == grade }.second
|
||||||
}.toIntArray(), binding.root.context)
|
}.toIntArray(), binding.root.context)
|
||||||
@ -126,7 +185,11 @@ class GradeStatisticsAdapter @Inject constructor() :
|
|||||||
data = PieData(dataset).apply {
|
data = PieData(dataset).apply {
|
||||||
setValueFormatter(object : ValueFormatter() {
|
setValueFormatter(object : ValueFormatter() {
|
||||||
override fun getPieLabel(value: Float, pieEntry: PieEntry): String {
|
override fun getPieLabel(value: Float, pieEntry: PieEntry): String {
|
||||||
return resources.getQuantityString(R.plurals.grade_number_item, value.toInt(), value.toInt())
|
return resources.getQuantityString(
|
||||||
|
R.plurals.grade_number_item,
|
||||||
|
value.toInt(),
|
||||||
|
value.toInt()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -143,11 +206,14 @@ class GradeStatisticsAdapter @Inject constructor() :
|
|||||||
|
|
||||||
val numberOfGradesString = amounts.fold(0) { acc, it -> acc + it }
|
val numberOfGradesString = amounts.fold(0) { acc, it -> acc + it }
|
||||||
.let { resources.getQuantityString(R.plurals.grade_number_item, it, it) }
|
.let { resources.getQuantityString(R.plurals.grade_number_item, it, it) }
|
||||||
val averageString = binding.root.context.getString(R.string.grade_statistics_average, average)
|
val averageString =
|
||||||
|
binding.root.context.getString(R.string.grade_statistics_average, average)
|
||||||
|
|
||||||
minAngleForSlices = 25f
|
minAngleForSlices = 25f
|
||||||
description.isEnabled = false
|
description.isEnabled = false
|
||||||
centerText = numberOfGradesString + ("\n\n" + averageString).takeIf { average.isNotBlank() }.orEmpty()
|
centerText =
|
||||||
|
numberOfGradesString + ("\n\n" + averageString).takeIf { average.isNotBlank() }
|
||||||
|
.orEmpty()
|
||||||
|
|
||||||
setHoleColor(context.getThemeAttrColor(android.R.attr.windowBackground))
|
setHoleColor(context.getThemeAttrColor(android.R.attr.windowBackground))
|
||||||
setCenterTextColor(context.getThemeAttrColor(android.R.attr.textColorPrimary))
|
setCenterTextColor(context.getThemeAttrColor(android.R.attr.textColorPrimary))
|
||||||
@ -155,16 +221,21 @@ class GradeStatisticsAdapter @Inject constructor() :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun bindBarChart(binding: ItemGradeStatisticsBarBinding, points: GradePointsStatistics) {
|
private fun bindBarChart(
|
||||||
|
binding: ItemGradeStatisticsBarBinding,
|
||||||
|
points: GradePointsStatistics
|
||||||
|
) {
|
||||||
with(binding.gradeStatisticsBarTitle) {
|
with(binding.gradeStatisticsBarTitle) {
|
||||||
text = points.subject
|
text = points.subject
|
||||||
visibility = if (items.size == 1) GONE else VISIBLE
|
visibility = if (items.size == 1) GONE else VISIBLE
|
||||||
}
|
}
|
||||||
|
|
||||||
val dataset = BarDataSet(listOf(
|
val dataset = BarDataSet(
|
||||||
|
listOf(
|
||||||
BarEntry(1f, points.others.toFloat()),
|
BarEntry(1f, points.others.toFloat()),
|
||||||
BarEntry(2f, points.student.toFloat())
|
BarEntry(2f, points.student.toFloat())
|
||||||
), binding.root.context.getString(R.string.grade_statistics_legend))
|
), binding.root.context.getString(R.string.grade_statistics_legend)
|
||||||
|
)
|
||||||
|
|
||||||
with(dataset) {
|
with(dataset) {
|
||||||
valueTextSize = 12f
|
valueTextSize = 12f
|
||||||
@ -189,7 +260,8 @@ class GradeStatisticsAdapter @Inject constructor() :
|
|||||||
form = Legend.LegendForm.SQUARE
|
form = Legend.LegendForm.SQUARE
|
||||||
},
|
},
|
||||||
LegendEntry().apply {
|
LegendEntry().apply {
|
||||||
label = binding.root.context.getString(R.string.grade_statistics_average_student)
|
label =
|
||||||
|
binding.root.context.getString(R.string.grade_statistics_average_student)
|
||||||
formColor = gradePointsColors[1]
|
formColor = gradePointsColors[1]
|
||||||
form = Legend.LegendForm.SQUARE
|
form = Legend.LegendForm.SQUARE
|
||||||
}
|
}
|
||||||
@ -226,4 +298,7 @@ class GradeStatisticsAdapter @Inject constructor() :
|
|||||||
|
|
||||||
private class PointsViewHolder(val binding: ItemGradeStatisticsBarBinding) :
|
private class PointsViewHolder(val binding: ItemGradeStatisticsBarBinding) :
|
||||||
RecyclerView.ViewHolder(binding.root)
|
RecyclerView.ViewHolder(binding.root)
|
||||||
|
|
||||||
|
private class HeaderViewHolder(val binding: ItemGradeStatisticsHeaderBinding) :
|
||||||
|
RecyclerView.ViewHolder(binding.root)
|
||||||
}
|
}
|
||||||
|
@ -38,27 +38,28 @@ class GradeStatisticsFragment :
|
|||||||
|
|
||||||
override val isViewEmpty get() = statisticsAdapter.items.isEmpty()
|
override val isViewEmpty get() = statisticsAdapter.items.isEmpty()
|
||||||
|
|
||||||
override val currentType
|
override val currentType get() = statisticsAdapter.currentDataType
|
||||||
get() = when (binding.gradeStatisticsTypeSwitch.checkedRadioButtonId) {
|
|
||||||
R.id.gradeStatisticsTypeSemester -> ViewType.SEMESTER
|
|
||||||
R.id.gradeStatisticsTypePartial -> ViewType.PARTIAL
|
|
||||||
else -> ViewType.POINTS
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
binding = FragmentGradeStatisticsBinding.bind(view)
|
binding = FragmentGradeStatisticsBinding.bind(view)
|
||||||
messageContainer = binding.gradeStatisticsSwipe
|
messageContainer = binding.gradeStatisticsSwipe
|
||||||
presenter.onAttachView(this, savedInstanceState?.getSerializable(SAVED_CHART_TYPE) as? ViewType)
|
presenter.onAttachView(
|
||||||
|
this,
|
||||||
|
savedInstanceState?.getSerializable(SAVED_CHART_TYPE) as? GradeStatisticsItem.DataType
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initView() {
|
override fun initView() {
|
||||||
|
statisticsAdapter.onDataTypeChangeListener = presenter::onTypeChange
|
||||||
|
|
||||||
with(binding.gradeStatisticsRecycler) {
|
with(binding.gradeStatisticsRecycler) {
|
||||||
layoutManager = LinearLayoutManager(requireContext())
|
layoutManager = LinearLayoutManager(requireContext())
|
||||||
adapter = statisticsAdapter
|
adapter = statisticsAdapter
|
||||||
}
|
}
|
||||||
|
|
||||||
subjectsAdapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, mutableListOf())
|
subjectsAdapter =
|
||||||
|
ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, mutableListOf())
|
||||||
subjectsAdapter.setDropDownViewResource(R.layout.item_attendance_summary_subject)
|
subjectsAdapter.setDropDownViewResource(R.layout.item_attendance_summary_subject)
|
||||||
|
|
||||||
with(binding.gradeStatisticsSubjects) {
|
with(binding.gradeStatisticsSubjects) {
|
||||||
@ -71,7 +72,9 @@ class GradeStatisticsFragment :
|
|||||||
|
|
||||||
gradeStatisticsSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
|
gradeStatisticsSwipe.setOnRefreshListener(presenter::onSwipeRefresh)
|
||||||
gradeStatisticsSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary))
|
gradeStatisticsSwipe.setColorSchemeColors(requireContext().getThemeAttrColor(R.attr.colorPrimary))
|
||||||
gradeStatisticsSwipe.setProgressBackgroundColorSchemeColor(requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh))
|
gradeStatisticsSwipe.setProgressBackgroundColorSchemeColor(
|
||||||
|
requireContext().getThemeAttrColor(R.attr.colorSwipeRefresh)
|
||||||
|
)
|
||||||
gradeStatisticsErrorRetry.setOnClickListener { presenter.onRetry() }
|
gradeStatisticsErrorRetry.setOnClickListener { presenter.onRetry() }
|
||||||
gradeStatisticsErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
gradeStatisticsErrorDetails.setOnClickListener { presenter.onDetailsClick() }
|
||||||
}
|
}
|
||||||
@ -85,11 +88,15 @@ class GradeStatisticsFragment :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updateData(items: List<GradeStatisticsItem>, theme: String, showAllSubjectsOnStatisticsList: Boolean) {
|
override fun updateData(
|
||||||
|
newItems: List<GradeStatisticsItem>,
|
||||||
|
newTheme: String,
|
||||||
|
showAllSubjectsOnStatisticsList: Boolean
|
||||||
|
) {
|
||||||
with(statisticsAdapter) {
|
with(statisticsAdapter) {
|
||||||
this.showAllSubjectsOnList = showAllSubjectsOnStatisticsList
|
showAllSubjectsOnList = showAllSubjectsOnStatisticsList
|
||||||
this.theme = theme
|
theme = newTheme
|
||||||
this.items = items
|
items = newItems
|
||||||
notifyDataSetChanged()
|
notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,11 +110,7 @@ class GradeStatisticsFragment :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun resetView() {
|
override fun resetView() {
|
||||||
binding.gradeStatisticsScroll.scrollTo(0, 0)
|
binding.gradeStatisticsRecycler.scrollToPosition(0)
|
||||||
}
|
|
||||||
|
|
||||||
override fun showContent(show: Boolean) {
|
|
||||||
binding.gradeStatisticsRecycler.visibility = if (show) View.VISIBLE else View.GONE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showEmpty(show: Boolean) {
|
override fun showEmpty(show: Boolean) {
|
||||||
@ -154,11 +157,6 @@ class GradeStatisticsFragment :
|
|||||||
(parentFragment as? GradeFragment)?.onChildRefresh()
|
(parentFragment as? GradeFragment)?.onChildRefresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
binding.gradeStatisticsTypeSwitch.setOnCheckedChangeListener { _, _ -> presenter.onTypeChange() }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSaveInstanceState(outState: Bundle) {
|
override fun onSaveInstanceState(outState: Bundle) {
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
outState.putSerializable(SAVED_CHART_TYPE, presenter.currentType)
|
outState.putSerializable(SAVED_CHART_TYPE, presenter.currentType)
|
||||||
|
@ -35,12 +35,12 @@ class GradeStatisticsPresenter @Inject constructor(
|
|||||||
|
|
||||||
private lateinit var lastError: Throwable
|
private lateinit var lastError: Throwable
|
||||||
|
|
||||||
var currentType: ViewType = ViewType.PARTIAL
|
var currentType: GradeStatisticsItem.DataType = GradeStatisticsItem.DataType.PARTIAL
|
||||||
private set
|
private set
|
||||||
|
|
||||||
fun onAttachView(view: GradeStatisticsView, type: ViewType?) {
|
fun onAttachView(view: GradeStatisticsView, type: GradeStatisticsItem.DataType?) {
|
||||||
super.onAttachView(view)
|
super.onAttachView(view)
|
||||||
currentType = type ?: ViewType.PARTIAL
|
currentType = type ?: GradeStatisticsItem.DataType.PARTIAL
|
||||||
view.initView()
|
view.initView()
|
||||||
errorHandler.showErrorMessage = ::showErrorViewOnError
|
errorHandler.showErrorMessage = ::showErrorViewOnError
|
||||||
}
|
}
|
||||||
@ -59,11 +59,11 @@ class GradeStatisticsPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onParentViewChangeSemester() {
|
fun onParentViewChangeSemester() {
|
||||||
|
clearDataInView()
|
||||||
view?.run {
|
view?.run {
|
||||||
showProgress(true)
|
showProgress(true)
|
||||||
enableSwipe(false)
|
enableSwipe(false)
|
||||||
showRefresh(false)
|
showRefresh(false)
|
||||||
showContent(false)
|
|
||||||
showErrorView(false)
|
showErrorView(false)
|
||||||
showEmpty(false)
|
showEmpty(false)
|
||||||
clearView()
|
clearView()
|
||||||
@ -90,8 +90,8 @@ class GradeStatisticsPresenter @Inject constructor(
|
|||||||
|
|
||||||
fun onSubjectSelected(name: String?) {
|
fun onSubjectSelected(name: String?) {
|
||||||
Timber.i("Select grade stats subject $name")
|
Timber.i("Select grade stats subject $name")
|
||||||
|
clearDataInView()
|
||||||
view?.run {
|
view?.run {
|
||||||
showContent(false)
|
|
||||||
showProgress(true)
|
showProgress(true)
|
||||||
enableSwipe(false)
|
enableSwipe(false)
|
||||||
showEmpty(false)
|
showEmpty(false)
|
||||||
@ -104,11 +104,11 @@ class GradeStatisticsPresenter @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onTypeChange() {
|
fun onTypeChange() {
|
||||||
val type = view?.currentType ?: ViewType.POINTS
|
val type = view?.currentType ?: GradeStatisticsItem.DataType.POINTS
|
||||||
Timber.i("Select grade stats semester: $type")
|
Timber.i("Select grade stats semester: $type")
|
||||||
cancelJobs("load")
|
cancelJobs("load")
|
||||||
|
clearDataInView()
|
||||||
view?.run {
|
view?.run {
|
||||||
showContent(false)
|
|
||||||
showProgress(true)
|
showProgress(true)
|
||||||
enableSwipe(false)
|
enableSwipe(false)
|
||||||
showEmpty(false)
|
showEmpty(false)
|
||||||
@ -143,10 +143,16 @@ class GradeStatisticsPresenter @Inject constructor(
|
|||||||
}.launch("subjects")
|
}.launch("subjects")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadDataByType(semesterId: Int, subjectName: String, type: ViewType, forceRefresh: Boolean = false) {
|
private fun loadDataByType(
|
||||||
|
semesterId: Int,
|
||||||
|
subjectName: String,
|
||||||
|
type: GradeStatisticsItem.DataType,
|
||||||
|
forceRefresh: Boolean = false
|
||||||
|
) {
|
||||||
Timber.i("Loading grade stats data started")
|
Timber.i("Loading grade stats data started")
|
||||||
|
|
||||||
currentSubjectName = if (preferencesRepository.showAllSubjectsOnStatisticsList) "Wszystkie" else subjectName
|
currentSubjectName =
|
||||||
|
if (preferencesRepository.showAllSubjectsOnStatisticsList) "Wszystkie" else subjectName
|
||||||
currentType = type
|
currentType = type
|
||||||
|
|
||||||
flowWithResourceIn {
|
flowWithResourceIn {
|
||||||
@ -156,9 +162,30 @@ class GradeStatisticsPresenter @Inject constructor(
|
|||||||
|
|
||||||
with(gradeStatisticsRepository) {
|
with(gradeStatisticsRepository) {
|
||||||
when (type) {
|
when (type) {
|
||||||
ViewType.PARTIAL -> getGradesPartialStatistics(student, semester, currentSubjectName, forceRefresh)
|
GradeStatisticsItem.DataType.PARTIAL -> {
|
||||||
ViewType.SEMESTER -> getGradesSemesterStatistics(student, semester, currentSubjectName, forceRefresh)
|
getGradesPartialStatistics(
|
||||||
ViewType.POINTS -> getGradesPointsStatistics(student, semester, currentSubjectName, forceRefresh)
|
student = student,
|
||||||
|
semester = semester,
|
||||||
|
subjectName = currentSubjectName,
|
||||||
|
forceRefresh = forceRefresh
|
||||||
|
)
|
||||||
|
}
|
||||||
|
GradeStatisticsItem.DataType.SEMESTER -> {
|
||||||
|
getGradesSemesterStatistics(
|
||||||
|
student = student,
|
||||||
|
semester = semester,
|
||||||
|
subjectName = currentSubjectName,
|
||||||
|
forceRefresh = forceRefresh
|
||||||
|
)
|
||||||
|
}
|
||||||
|
GradeStatisticsItem.DataType.POINTS -> {
|
||||||
|
getGradesPointsStatistics(
|
||||||
|
student = student,
|
||||||
|
semester = semester,
|
||||||
|
subjectName = currentSubjectName,
|
||||||
|
forceRefresh = forceRefresh
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.onEach {
|
}.onEach {
|
||||||
@ -168,12 +195,15 @@ class GradeStatisticsPresenter @Inject constructor(
|
|||||||
if (!isNoContent) {
|
if (!isNoContent) {
|
||||||
view?.run {
|
view?.run {
|
||||||
showEmpty(isNoContent)
|
showEmpty(isNoContent)
|
||||||
showContent(!isNoContent)
|
|
||||||
showErrorView(false)
|
showErrorView(false)
|
||||||
enableSwipe(true)
|
enableSwipe(true)
|
||||||
showRefresh(true)
|
showRefresh(true)
|
||||||
showProgress(false)
|
showProgress(false)
|
||||||
updateData(it.data!!, preferencesRepository.gradeColorTheme, preferencesRepository.showAllSubjectsOnStatisticsList)
|
updateData(
|
||||||
|
if (isNoContent) emptyList() else it.data!!,
|
||||||
|
preferencesRepository.gradeColorTheme,
|
||||||
|
preferencesRepository.showAllSubjectsOnStatisticsList
|
||||||
|
)
|
||||||
showSubjects(!preferencesRepository.showAllSubjectsOnStatisticsList)
|
showSubjects(!preferencesRepository.showAllSubjectsOnStatisticsList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -183,9 +213,12 @@ class GradeStatisticsPresenter @Inject constructor(
|
|||||||
view?.run {
|
view?.run {
|
||||||
val isNoContent = checkIsNoContent(it.data!!, type)
|
val isNoContent = checkIsNoContent(it.data!!, type)
|
||||||
showEmpty(isNoContent)
|
showEmpty(isNoContent)
|
||||||
showContent(!isNoContent)
|
|
||||||
showErrorView(false)
|
showErrorView(false)
|
||||||
updateData(it.data, preferencesRepository.gradeColorTheme, preferencesRepository.showAllSubjectsOnStatisticsList)
|
updateData(
|
||||||
|
if (isNoContent) emptyList() else it.data,
|
||||||
|
preferencesRepository.gradeColorTheme,
|
||||||
|
preferencesRepository.showAllSubjectsOnStatisticsList
|
||||||
|
)
|
||||||
showSubjects(!preferencesRepository.showAllSubjectsOnStatisticsList)
|
showSubjects(!preferencesRepository.showAllSubjectsOnStatisticsList)
|
||||||
}
|
}
|
||||||
analytics.logEvent(
|
analytics.logEvent(
|
||||||
@ -209,14 +242,29 @@ class GradeStatisticsPresenter @Inject constructor(
|
|||||||
}.launch("load")
|
}.launch("load")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkIsNoContent(items: List<GradeStatisticsItem>, type: ViewType): Boolean {
|
private fun checkIsNoContent(
|
||||||
|
items: List<GradeStatisticsItem>,
|
||||||
|
type: GradeStatisticsItem.DataType
|
||||||
|
): Boolean {
|
||||||
return items.isEmpty() || when (type) {
|
return items.isEmpty() || when (type) {
|
||||||
ViewType.SEMESTER -> items.firstOrNull()?.semester?.amounts.orEmpty().sum() == 0
|
GradeStatisticsItem.DataType.SEMESTER -> {
|
||||||
ViewType.PARTIAL -> items.firstOrNull()?.partial?.classAmounts.orEmpty().sum() == 0
|
items.firstOrNull()?.semester?.amounts.orEmpty().sum() == 0
|
||||||
ViewType.POINTS -> items.firstOrNull()?.points?.let { points ->
|
|
||||||
points.student == .0 && points.others == .0
|
|
||||||
} ?: false
|
|
||||||
}
|
}
|
||||||
|
GradeStatisticsItem.DataType.PARTIAL -> {
|
||||||
|
items.firstOrNull()?.partial?.classAmounts.orEmpty().sum() == 0
|
||||||
|
}
|
||||||
|
GradeStatisticsItem.DataType.POINTS -> {
|
||||||
|
items.firstOrNull()?.points?.let { points -> points.student == .0 && points.others == .0 } ?: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun clearDataInView() {
|
||||||
|
view?.updateData(
|
||||||
|
emptyList(),
|
||||||
|
preferencesRepository.gradeColorTheme,
|
||||||
|
preferencesRepository.showAllSubjectsOnStatisticsList
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showErrorViewOnError(message: String, error: Throwable) {
|
private fun showErrorViewOnError(message: String, error: Throwable) {
|
||||||
|
@ -7,13 +7,17 @@ interface GradeStatisticsView : BaseView {
|
|||||||
|
|
||||||
val isViewEmpty: Boolean
|
val isViewEmpty: Boolean
|
||||||
|
|
||||||
val currentType: ViewType
|
val currentType: GradeStatisticsItem.DataType
|
||||||
|
|
||||||
fun initView()
|
fun initView()
|
||||||
|
|
||||||
fun updateSubjects(data: ArrayList<String>)
|
fun updateSubjects(data: ArrayList<String>)
|
||||||
|
|
||||||
fun updateData(items: List<GradeStatisticsItem>, theme: String, showAllSubjectsOnStatisticsList: Boolean)
|
fun updateData(
|
||||||
|
newItems: List<GradeStatisticsItem>,
|
||||||
|
newTheme: String,
|
||||||
|
showAllSubjectsOnStatisticsList: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
fun showSubjects(show: Boolean)
|
fun showSubjects(show: Boolean)
|
||||||
|
|
||||||
@ -25,8 +29,6 @@ interface GradeStatisticsView : BaseView {
|
|||||||
|
|
||||||
fun resetView()
|
fun resetView()
|
||||||
|
|
||||||
fun showContent(show: Boolean)
|
|
||||||
|
|
||||||
fun showEmpty(show: Boolean)
|
fun showEmpty(show: Boolean)
|
||||||
|
|
||||||
fun showErrorView(show: Boolean)
|
fun showErrorView(show: Boolean)
|
||||||
|
@ -3,5 +3,6 @@ package io.github.wulkanowy.ui.modules.grade.statistics
|
|||||||
enum class ViewType(val id: Int) {
|
enum class ViewType(val id: Int) {
|
||||||
SEMESTER(1),
|
SEMESTER(1),
|
||||||
PARTIAL(2),
|
PARTIAL(2),
|
||||||
POINTS(3)
|
POINTS(3),
|
||||||
|
HEADER(4)
|
||||||
}
|
}
|
||||||
|
@ -3,8 +3,7 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical">
|
||||||
tools:context=".ui.modules.grade.statistics.GradeStatisticsFragment">
|
|
||||||
|
|
||||||
<io.github.wulkanowy.ui.widgets.MaterialLinearLayout
|
<io.github.wulkanowy.ui.widgets.MaterialLinearLayout
|
||||||
android:id="@+id/gradeStatisticsSubjectsContainer"
|
android:id="@+id/gradeStatisticsSubjectsContainer"
|
||||||
@ -12,7 +11,8 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="?android:windowBackground"
|
android:background="?android:windowBackground"
|
||||||
android:padding="5dp"
|
android:padding="5dp"
|
||||||
android:visibility="gone"
|
android:visibility="visible"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:ignore="UnusedAttribute"
|
tools:ignore="UnusedAttribute"
|
||||||
tools:listitem="@layout/item_attendance_summary"
|
tools:listitem="@layout/item_attendance_summary"
|
||||||
tools:visibility="visible">
|
tools:visibility="visible">
|
||||||
@ -34,67 +34,12 @@
|
|||||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||||
android:id="@+id/gradeStatisticsSwipe"
|
android:id="@+id/gradeStatisticsSwipe"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
|
||||||
android:id="@+id/gradeStatisticsScroll"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:fillViewport="true">
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<HorizontalScrollView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_gravity="center">
|
|
||||||
|
|
||||||
<RadioGroup
|
|
||||||
android:id="@+id/gradeStatisticsTypeSwitch"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:paddingStart="16dp"
|
|
||||||
android:paddingTop="5dp"
|
|
||||||
android:paddingEnd="16dp">
|
|
||||||
|
|
||||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
|
||||||
android:id="@+id/gradeStatisticsTypePartial"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:checked="true"
|
|
||||||
android:tag="partial"
|
|
||||||
android:text="@string/grade_statistics_partial" />
|
|
||||||
|
|
||||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
|
||||||
android:id="@+id/gradeStatisticsTypeSemester"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:tag="annual"
|
|
||||||
android:text="@string/grade_statistics_semester" />
|
|
||||||
|
|
||||||
<com.google.android.material.radiobutton.MaterialRadioButton
|
|
||||||
android:id="@+id/gradeStatisticsTypePoints"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:tag="points"
|
|
||||||
android:text="@string/grade_statistics_points" />
|
|
||||||
</RadioGroup>
|
|
||||||
</HorizontalScrollView>
|
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/gradeStatisticsRecycler"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
tools:listitem="@layout/item_grade_statistics_pie" />
|
|
||||||
|
|
||||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||||
android:id="@+id/gradeStatisticsProgress"
|
android:id="@+id/gradeStatisticsProgress"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
@ -103,6 +48,12 @@
|
|||||||
android:indeterminate="true"
|
android:indeterminate="true"
|
||||||
tools:visibility="gone" />
|
tools:visibility="gone" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/gradeStatisticsRecycler"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:listitem="@layout/item_grade_statistics_pie" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/gradeStatisticsEmpty"
|
android:id="@+id/gradeStatisticsEmpty"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -128,7 +79,6 @@
|
|||||||
android:textSize="20sp" />
|
android:textSize="20sp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/gradeStatisticsError"
|
android:id="@+id/gradeStatisticsError"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -180,7 +130,5 @@
|
|||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
</LinearLayout>
|
|
||||||
</androidx.core.widget.NestedScrollView>
|
|
||||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
47
app/src/main/res/layout/item_grade_statistics_header.xml
Normal file
47
app/src/main/res/layout/item_grade_statistics_header.xml
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<HorizontalScrollView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent">
|
||||||
|
|
||||||
|
<RadioGroup
|
||||||
|
android:id="@+id/gradeStatisticsTypeSwitch"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingTop="5dp"
|
||||||
|
android:paddingEnd="16dp">
|
||||||
|
|
||||||
|
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||||
|
android:id="@+id/gradeStatisticsTypePartial"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:checked="true"
|
||||||
|
android:tag="partial"
|
||||||
|
android:text="@string/grade_statistics_partial" />
|
||||||
|
|
||||||
|
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||||
|
android:id="@+id/gradeStatisticsTypeSemester"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:tag="annual"
|
||||||
|
android:text="@string/grade_statistics_semester" />
|
||||||
|
|
||||||
|
<com.google.android.material.radiobutton.MaterialRadioButton
|
||||||
|
android:id="@+id/gradeStatisticsTypePoints"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:tag="points"
|
||||||
|
android:text="@string/grade_statistics_points" />
|
||||||
|
</RadioGroup>
|
||||||
|
</HorizontalScrollView>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
Loading…
x
Reference in New Issue
Block a user