From 945d5886ea6f67f9a9e6d0093dc4bf5368490823 Mon Sep 17 00:00:00 2001
From: rebelonion <87634197+rebelonion@users.noreply.github.com>
Date: Sun, 3 Mar 2024 01:25:45 -0600
Subject: [PATCH] feat: genre graph
---
.../ani/dantotsu/profile/StatsFragment.kt | 131 ++++++++++++++++--
1 file changed, 123 insertions(+), 8 deletions(-)
diff --git a/app/src/main/java/ani/dantotsu/profile/StatsFragment.kt b/app/src/main/java/ani/dantotsu/profile/StatsFragment.kt
index f3007300..7e9791ae 100644
--- a/app/src/main/java/ani/dantotsu/profile/StatsFragment.kt
+++ b/app/src/main/java/ani/dantotsu/profile/StatsFragment.kt
@@ -22,11 +22,14 @@ import com.github.aachartmodel.aainfographics.aachartcreator.AADataElement
import com.github.aachartmodel.aainfographics.aachartcreator.AAOptions
import com.github.aachartmodel.aainfographics.aachartcreator.AASeriesElement
import com.github.aachartmodel.aainfographics.aachartcreator.aa_toAAOptions
+import com.github.aachartmodel.aainfographics.aaoptionsmodel.AAArea
+import com.github.aachartmodel.aainfographics.aaoptionsmodel.AAChart
import com.github.aachartmodel.aainfographics.aaoptionsmodel.AADataLabels
import com.github.aachartmodel.aainfographics.aaoptionsmodel.AAItemStyle
import com.github.aachartmodel.aainfographics.aaoptionsmodel.AAMarker
import com.github.aachartmodel.aainfographics.aaoptionsmodel.AAPlotOptions
import com.github.aachartmodel.aainfographics.aaoptionsmodel.AAStyle
+import com.github.aachartmodel.aainfographics.aaoptionsmodel.AAYAxis
import com.github.aachartmodel.aainfographics.aatools.AAColor
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -163,6 +166,46 @@ class StatsFragment(private val user: Query.UserProfile, private val activity: P
binding.releaseYearChartView.visibility = View.GONE
}
+ val startYearChartModel = getStartYearChartModel(anime)
+ if (startYearChartModel != null) {
+ binding.startYearChartView.visibility = View.VISIBLE
+ val aaOptions = buildOptions(startYearChartModel, false, """
+ function () {
+ return 'Year: ' +
+ this.x +
+ '
' +
+ ' ${getTypeName()} ' +
+ this.y
+ }
+ """.trimIndent()
+ )
+ binding.startYearChartView.aa_drawChartWithChartOptions(aaOptions)
+ } else {
+ binding.startYearChartView.visibility = View.GONE
+ }
+
+ val genreChartModel = getGenreChartModel(anime)
+ if (genreChartModel.first != null) {
+ binding.genreChartView.visibility = View.VISIBLE
+ val aaOptions = buildOptions(genreChartModel.first!!, true, """
+ function () {
+ return 'Genre: ' +
+ this.x +
+ '
' +
+ ' ${getTypeName()} ' +
+ this.y
+ }
+ """.trimIndent()
+ )
+ val min = genreChartModel.second.first
+ val max = genreChartModel.second.second
+ aaOptions.yAxis = AAYAxis().min(min).max(max).tickInterval(if (max > 100) 20 else 10)
+ binding.genreChartView.aa_drawChartWithChartOptions(aaOptions)
+ } else {
+ binding.genreChartView.visibility = View.GONE
+ }
+
+
}
private fun buildOptions(
@@ -302,9 +345,9 @@ class StatsFragment(private val user: Query.UserProfile, private val activity: P
private fun getLengthChartModel(anime: Boolean): AAChartModel? {
val names: List = if (anime) {
- stats?.data?.user?.statistics?.anime?.lengths?.mapNotNull { it.length } ?: emptyList()
+ stats?.data?.user?.statistics?.anime?.lengths?.map { it.length?: "unknown" } ?: emptyList()
} else {
- stats?.data?.user?.statistics?.manga?.lengths?.mapNotNull { it.length } ?: emptyList()
+ stats?.data?.user?.statistics?.manga?.lengths?.map { it.length?: "unknown" } ?: emptyList()
}
val values: List = if (anime) {
when (statType) {
@@ -351,7 +394,6 @@ class StatsFragment(private val user: Query.UserProfile, private val activity: P
StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.manga?.releaseYears?.map { it.meanScore }
} ?: emptyList()
}
- //clear nulls from names
if (names.isEmpty() || values.isEmpty())
return null
val palette = generateColorPalette(primaryColor, names.size)
@@ -368,6 +410,79 @@ class StatsFragment(private val user: Query.UserProfile, private val activity: P
.colorsTheme(hexColorsArray)
}
+ private fun getStartYearChartModel(anime: Boolean): AAChartModel? {
+ val names: List = if (anime) {
+ stats?.data?.user?.statistics?.anime?.startYears?.map { it.startYear } ?: emptyList()
+ } else {
+ stats?.data?.user?.statistics?.manga?.startYears?.map { it.startYear } ?: emptyList()
+ }
+ val values: List = if (anime) {
+ when (statType) {
+ StatType.COUNT -> stats?.data?.user?.statistics?.anime?.startYears?.map { it.count }
+ StatType.TIME -> stats?.data?.user?.statistics?.anime?.startYears?.map { it.minutesWatched / 60 }
+ StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.anime?.startYears?.map { it.meanScore }
+ } ?: emptyList()
+ } else {
+ when (statType) {
+ StatType.COUNT -> stats?.data?.user?.statistics?.manga?.startYears?.map { it.count }
+ StatType.TIME -> stats?.data?.user?.statistics?.manga?.startYears?.map { it.chaptersRead }
+ StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.manga?.startYears?.map { it.meanScore }
+ } ?: emptyList()
+ }
+ if (names.isEmpty() || values.isEmpty())
+ return null
+ val palette = generateColorPalette(primaryColor, names.size)
+ val hexColorsArray: Array = palette.map { String.format("#%06X", 0xFFFFFF and it) }.toTypedArray()
+ return AAChartModel()
+ .chartType(AAChartType.Bar)
+ .title("Start Year")
+ .subtitle(getTypeName())
+ .zoomType(AAChartZoomType.XY)
+ .dataLabelsEnabled(false)
+ .yAxisTitle(getTypeName())
+ .stacking(AAChartStackingType.Normal)
+ .series(getElementsSimple(names, values))
+ .colorsTheme(hexColorsArray)
+ }
+
+ private fun getGenreChartModel(anime: Boolean): Pair> {
+ val names: List = if (anime) {
+ stats?.data?.user?.statistics?.anime?.genres?.map { it.genre } ?: emptyList()
+ } else {
+ stats?.data?.user?.statistics?.manga?.genres?.map { it.genre } ?: emptyList()
+ }
+ val values: List = if (anime) {
+ when (statType) {
+ StatType.COUNT -> stats?.data?.user?.statistics?.anime?.genres?.map { it.count }
+ StatType.TIME -> stats?.data?.user?.statistics?.anime?.genres?.map { it.minutesWatched / 60 }
+ StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.anime?.genres?.map { it.meanScore }
+ } ?: emptyList()
+ } else {
+ when (statType) {
+ StatType.COUNT -> stats?.data?.user?.statistics?.manga?.genres?.map { it.count }
+ StatType.TIME -> stats?.data?.user?.statistics?.manga?.genres?.map { it.chaptersRead }
+ StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.manga?.genres?.map { it.meanScore }
+ } ?: emptyList()
+ }
+ if (names.isEmpty() || values.isEmpty())
+ return Pair(null, Pair(0, 0))
+ val palette = generateColorPalette(primaryColor, names.size)
+ val hexColorsArray: Array = palette.map { String.format("#%06X", 0xFFFFFF and it) }.toTypedArray()
+ return Pair(AAChartModel()
+ .chartType(AAChartType.Area)
+ .title("Genre")
+ .subtitle(getTypeName())
+ .zoomType(AAChartZoomType.XY)
+ .dataLabelsEnabled(false)
+ .legendEnabled(false)
+ .yAxisTitle(getTypeName())
+ .stacking(AAChartStackingType.Normal)
+ .series(getElementsSimple(names, values))
+ .colorsTheme(hexColorsArray)
+ .categories(names.toTypedArray()),
+ Pair(values.minOf { it.toInt() }, values.maxOf { it.toInt() }))
+ }
+
enum class StatType {
COUNT, TIME, MEAN_SCORE
}
@@ -409,6 +524,7 @@ class StatsFragment(private val user: Query.UserProfile, private val activity: P
.backgroundColor(AAColor.rgbaColor(255, 255, 255, 0.0f))
)
} else {
+ element.x(i)
element.name(names[i] as String)
}
statDataElements.add(element)
@@ -420,17 +536,16 @@ class StatsFragment(private val user: Query.UserProfile, private val activity: P
}
private fun getElementsSimple(
- names: List,
- statData: List
+ names: List,
+ statData: List
): Array {
- val statValues = mutableListOf>()
+ val statValues = mutableListOf>()
for (i in statData.indices) {
statValues.add(arrayOf(names[i], statData[i], statData[i]))
}
- val sorted = statValues.sortedBy { it[0] as Int }
return arrayOf(
AASeriesElement().name("Score")
- .data(sorted.toTypedArray())
+ .data(statValues.toTypedArray())
.dataLabels(AADataLabels()
.enabled(false)
)