forked from github/wulkanowy-mirror
Show list of charts in grade statistics (#689)
This commit is contained in:
parent
e61c2bced8
commit
be057dd63c
@ -54,8 +54,10 @@ class GradeStatisticsLocalTest {
|
|||||||
))
|
))
|
||||||
|
|
||||||
val stats = gradeStatisticsLocal.getGradesStatistics(getSemester(), false, "Wszystkie").blockingGet()
|
val stats = gradeStatisticsLocal.getGradesStatistics(getSemester(), false, "Wszystkie").blockingGet()
|
||||||
assertEquals(1, stats.size)
|
assertEquals(3, stats.size)
|
||||||
assertEquals(stats[0].subject, "Wszystkie")
|
assertEquals(stats[0].subject, "Wszystkie")
|
||||||
|
assertEquals(stats[1].subject, "Matematyka")
|
||||||
|
assertEquals(stats[2].subject, "Chemia")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -67,7 +69,7 @@ class GradeStatisticsLocalTest {
|
|||||||
))
|
))
|
||||||
|
|
||||||
val stats = gradeStatisticsLocal.getGradesPointsStatistics(getSemester(), "Matematyka").blockingGet()
|
val stats = gradeStatisticsLocal.getGradesPointsStatistics(getSemester(), "Matematyka").blockingGet()
|
||||||
with(stats) {
|
with(stats[0]) {
|
||||||
assertEquals(subject, "Matematyka")
|
assertEquals(subject, "Matematyka")
|
||||||
assertEquals(others, 5.0)
|
assertEquals(others, 5.0)
|
||||||
assertEquals(student, 5.0)
|
assertEquals(student, 5.0)
|
||||||
|
@ -11,7 +11,7 @@ import javax.inject.Singleton
|
|||||||
interface GradePointsStatisticsDao : BaseDao<GradePointsStatistics> {
|
interface GradePointsStatisticsDao : BaseDao<GradePointsStatistics> {
|
||||||
|
|
||||||
@Query("SELECT * FROM GradesPointsStatistics WHERE student_id = :studentId AND semester_id = :semesterId AND subject = :subjectName")
|
@Query("SELECT * FROM GradesPointsStatistics WHERE student_id = :studentId AND semester_id = :semesterId AND subject = :subjectName")
|
||||||
fun loadSubject(semesterId: Int, studentId: Int, subjectName: String): Maybe<GradePointsStatistics>
|
fun loadSubject(semesterId: Int, studentId: Int, subjectName: String): Maybe<List<GradePointsStatistics>>
|
||||||
|
|
||||||
@Query("SELECT * FROM GradesPointsStatistics WHERE student_id = :studentId AND semester_id = :semesterId")
|
@Query("SELECT * FROM GradesPointsStatistics WHERE student_id = :studentId AND semester_id = :semesterId")
|
||||||
fun loadAll(semesterId: Int, studentId: Int): Maybe<List<GradePointsStatistics>>
|
fun loadAll(semesterId: Int, studentId: Int): Maybe<List<GradePointsStatistics>>
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
package io.github.wulkanowy.data.pojos
|
||||||
|
|
||||||
|
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
||||||
|
import io.github.wulkanowy.data.db.entities.GradeStatistics
|
||||||
|
import io.github.wulkanowy.ui.modules.grade.statistics.ViewType
|
||||||
|
|
||||||
|
data class GradeStatisticsItem(
|
||||||
|
|
||||||
|
val type: ViewType,
|
||||||
|
|
||||||
|
val partial: List<GradeStatistics>,
|
||||||
|
|
||||||
|
val points: GradePointsStatistics?
|
||||||
|
)
|
@ -5,7 +5,6 @@ import io.github.wulkanowy.data.db.dao.GradeStatisticsDao
|
|||||||
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
||||||
import io.github.wulkanowy.data.db.entities.GradeStatistics
|
import io.github.wulkanowy.data.db.entities.GradeStatistics
|
||||||
import io.github.wulkanowy.data.db.entities.Semester
|
import io.github.wulkanowy.data.db.entities.Semester
|
||||||
import io.github.wulkanowy.utils.roundToDecimalPlaces
|
|
||||||
import io.reactivex.Maybe
|
import io.reactivex.Maybe
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
@ -30,23 +29,17 @@ class GradeStatisticsLocal @Inject constructor(
|
|||||||
list.groupBy { it.grade }.map {
|
list.groupBy { it.grade }.map {
|
||||||
GradeStatistics(semester.studentId, semester.semesterId, subjectName, it.key,
|
GradeStatistics(semester.studentId, semester.semesterId, subjectName, it.key,
|
||||||
it.value.fold(0) { acc, e -> acc + e.amount }, false)
|
it.value.fold(0) { acc, e -> acc + e.amount }, false)
|
||||||
}
|
} + list
|
||||||
}
|
}
|
||||||
else -> gradeStatisticsDb.loadSubject(semester.semesterId, semester.studentId, subjectName, isSemester)
|
else -> gradeStatisticsDb.loadSubject(semester.semesterId, semester.studentId, subjectName, isSemester)
|
||||||
}.filter { it.isNotEmpty() }
|
}.filter { it.isNotEmpty() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getGradesPointsStatistics(semester: Semester, subjectName: String): Maybe<GradePointsStatistics> {
|
fun getGradesPointsStatistics(semester: Semester, subjectName: String): Maybe<List<GradePointsStatistics>> {
|
||||||
return when (subjectName) {
|
return when (subjectName) {
|
||||||
"Wszystkie" -> gradePointsStatisticsDb.loadAll(semester.semesterId, semester.studentId).flatMap { list ->
|
"Wszystkie" -> gradePointsStatisticsDb.loadAll(semester.semesterId, semester.studentId)
|
||||||
if (list.isEmpty()) return@flatMap Maybe.empty<GradePointsStatistics>()
|
|
||||||
Maybe.just(GradePointsStatistics(semester.studentId, semester.semesterId, subjectName,
|
|
||||||
(list.fold(.0) { acc, e -> acc + e.others } / list.size).roundToDecimalPlaces(2),
|
|
||||||
(list.fold(.0) { acc, e -> acc + e.student } / list.size).roundToDecimalPlaces(2)
|
|
||||||
))
|
|
||||||
}
|
|
||||||
else -> gradePointsStatisticsDb.loadSubject(semester.semesterId, semester.studentId, subjectName)
|
else -> gradePointsStatisticsDb.loadSubject(semester.semesterId, semester.studentId, subjectName)
|
||||||
}
|
}.filter { it.isNotEmpty() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun saveGradesStatistics(gradesStatistics: List<GradeStatistics>) {
|
fun saveGradesStatistics(gradesStatistics: List<GradeStatistics>) {
|
||||||
|
@ -5,8 +5,9 @@ import com.github.pwittchen.reactivenetwork.library.rx2.internet.observing.Inter
|
|||||||
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
||||||
import io.github.wulkanowy.data.db.entities.GradeStatistics
|
import io.github.wulkanowy.data.db.entities.GradeStatistics
|
||||||
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.ui.modules.grade.statistics.ViewType
|
||||||
import io.github.wulkanowy.utils.uniqueSubtract
|
import io.github.wulkanowy.utils.uniqueSubtract
|
||||||
import io.reactivex.Maybe
|
|
||||||
import io.reactivex.Single
|
import io.reactivex.Single
|
||||||
import java.net.UnknownHostException
|
import java.net.UnknownHostException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -19,8 +20,8 @@ class GradeStatisticsRepository @Inject constructor(
|
|||||||
private val remote: GradeStatisticsRemote
|
private val remote: GradeStatisticsRemote
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun getGradesStatistics(semester: Semester, subjectName: String, isSemester: Boolean, forceRefresh: Boolean = false): Single<List<GradeStatistics>> {
|
fun getGradesStatistics(semester: Semester, subjectName: String, isSemester: Boolean, forceRefresh: Boolean = false): Single<List<GradeStatisticsItem>> {
|
||||||
return local.getGradesStatistics(semester, isSemester, subjectName).filter { !forceRefresh }
|
return local.getGradesStatistics(semester, isSemester, subjectName).map { it.mapToStatisticItems() }.filter { !forceRefresh }
|
||||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||||
.flatMap {
|
.flatMap {
|
||||||
if (it) remote.getGradeStatistics(semester, isSemester)
|
if (it) remote.getGradeStatistics(semester, isSemester)
|
||||||
@ -31,21 +32,43 @@ class GradeStatisticsRepository @Inject constructor(
|
|||||||
local.deleteGradesStatistics(old.uniqueSubtract(new))
|
local.deleteGradesStatistics(old.uniqueSubtract(new))
|
||||||
local.saveGradesStatistics(new.uniqueSubtract(old))
|
local.saveGradesStatistics(new.uniqueSubtract(old))
|
||||||
}
|
}
|
||||||
}.flatMap { local.getGradesStatistics(semester, isSemester, subjectName).toSingle(emptyList()) })
|
}.flatMap { local.getGradesStatistics(semester, isSemester, subjectName).map { it.mapToStatisticItems() }.toSingle(emptyList()) })
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getGradesPointsStatistics(semester: Semester, subjectName: String, forceRefresh: Boolean): Maybe<GradePointsStatistics> {
|
fun getGradesPointsStatistics(semester: Semester, subjectName: String, forceRefresh: Boolean): Single<List<GradeStatisticsItem>> {
|
||||||
return local.getGradesPointsStatistics(semester, subjectName).filter { !forceRefresh }
|
return local.getGradesPointsStatistics(semester, subjectName).map { it.mapToStatisticsItem() }.filter { !forceRefresh }
|
||||||
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
.switchIfEmpty(ReactiveNetwork.checkInternetConnectivity(settings)
|
||||||
.flatMapMaybe {
|
.flatMap {
|
||||||
if (it) remote.getGradePointsStatistics(semester).toMaybe()
|
if (it) remote.getGradePointsStatistics(semester)
|
||||||
else Maybe.error(UnknownHostException())
|
else Single.error(UnknownHostException())
|
||||||
}.flatMap { new ->
|
}.flatMap { new ->
|
||||||
local.getGradesPointsStatistics(semester).defaultIfEmpty(emptyList())
|
local.getGradesPointsStatistics(semester).toSingle(emptyList())
|
||||||
.doOnSuccess { old ->
|
.doOnSuccess { old ->
|
||||||
local.deleteGradesPointsStatistics(old.uniqueSubtract(new))
|
local.deleteGradesPointsStatistics(old.uniqueSubtract(new))
|
||||||
local.saveGradesPointsStatistics(new.uniqueSubtract(old))
|
local.saveGradesPointsStatistics(new.uniqueSubtract(old))
|
||||||
}
|
}
|
||||||
}.flatMap { local.getGradesPointsStatistics(semester, subjectName) })
|
}.flatMap { local.getGradesPointsStatistics(semester, subjectName).map { it.mapToStatisticsItem() }.toSingle(emptyList()) })
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun List<GradeStatistics>.mapToStatisticItems(): List<GradeStatisticsItem> {
|
||||||
|
return groupBy { it.subject }.map {
|
||||||
|
GradeStatisticsItem(
|
||||||
|
type = ViewType.PARTIAL,
|
||||||
|
partial = it.value
|
||||||
|
.sortedByDescending { item -> item.grade }
|
||||||
|
.filter { item -> item.amount != 0 },
|
||||||
|
points = null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun List<GradePointsStatistics>.mapToStatisticsItem(): List<GradeStatisticsItem> {
|
||||||
|
return map {
|
||||||
|
GradeStatisticsItem(
|
||||||
|
type = ViewType.POINTS,
|
||||||
|
partial = emptyList(),
|
||||||
|
points = it
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,209 @@
|
|||||||
|
package io.github.wulkanowy.ui.modules.grade.statistics
|
||||||
|
|
||||||
|
import android.graphics.Color
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.View.GONE
|
||||||
|
import android.view.View.VISIBLE
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.github.mikephil.charting.components.Legend
|
||||||
|
import com.github.mikephil.charting.components.LegendEntry
|
||||||
|
import com.github.mikephil.charting.data.BarData
|
||||||
|
import com.github.mikephil.charting.data.BarDataSet
|
||||||
|
import com.github.mikephil.charting.data.BarEntry
|
||||||
|
import com.github.mikephil.charting.data.PieData
|
||||||
|
import com.github.mikephil.charting.data.PieDataSet
|
||||||
|
import com.github.mikephil.charting.data.PieEntry
|
||||||
|
import com.github.mikephil.charting.formatter.ValueFormatter
|
||||||
|
import io.github.wulkanowy.R
|
||||||
|
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
||||||
|
import io.github.wulkanowy.data.db.entities.GradeStatistics
|
||||||
|
import io.github.wulkanowy.data.pojos.GradeStatisticsItem
|
||||||
|
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||||
|
import kotlinx.android.synthetic.main.item_grade_statistics_bar.view.*
|
||||||
|
import kotlinx.android.synthetic.main.item_grade_statistics_pie.view.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class GradeStatisticsAdapter @Inject constructor() :
|
||||||
|
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
|
||||||
|
|
||||||
|
var items = emptyList<GradeStatisticsItem>()
|
||||||
|
|
||||||
|
var theme: String = "vulcan"
|
||||||
|
|
||||||
|
private val vulcanGradeColors = listOf(
|
||||||
|
6 to R.color.grade_vulcan_six,
|
||||||
|
5 to R.color.grade_vulcan_five,
|
||||||
|
4 to R.color.grade_vulcan_four,
|
||||||
|
3 to R.color.grade_vulcan_three,
|
||||||
|
2 to R.color.grade_vulcan_two,
|
||||||
|
1 to R.color.grade_vulcan_one
|
||||||
|
)
|
||||||
|
|
||||||
|
private val materialGradeColors = listOf(
|
||||||
|
6 to R.color.grade_material_six,
|
||||||
|
5 to R.color.grade_material_five,
|
||||||
|
4 to R.color.grade_material_four,
|
||||||
|
3 to R.color.grade_material_three,
|
||||||
|
2 to R.color.grade_material_two,
|
||||||
|
1 to R.color.grade_material_one
|
||||||
|
)
|
||||||
|
|
||||||
|
private val gradePointsColors = listOf(
|
||||||
|
Color.parseColor("#37c69c"),
|
||||||
|
Color.parseColor("#d8b12a")
|
||||||
|
)
|
||||||
|
|
||||||
|
private val gradeLabels = listOf(
|
||||||
|
"6, 6-", "5, 5-, 5+", "4, 4-, 4+", "3, 3-, 3+", "2, 2-, 2+", "1, 1+"
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun getItemCount() = items.size
|
||||||
|
|
||||||
|
override fun getItemViewType(position: Int): Int {
|
||||||
|
return when (items[position].type) {
|
||||||
|
ViewType.SEMESTER, ViewType.PARTIAL -> R.layout.item_grade_statistics_pie
|
||||||
|
ViewType.POINTS -> R.layout.item_grade_statistics_bar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
|
||||||
|
val viewHolder = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
|
||||||
|
return when (viewType) {
|
||||||
|
R.layout.item_grade_statistics_bar -> GradeStatisticsBar(viewHolder)
|
||||||
|
else -> GradeStatisticsPie(viewHolder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||||
|
when (holder) {
|
||||||
|
is GradeStatisticsPie -> bindPieChart(holder, items[position].partial)
|
||||||
|
is GradeStatisticsBar -> bindBarChart(holder, items[position].points!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun bindPieChart(holder: GradeStatisticsPie, partials: List<GradeStatistics>) {
|
||||||
|
with(holder.view.gradeStatisticsPieTitle) {
|
||||||
|
text = partials.firstOrNull()?.subject
|
||||||
|
visibility = if (items.size == 1) GONE else VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
val gradeColors = when (theme) {
|
||||||
|
"vulcan" -> vulcanGradeColors
|
||||||
|
else -> materialGradeColors
|
||||||
|
}
|
||||||
|
|
||||||
|
val dataset = PieDataSet(partials.map {
|
||||||
|
PieEntry(it.amount.toFloat(), it.grade.toString())
|
||||||
|
}, "Legenda")
|
||||||
|
|
||||||
|
with(dataset) {
|
||||||
|
valueTextSize = 12f
|
||||||
|
sliceSpace = 1f
|
||||||
|
valueTextColor = Color.WHITE
|
||||||
|
setColors(partials.map {
|
||||||
|
gradeColors.single { color -> color.first == it.grade }.second
|
||||||
|
}.toIntArray(), holder.view.context)
|
||||||
|
}
|
||||||
|
|
||||||
|
with(holder.view.gradeStatisticsPie) {
|
||||||
|
setTouchEnabled(false)
|
||||||
|
if (partials.size == 1) animateXY(1000, 1000)
|
||||||
|
data = PieData(dataset).apply {
|
||||||
|
setValueFormatter(object : ValueFormatter() {
|
||||||
|
override fun getPieLabel(value: Float, pieEntry: PieEntry): String {
|
||||||
|
return resources.getQuantityString(R.plurals.grade_number_item, value.toInt(), value.toInt())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
with(legend) {
|
||||||
|
textColor = context.getThemeAttrColor(android.R.attr.textColorPrimary)
|
||||||
|
setCustom(gradeLabels.mapIndexed { i, it ->
|
||||||
|
LegendEntry().apply {
|
||||||
|
label = it
|
||||||
|
formColor = ContextCompat.getColor(context, gradeColors[i].second)
|
||||||
|
form = Legend.LegendForm.SQUARE
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
minAngleForSlices = 25f
|
||||||
|
description.isEnabled = false
|
||||||
|
centerText = partials.fold(0) { acc, it -> acc + it.amount }
|
||||||
|
.let { resources.getQuantityString(R.plurals.grade_number_item, it, it) }
|
||||||
|
|
||||||
|
setHoleColor(context.getThemeAttrColor(android.R.attr.windowBackground))
|
||||||
|
setCenterTextColor(context.getThemeAttrColor(android.R.attr.textColorPrimary))
|
||||||
|
invalidate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun bindBarChart(holder: GradeStatisticsBar, points: GradePointsStatistics) {
|
||||||
|
with(holder.view.gradeStatisticsBarTitle) {
|
||||||
|
text = points.subject
|
||||||
|
visibility = if (items.size == 1) GONE else VISIBLE
|
||||||
|
}
|
||||||
|
|
||||||
|
val dataset = BarDataSet(listOf(
|
||||||
|
BarEntry(1f, points.others.toFloat()),
|
||||||
|
BarEntry(2f, points.student.toFloat())
|
||||||
|
), "Legenda")
|
||||||
|
|
||||||
|
with(dataset) {
|
||||||
|
valueTextSize = 12f
|
||||||
|
valueTextColor = holder.view.context.getThemeAttrColor(android.R.attr.textColorPrimary)
|
||||||
|
valueFormatter = object : ValueFormatter() {
|
||||||
|
override fun getBarLabel(barEntry: BarEntry) = "${barEntry.y}%"
|
||||||
|
}
|
||||||
|
colors = gradePointsColors
|
||||||
|
}
|
||||||
|
|
||||||
|
with(holder.view.gradeStatisticsBar) {
|
||||||
|
setTouchEnabled(false)
|
||||||
|
if (items.size == 1) animateXY(1000, 1000)
|
||||||
|
data = BarData(dataset).apply {
|
||||||
|
barWidth = 0.5f
|
||||||
|
setFitBars(true)
|
||||||
|
}
|
||||||
|
legend.setCustom(listOf(
|
||||||
|
LegendEntry().apply {
|
||||||
|
label = "Średnia klasy"
|
||||||
|
formColor = gradePointsColors[0]
|
||||||
|
form = Legend.LegendForm.SQUARE
|
||||||
|
},
|
||||||
|
LegendEntry().apply {
|
||||||
|
label = "Uczeń"
|
||||||
|
formColor = gradePointsColors[1]
|
||||||
|
form = Legend.LegendForm.SQUARE
|
||||||
|
}
|
||||||
|
))
|
||||||
|
legend.textColor = context.getThemeAttrColor(android.R.attr.textColorPrimary)
|
||||||
|
|
||||||
|
description.isEnabled = false
|
||||||
|
|
||||||
|
holder.view.context.getThemeAttrColor(android.R.attr.textColorPrimary).let {
|
||||||
|
axisLeft.textColor = it
|
||||||
|
axisRight.textColor = it
|
||||||
|
}
|
||||||
|
xAxis.setDrawLabels(false)
|
||||||
|
xAxis.setDrawGridLines(false)
|
||||||
|
with(axisLeft) {
|
||||||
|
axisMinimum = 0f
|
||||||
|
axisMaximum = 100f
|
||||||
|
labelCount = 11
|
||||||
|
}
|
||||||
|
with(axisRight) {
|
||||||
|
axisMinimum = 0f
|
||||||
|
axisMaximum = 100f
|
||||||
|
labelCount = 11
|
||||||
|
}
|
||||||
|
invalidate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GradeStatisticsPie(val view: View) : RecyclerView.ViewHolder(view)
|
||||||
|
|
||||||
|
class GradeStatisticsBar(val view: View) : RecyclerView.ViewHolder(view)
|
||||||
|
}
|
@ -1,31 +1,18 @@
|
|||||||
package io.github.wulkanowy.ui.modules.grade.statistics
|
package io.github.wulkanowy.ui.modules.grade.statistics
|
||||||
|
|
||||||
import android.graphics.Color
|
|
||||||
import android.graphics.Color.WHITE
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.ArrayAdapter
|
import android.widget.ArrayAdapter
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.github.mikephil.charting.components.Legend
|
|
||||||
import com.github.mikephil.charting.components.LegendEntry
|
|
||||||
import com.github.mikephil.charting.data.BarData
|
|
||||||
import com.github.mikephil.charting.data.BarDataSet
|
|
||||||
import com.github.mikephil.charting.data.BarEntry
|
|
||||||
import com.github.mikephil.charting.data.PieData
|
|
||||||
import com.github.mikephil.charting.data.PieDataSet
|
|
||||||
import com.github.mikephil.charting.data.PieEntry
|
|
||||||
import com.github.mikephil.charting.formatter.ValueFormatter
|
|
||||||
import io.github.wulkanowy.R
|
import io.github.wulkanowy.R
|
||||||
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
import io.github.wulkanowy.data.pojos.GradeStatisticsItem
|
||||||
import io.github.wulkanowy.data.db.entities.GradeStatistics
|
|
||||||
import io.github.wulkanowy.ui.base.BaseFragment
|
import io.github.wulkanowy.ui.base.BaseFragment
|
||||||
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
import io.github.wulkanowy.ui.modules.grade.GradeFragment
|
||||||
import io.github.wulkanowy.ui.modules.grade.GradeView
|
import io.github.wulkanowy.ui.modules.grade.GradeView
|
||||||
import io.github.wulkanowy.utils.dpToPx
|
import io.github.wulkanowy.utils.dpToPx
|
||||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
|
||||||
import io.github.wulkanowy.utils.setOnItemSelectedListener
|
import io.github.wulkanowy.utils.setOnItemSelectedListener
|
||||||
import kotlinx.android.synthetic.main.fragment_grade_statistics.*
|
import kotlinx.android.synthetic.main.fragment_grade_statistics.*
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -35,6 +22,9 @@ class GradeStatisticsFragment : BaseFragment(), GradeStatisticsView, GradeView.G
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var presenter: GradeStatisticsPresenter
|
lateinit var presenter: GradeStatisticsPresenter
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
lateinit var statisticsAdapter: GradeStatisticsAdapter
|
||||||
|
|
||||||
private lateinit var subjectsAdapter: ArrayAdapter<String>
|
private lateinit var subjectsAdapter: ArrayAdapter<String>
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -43,9 +33,7 @@ class GradeStatisticsFragment : BaseFragment(), GradeStatisticsView, GradeView.G
|
|||||||
fun newInstance() = GradeStatisticsFragment()
|
fun newInstance() = GradeStatisticsFragment()
|
||||||
}
|
}
|
||||||
|
|
||||||
override val isPieViewEmpty get() = gradeStatisticsChart.isEmpty
|
override val isViewEmpty get() = statisticsAdapter.items.isEmpty()
|
||||||
|
|
||||||
override val isBarViewEmpty get() = gradeStatisticsChartPoints.isEmpty
|
|
||||||
|
|
||||||
override val currentType
|
override val currentType
|
||||||
get() = when (gradeStatisticsTypeSwitch.checkedRadioButtonId) {
|
get() = when (gradeStatisticsTypeSwitch.checkedRadioButtonId) {
|
||||||
@ -54,35 +42,6 @@ class GradeStatisticsFragment : BaseFragment(), GradeStatisticsView, GradeView.G
|
|||||||
else -> ViewType.POINTS
|
else -> ViewType.POINTS
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var gradeColors: List<Pair<Int, Int>>
|
|
||||||
|
|
||||||
private val vulcanGradeColors = listOf(
|
|
||||||
6 to R.color.grade_vulcan_six,
|
|
||||||
5 to R.color.grade_vulcan_five,
|
|
||||||
4 to R.color.grade_vulcan_four,
|
|
||||||
3 to R.color.grade_vulcan_three,
|
|
||||||
2 to R.color.grade_vulcan_two,
|
|
||||||
1 to R.color.grade_vulcan_one
|
|
||||||
)
|
|
||||||
|
|
||||||
private val materialGradeColors = listOf(
|
|
||||||
6 to R.color.grade_material_six,
|
|
||||||
5 to R.color.grade_material_five,
|
|
||||||
4 to R.color.grade_material_four,
|
|
||||||
3 to R.color.grade_material_three,
|
|
||||||
2 to R.color.grade_material_two,
|
|
||||||
1 to R.color.grade_material_one
|
|
||||||
)
|
|
||||||
|
|
||||||
private val gradePointsColors = listOf(
|
|
||||||
Color.parseColor("#37c69c"),
|
|
||||||
Color.parseColor("#d8b12a")
|
|
||||||
)
|
|
||||||
|
|
||||||
private val gradeLabels = listOf(
|
|
||||||
"6, 6-", "5, 5-, 5+", "4, 4-, 4+", "3, 3-, 3+", "2, 2-, 2+", "1, 1+"
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
return inflater.inflate(R.layout.fragment_grade_statistics, container, false)
|
return inflater.inflate(R.layout.fragment_grade_statistics, container, false)
|
||||||
}
|
}
|
||||||
@ -94,31 +53,9 @@ class GradeStatisticsFragment : BaseFragment(), GradeStatisticsView, GradeView.G
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun initView() {
|
override fun initView() {
|
||||||
with(gradeStatisticsChart) {
|
with(gradeStatisticsRecycler) {
|
||||||
description.isEnabled = false
|
layoutManager = LinearLayoutManager(requireContext())
|
||||||
setHoleColor(context.getThemeAttrColor(android.R.attr.windowBackground))
|
adapter = statisticsAdapter
|
||||||
setCenterTextColor(context.getThemeAttrColor(android.R.attr.textColorPrimary))
|
|
||||||
animateXY(1000, 1000)
|
|
||||||
minAngleForSlices = 25f
|
|
||||||
legend.textColor = context.getThemeAttrColor(android.R.attr.textColorPrimary)
|
|
||||||
}
|
|
||||||
|
|
||||||
with(gradeStatisticsChartPoints) {
|
|
||||||
description.isEnabled = false
|
|
||||||
|
|
||||||
animateXY(1000, 1000)
|
|
||||||
legend.textColor = context.getThemeAttrColor(android.R.attr.textColorPrimary)
|
|
||||||
|
|
||||||
with(axisLeft) {
|
|
||||||
axisMinimum = 0f
|
|
||||||
axisMaximum = 100f
|
|
||||||
labelCount = 11
|
|
||||||
}
|
|
||||||
with(axisRight) {
|
|
||||||
axisMinimum = 0f
|
|
||||||
axisMaximum = 100f
|
|
||||||
labelCount = 11
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
subjectsAdapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, mutableListOf())
|
subjectsAdapter = ArrayAdapter(requireContext(), android.R.layout.simple_spinner_item, mutableListOf())
|
||||||
@ -144,86 +81,10 @@ class GradeStatisticsFragment : BaseFragment(), GradeStatisticsView, GradeView.G
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun updatePieData(items: List<GradeStatistics>, theme: String) {
|
override fun updateData(items: List<GradeStatisticsItem>, theme: String) {
|
||||||
gradeColors = when (theme) {
|
statisticsAdapter.theme = theme
|
||||||
"vulcan" -> vulcanGradeColors
|
statisticsAdapter.items = items
|
||||||
else -> materialGradeColors
|
statisticsAdapter.notifyDataSetChanged()
|
||||||
}
|
|
||||||
|
|
||||||
val dataset = PieDataSet(items.map {
|
|
||||||
PieEntry(it.amount.toFloat(), it.grade.toString())
|
|
||||||
}, "Legenda").apply {
|
|
||||||
valueTextSize = 12f
|
|
||||||
sliceSpace = 1f
|
|
||||||
valueTextColor = WHITE
|
|
||||||
setColors(items.map {
|
|
||||||
gradeColors.single { color -> color.first == it.grade }.second
|
|
||||||
}.toIntArray(), context)
|
|
||||||
}
|
|
||||||
|
|
||||||
with(gradeStatisticsChart) {
|
|
||||||
data = PieData(dataset).apply {
|
|
||||||
setTouchEnabled(false)
|
|
||||||
setValueFormatter(object : ValueFormatter() {
|
|
||||||
override fun getPieLabel(value: Float, pieEntry: PieEntry): String {
|
|
||||||
return resources.getQuantityString(R.plurals.grade_number_item, value.toInt(), value.toInt())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
centerText = items.fold(0) { acc, it -> acc + it.amount }
|
|
||||||
.let { resources.getQuantityString(R.plurals.grade_number_item, it, it) }
|
|
||||||
}
|
|
||||||
legend.apply {
|
|
||||||
setCustom(gradeLabels.mapIndexed { i, it ->
|
|
||||||
LegendEntry().apply {
|
|
||||||
label = it
|
|
||||||
formColor = ContextCompat.getColor(context, gradeColors[i].second)
|
|
||||||
form = Legend.LegendForm.SQUARE
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
invalidate()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun updateBarData(item: GradePointsStatistics) {
|
|
||||||
val dataset = BarDataSet(listOf(
|
|
||||||
BarEntry(1f, item.others.toFloat()),
|
|
||||||
BarEntry(2f, item.student.toFloat())
|
|
||||||
), "Legenda").apply {
|
|
||||||
valueTextSize = 12f
|
|
||||||
valueTextColor = requireContext().getThemeAttrColor(android.R.attr.textColorPrimary)
|
|
||||||
valueFormatter = object : ValueFormatter() {
|
|
||||||
override fun getBarLabel(barEntry: BarEntry) = "${barEntry.y}%"
|
|
||||||
}
|
|
||||||
colors = gradePointsColors
|
|
||||||
}
|
|
||||||
|
|
||||||
with(gradeStatisticsChartPoints) {
|
|
||||||
data = BarData(dataset).apply {
|
|
||||||
barWidth = 0.5f
|
|
||||||
setFitBars(true)
|
|
||||||
}
|
|
||||||
setTouchEnabled(false)
|
|
||||||
xAxis.setDrawLabels(false)
|
|
||||||
xAxis.setDrawGridLines(false)
|
|
||||||
requireContext().getThemeAttrColor(android.R.attr.textColorPrimary).let {
|
|
||||||
axisLeft.textColor = it
|
|
||||||
axisRight.textColor = it
|
|
||||||
}
|
|
||||||
legend.setCustom(listOf(
|
|
||||||
LegendEntry().apply {
|
|
||||||
label = "Średnia klasy"
|
|
||||||
formColor = gradePointsColors[0]
|
|
||||||
form = Legend.LegendForm.SQUARE
|
|
||||||
},
|
|
||||||
LegendEntry().apply {
|
|
||||||
label = "Uczeń"
|
|
||||||
formColor = gradePointsColors[1]
|
|
||||||
form = Legend.LegendForm.SQUARE
|
|
||||||
}
|
|
||||||
))
|
|
||||||
invalidate()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showSubjects(show: Boolean) {
|
override fun showSubjects(show: Boolean) {
|
||||||
@ -232,16 +93,15 @@ class GradeStatisticsFragment : BaseFragment(), GradeStatisticsView, GradeView.G
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun clearView() {
|
override fun clearView() {
|
||||||
gradeStatisticsChart.clear()
|
statisticsAdapter.items = emptyList()
|
||||||
gradeStatisticsChartPoints.clear()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showPieContent(show: Boolean) {
|
override fun resetView() {
|
||||||
gradeStatisticsChart.visibility = if (show) View.VISIBLE else View.GONE
|
gradeStatisticsScroll.scrollTo(0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showBarContent(show: Boolean) {
|
override fun showContent(show: Boolean) {
|
||||||
gradeStatisticsChartPoints.visibility = if (show) View.VISIBLE else View.GONE
|
gradeStatisticsRecycler.visibility = if (show) View.VISIBLE else View.GONE
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showEmpty(show: Boolean) {
|
override fun showEmpty(show: Boolean) {
|
||||||
@ -273,7 +133,7 @@ class GradeStatisticsFragment : BaseFragment(), GradeStatisticsView, GradeView.G
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onParentReselected() {
|
override fun onParentReselected() {
|
||||||
//
|
presenter.onParentViewReselected()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onParentChangeSemester() {
|
override fun onParentChangeSemester() {
|
||||||
|
@ -48,12 +48,19 @@ class GradeStatisticsPresenter @Inject constructor(
|
|||||||
loadDataByType(semesterId, currentSubjectName, currentType, forceRefresh)
|
loadDataByType(semesterId, currentSubjectName, currentType, forceRefresh)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun onParentViewReselected() {
|
||||||
|
view?.run {
|
||||||
|
if (!isViewEmpty) resetView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun onParentViewChangeSemester() {
|
fun onParentViewChangeSemester() {
|
||||||
view?.run {
|
view?.run {
|
||||||
showProgress(true)
|
showProgress(true)
|
||||||
enableSwipe(false)
|
enableSwipe(false)
|
||||||
showRefresh(false)
|
showRefresh(false)
|
||||||
showBarContent(false)
|
showContent(false)
|
||||||
showErrorView(false)
|
showErrorView(false)
|
||||||
showEmpty(false)
|
showEmpty(false)
|
||||||
clearView()
|
clearView()
|
||||||
@ -81,8 +88,7 @@ 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")
|
||||||
view?.run {
|
view?.run {
|
||||||
showBarContent(false)
|
showContent(false)
|
||||||
showPieContent(false)
|
|
||||||
showProgress(true)
|
showProgress(true)
|
||||||
enableSwipe(false)
|
enableSwipe(false)
|
||||||
showEmpty(false)
|
showEmpty(false)
|
||||||
@ -99,8 +105,7 @@ class GradeStatisticsPresenter @Inject constructor(
|
|||||||
Timber.i("Select grade stats semester: $type")
|
Timber.i("Select grade stats semester: $type")
|
||||||
disposable.clear()
|
disposable.clear()
|
||||||
view?.run {
|
view?.run {
|
||||||
showBarContent(false)
|
showContent(false)
|
||||||
showPieContent(false)
|
|
||||||
showProgress(true)
|
showProgress(true)
|
||||||
enableSwipe(false)
|
enableSwipe(false)
|
||||||
showEmpty(false)
|
showEmpty(false)
|
||||||
@ -135,20 +140,22 @@ class GradeStatisticsPresenter @Inject constructor(
|
|||||||
private fun loadDataByType(semesterId: Int, subjectName: String, type: ViewType, forceRefresh: Boolean = false) {
|
private fun loadDataByType(semesterId: Int, subjectName: String, type: ViewType, forceRefresh: Boolean = false) {
|
||||||
currentSubjectName = subjectName
|
currentSubjectName = subjectName
|
||||||
currentType = type
|
currentType = type
|
||||||
when (type) {
|
loadData(semesterId, subjectName, type, forceRefresh)
|
||||||
ViewType.SEMESTER -> loadData(semesterId, subjectName, true, forceRefresh)
|
|
||||||
ViewType.PARTIAL -> loadData(semesterId, subjectName, false, forceRefresh)
|
|
||||||
ViewType.POINTS -> loadPointsData(semesterId, subjectName, forceRefresh)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadData(semesterId: Int, subjectName: String, isSemester: Boolean, forceRefresh: Boolean = false) {
|
private fun loadData(semesterId: Int, subjectName: String, type: ViewType, forceRefresh: Boolean) {
|
||||||
Timber.i("Loading grade stats data started")
|
Timber.i("Loading grade stats data started")
|
||||||
disposable.add(studentRepository.getCurrentStudent()
|
disposable.add(studentRepository.getCurrentStudent()
|
||||||
.flatMap { semesterRepository.getSemesters(it) }
|
.flatMap { semesterRepository.getSemesters(it) }
|
||||||
.flatMap { gradeStatisticsRepository.getGradesStatistics(it.first { item -> item.semesterId == semesterId }, subjectName, isSemester, forceRefresh) }
|
.flatMap {
|
||||||
.map { list -> list.sortedByDescending { it.grade } }
|
val semester = it.first { item -> item.semesterId == semesterId }
|
||||||
.map { list -> list.filter { it.amount != 0 } }
|
|
||||||
|
when (type) {
|
||||||
|
ViewType.SEMESTER -> gradeStatisticsRepository.getGradesStatistics(semester, subjectName, true, forceRefresh)
|
||||||
|
ViewType.PARTIAL -> gradeStatisticsRepository.getGradesStatistics(semester, subjectName, false, forceRefresh)
|
||||||
|
ViewType.POINTS -> gradeStatisticsRepository.getGradesPointsStatistics(semester, subjectName, forceRefresh)
|
||||||
|
}
|
||||||
|
}
|
||||||
.subscribeOn(schedulers.backgroundThread)
|
.subscribeOn(schedulers.backgroundThread)
|
||||||
.observeOn(schedulers.mainThread)
|
.observeOn(schedulers.mainThread)
|
||||||
.doFinally {
|
.doFinally {
|
||||||
@ -163,10 +170,9 @@ class GradeStatisticsPresenter @Inject constructor(
|
|||||||
Timber.i("Loading grade stats result: Success")
|
Timber.i("Loading grade stats result: Success")
|
||||||
view?.run {
|
view?.run {
|
||||||
showEmpty(it.isEmpty())
|
showEmpty(it.isEmpty())
|
||||||
showBarContent(false)
|
showContent(it.isNotEmpty())
|
||||||
showPieContent(it.isNotEmpty())
|
|
||||||
showErrorView(false)
|
showErrorView(false)
|
||||||
updatePieData(it, preferencesRepository.gradeColorTheme)
|
updateData(it, preferencesRepository.gradeColorTheme)
|
||||||
}
|
}
|
||||||
analytics.logEvent("load_grade_statistics", "items" to it.size, "force_refresh" to forceRefresh)
|
analytics.logEvent("load_grade_statistics", "items" to it.size, "force_refresh" to forceRefresh)
|
||||||
}) {
|
}) {
|
||||||
@ -175,47 +181,9 @@ class GradeStatisticsPresenter @Inject constructor(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadPointsData(semesterId: Int, subjectName: String, forceRefresh: Boolean = false) {
|
|
||||||
Timber.i("Loading grade points stats data started")
|
|
||||||
disposable.add(studentRepository.getCurrentStudent()
|
|
||||||
.flatMap { semesterRepository.getSemesters(it) }
|
|
||||||
.flatMapMaybe { gradeStatisticsRepository.getGradesPointsStatistics(it.first { item -> item.semesterId == semesterId }, subjectName, forceRefresh) }
|
|
||||||
.subscribeOn(schedulers.backgroundThread)
|
|
||||||
.observeOn(schedulers.mainThread)
|
|
||||||
.doFinally {
|
|
||||||
view?.run {
|
|
||||||
showRefresh(false)
|
|
||||||
showProgress(false)
|
|
||||||
enableSwipe(true)
|
|
||||||
notifyParentDataLoaded(semesterId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.subscribe({
|
|
||||||
Timber.i("Loading grade points stats result: Success")
|
|
||||||
view?.run {
|
|
||||||
showEmpty(false)
|
|
||||||
showPieContent(false)
|
|
||||||
showBarContent(true)
|
|
||||||
showErrorView(false)
|
|
||||||
updateBarData(it)
|
|
||||||
}
|
|
||||||
analytics.logEvent("load_grade_points_statistics", "force_refresh" to forceRefresh)
|
|
||||||
}, {
|
|
||||||
Timber.e("Loading grade points stats result: An exception occurred")
|
|
||||||
errorHandler.dispatch(it)
|
|
||||||
}, {
|
|
||||||
Timber.d("Loading grade points stats result: No point stats found")
|
|
||||||
view?.run {
|
|
||||||
showBarContent(false)
|
|
||||||
showEmpty(true)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showErrorViewOnError(message: String, error: Throwable) {
|
private fun showErrorViewOnError(message: String, error: Throwable) {
|
||||||
view?.run {
|
view?.run {
|
||||||
if ((isBarViewEmpty && currentType == ViewType.POINTS) || (isPieViewEmpty) && currentType != ViewType.POINTS) {
|
if (isViewEmpty) {
|
||||||
lastError = error
|
lastError = error
|
||||||
setErrorDetails(message)
|
setErrorDetails(message)
|
||||||
showErrorView(true)
|
showErrorView(true)
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
package io.github.wulkanowy.ui.modules.grade.statistics
|
package io.github.wulkanowy.ui.modules.grade.statistics
|
||||||
|
|
||||||
import io.github.wulkanowy.data.db.entities.GradePointsStatistics
|
import io.github.wulkanowy.data.pojos.GradeStatisticsItem
|
||||||
import io.github.wulkanowy.data.db.entities.GradeStatistics
|
|
||||||
import io.github.wulkanowy.ui.base.BaseView
|
import io.github.wulkanowy.ui.base.BaseView
|
||||||
|
|
||||||
interface GradeStatisticsView : BaseView {
|
interface GradeStatisticsView : BaseView {
|
||||||
|
|
||||||
val isPieViewEmpty: Boolean
|
val isViewEmpty: Boolean
|
||||||
|
|
||||||
val isBarViewEmpty: Boolean
|
|
||||||
|
|
||||||
val currentType: ViewType
|
val currentType: ViewType
|
||||||
|
|
||||||
@ -16,9 +13,7 @@ interface GradeStatisticsView : BaseView {
|
|||||||
|
|
||||||
fun updateSubjects(data: ArrayList<String>)
|
fun updateSubjects(data: ArrayList<String>)
|
||||||
|
|
||||||
fun updatePieData(items: List<GradeStatistics>, theme: String)
|
fun updateData(items: List<GradeStatisticsItem>, theme: String)
|
||||||
|
|
||||||
fun updateBarData(item: GradePointsStatistics)
|
|
||||||
|
|
||||||
fun showSubjects(show: Boolean)
|
fun showSubjects(show: Boolean)
|
||||||
|
|
||||||
@ -28,9 +23,9 @@ interface GradeStatisticsView : BaseView {
|
|||||||
|
|
||||||
fun clearView()
|
fun clearView()
|
||||||
|
|
||||||
fun showPieContent(show: Boolean)
|
fun resetView()
|
||||||
|
|
||||||
fun showBarContent(show: Boolean)
|
fun showContent(show: Boolean)
|
||||||
|
|
||||||
fun showEmpty(show: Boolean)
|
fun showEmpty(show: Boolean)
|
||||||
|
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
package io.github.wulkanowy.utils
|
|
||||||
|
|
||||||
import kotlin.math.round
|
|
||||||
|
|
||||||
fun Double.roundToDecimalPlaces(places: Int = 2): Double {
|
|
||||||
return round(this * 10 * places) / (10 * places)
|
|
||||||
}
|
|
@ -37,6 +37,7 @@
|
|||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<androidx.core.widget.NestedScrollView
|
<androidx.core.widget.NestedScrollView
|
||||||
|
android:id="@+id/gradeStatisticsScroll"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:fillViewport="true">
|
android:fillViewport="true">
|
||||||
@ -90,25 +91,11 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
<com.github.mikephil.charting.charts.PieChart
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
android:id="@+id/gradeStatisticsChart"
|
android:id="@+id/gradeStatisticsRecycler"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:layout_margin="10dp"
|
tools:listitem="@layout/item_grade_statistics_pie" />
|
||||||
android:background="?android:windowBackground"
|
|
||||||
android:minHeight="400dp"
|
|
||||||
android:visibility="gone"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
<com.github.mikephil.charting.charts.BarChart
|
|
||||||
android:id="@+id/gradeStatisticsChartPoints"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:layout_margin="10dp"
|
|
||||||
android:background="?android:windowBackground"
|
|
||||||
android:minHeight="400dp"
|
|
||||||
android:visibility="gone"
|
|
||||||
tools:visibility="visible" />
|
|
||||||
|
|
||||||
<me.zhanghai.android.materialprogressbar.MaterialProgressBar
|
<me.zhanghai.android.materialprogressbar.MaterialProgressBar
|
||||||
android:id="@+id/gradeStatisticsProgress"
|
android:id="@+id/gradeStatisticsProgress"
|
||||||
|
27
app/src/main/res/layout/item_grade_statistics_bar.xml
Normal file
27
app/src/main/res/layout/item_grade_statistics_bar.xml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/gradeStatisticsBarTitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?colorControlHighlight"
|
||||||
|
android:paddingLeft="20dp"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:paddingRight="20dp"
|
||||||
|
android:paddingBottom="10dp"
|
||||||
|
android:textSize="18sp"
|
||||||
|
tools:text="Matematyka" />
|
||||||
|
|
||||||
|
<com.github.mikephil.charting.charts.BarChart
|
||||||
|
android:id="@+id/gradeStatisticsBar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="400dp"
|
||||||
|
android:layout_margin="10dp"
|
||||||
|
android:background="?android:windowBackground"
|
||||||
|
tools:context=".ui.modules.grade.statistics.GradeStatisticsAdapter" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
27
app/src/main/res/layout/item_grade_statistics_pie.xml
Normal file
27
app/src/main/res/layout/item_grade_statistics_pie.xml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/gradeStatisticsPieTitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?colorControlHighlight"
|
||||||
|
android:paddingLeft="20dp"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:paddingRight="20dp"
|
||||||
|
android:paddingBottom="10dp"
|
||||||
|
android:textSize="18sp"
|
||||||
|
tools:text="Matematyka" />
|
||||||
|
|
||||||
|
<com.github.mikephil.charting.charts.PieChart
|
||||||
|
android:id="@+id/gradeStatisticsPie"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="400dp"
|
||||||
|
android:layout_margin="10dp"
|
||||||
|
android:background="?android:windowBackground"
|
||||||
|
tools:context=".ui.modules.grade.statistics.GradeStatisticsAdapter" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
Loading…
x
Reference in New Issue
Block a user