feat: compare user stats
This commit is contained in:
parent
d181dcf837
commit
5279b0cd65
13 changed files with 745 additions and 472 deletions
|
@ -3,6 +3,7 @@ package ani.dantotsu.profile
|
|||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.util.TypedValue
|
||||
import ani.dantotsu.util.ColorEditor
|
||||
import com.github.aachartmodel.aainfographics.aachartcreator.AAChartModel
|
||||
import com.github.aachartmodel.aainfographics.aachartcreator.AAChartStackingType
|
||||
import com.github.aachartmodel.aainfographics.aachartcreator.AAChartType
|
||||
|
@ -17,6 +18,7 @@ import com.github.aachartmodel.aainfographics.aaoptionsmodel.AAScrollablePlotAre
|
|||
import com.github.aachartmodel.aainfographics.aaoptionsmodel.AAStyle
|
||||
import com.github.aachartmodel.aainfographics.aaoptionsmodel.AAYAxis
|
||||
import com.github.aachartmodel.aainfographics.aatools.AAColor
|
||||
import com.github.aachartmodel.aainfographics.aatools.AAGradientColor
|
||||
|
||||
class ChartBuilder {
|
||||
companion object {
|
||||
|
@ -25,25 +27,30 @@ class ChartBuilder {
|
|||
}
|
||||
|
||||
enum class StatType {
|
||||
COUNT, TIME, MEAN_SCORE
|
||||
COUNT, TIME, AVG_SCORE
|
||||
}
|
||||
|
||||
enum class MediaType {
|
||||
ANIME, MANGA
|
||||
}
|
||||
|
||||
data class ChartPacket(
|
||||
val username: String,
|
||||
val names: List<Any>,
|
||||
val statData: List<Number>
|
||||
)
|
||||
|
||||
fun buildChart(
|
||||
context: Context,
|
||||
chartType: ChartType,
|
||||
aaChartType: AAChartType,
|
||||
passedChartType: ChartType,
|
||||
passedAaChartType: AAChartType,
|
||||
statType: StatType,
|
||||
mediaType: MediaType,
|
||||
names: List<Any>,
|
||||
statData: List<Number>,
|
||||
chartPackets: List<ChartPacket>,
|
||||
xAxisName: String = "X Axis",
|
||||
xAxisTickInterval: Int? = null,
|
||||
polar: Boolean = false,
|
||||
categories: List<String>? = null,
|
||||
passedCategories: List<String>? = null,
|
||||
scrollPos: Float? = null,
|
||||
): AAOptions {
|
||||
val typedValue = TypedValue()
|
||||
|
@ -53,7 +60,18 @@ class ChartBuilder {
|
|||
true
|
||||
)
|
||||
val primaryColor = typedValue.data
|
||||
val palette = generateColorPalette(primaryColor, names.size)
|
||||
var chartType = passedChartType
|
||||
var aaChartType = passedAaChartType
|
||||
var categories = passedCategories
|
||||
if (chartType == ChartType.OneDimensional && chartPackets.size != 1) {
|
||||
//need to convert to 2D
|
||||
chartType = ChartType.TwoDimensional
|
||||
aaChartType = AAChartType.Column
|
||||
categories = chartPackets[0].names.map { it.toString() }
|
||||
}
|
||||
|
||||
val namesMax = chartPackets.maxOf { it.names.size }
|
||||
val palette = ColorEditor.generateColorPalette(primaryColor, namesMax)
|
||||
val aaChartModel = when (chartType) {
|
||||
ChartType.OneDimensional -> {
|
||||
val chart = AAChartModel()
|
||||
|
@ -61,14 +79,26 @@ class ChartBuilder {
|
|||
.subtitle(getTypeName(statType, mediaType))
|
||||
.zoomType(AAChartZoomType.None)
|
||||
.dataLabelsEnabled(true)
|
||||
.series(
|
||||
get1DElements(
|
||||
names,
|
||||
statData,
|
||||
palette,
|
||||
primaryColor
|
||||
)
|
||||
)
|
||||
val elements: MutableList<Any> = mutableListOf()
|
||||
chartPackets.forEachIndexed { index, chartPacket ->
|
||||
val element = AASeriesElement()
|
||||
.name(chartPacket.username)
|
||||
.data(
|
||||
get1DElements(
|
||||
chartPacket.names,
|
||||
chartPacket.statData,
|
||||
palette
|
||||
)
|
||||
)
|
||||
if (index == 0) {
|
||||
element.color(primaryColor)
|
||||
} else {
|
||||
element.color(ColorEditor.oppositeColor(primaryColor))
|
||||
}
|
||||
elements.add(element)
|
||||
|
||||
}
|
||||
chart.series(elements.toTypedArray())
|
||||
xAxisTickInterval?.let { chart.xAxisTickInterval(it) }
|
||||
categories?.let { chart.categories(it.toTypedArray()) }
|
||||
chart
|
||||
|
@ -83,9 +113,31 @@ class ChartBuilder {
|
|||
.zoomType(AAChartZoomType.None)
|
||||
.dataLabelsEnabled(false)
|
||||
.yAxisTitle(getTypeName(statType, mediaType))
|
||||
.stacking(AAChartStackingType.Normal)
|
||||
.series(get2DElements(names, statData, primaryColor))
|
||||
.colorsTheme(hexColorsArray)
|
||||
if (chartPackets.size == 1) {
|
||||
chart.colorsTheme(hexColorsArray)
|
||||
}
|
||||
|
||||
val elements: MutableList<AASeriesElement> = mutableListOf()
|
||||
chartPackets.forEachIndexed { index, chartPacket ->
|
||||
val element = get2DElements(
|
||||
chartPacket.names,
|
||||
chartPacket.statData,
|
||||
chartPackets.size == 1
|
||||
)
|
||||
element.name(chartPacket.username)
|
||||
|
||||
if (index == 0) {
|
||||
element.color(AAColor.rgbaColor(Color.red(primaryColor), Color.green(primaryColor), Color.blue(primaryColor), 0.9f))
|
||||
|
||||
} else {
|
||||
element.color(AAColor.rgbaColor(Color.red(ColorEditor.oppositeColor(primaryColor)), Color.green(ColorEditor.oppositeColor(primaryColor)), Color.blue(ColorEditor.oppositeColor(primaryColor)), 0.9f))
|
||||
}
|
||||
if (chartPackets.size == 1) {
|
||||
element.fillColor(AAColor.rgbaColor(Color.red(primaryColor), Color.green(primaryColor), Color.blue(primaryColor), 0.9f))
|
||||
}
|
||||
elements.add(element)
|
||||
}
|
||||
chart.series(elements.toTypedArray())
|
||||
|
||||
xAxisTickInterval?.let { chart.xAxisTickInterval(it) }
|
||||
categories?.let { chart.categories(it.toTypedArray()) }
|
||||
|
@ -101,24 +153,32 @@ class ChartBuilder {
|
|||
getToolTipFunction(
|
||||
chartType,
|
||||
xAxisName,
|
||||
getTypeName(statType, mediaType)
|
||||
getTypeName(statType, mediaType),
|
||||
chartPackets.size
|
||||
)
|
||||
)
|
||||
if (chartPackets.size > 1) {
|
||||
useHTML(true)
|
||||
}
|
||||
}
|
||||
aaOptions.legend?.apply {
|
||||
enabled(true)
|
||||
.labelFormat = "{name}: {y}"
|
||||
.labelFormat = "{name}"
|
||||
}
|
||||
aaOptions.plotOptions?.series?.connectNulls(true)
|
||||
aaOptions.plotOptions?.series?.connectNulls(false)
|
||||
aaOptions.plotOptions?.series?.stacking(AAChartStackingType.False)
|
||||
aaOptions.chart?.panning = true
|
||||
|
||||
scrollPos?.let {
|
||||
aaOptions.chart?.scrollablePlotArea(AAScrollablePlotArea().scrollPositionX(scrollPos))
|
||||
aaOptions.chart?.scrollablePlotArea?.minWidth((context.resources.displayMetrics.widthPixels.toFloat() / context.resources.displayMetrics.density) * (names.size.toFloat() / 18.0f))
|
||||
aaOptions.chart?.scrollablePlotArea?.minWidth((context.resources.displayMetrics.widthPixels.toFloat() / context.resources.displayMetrics.density) * (namesMax.toFloat() / 18.0f))
|
||||
}
|
||||
val min = ((statData.minOfOrNull { it.toDouble() } ?: 0.0) - 1.0).coerceAtLeast(0.0)
|
||||
val max = statData.maxOfOrNull { it.toDouble() } ?: 0.0
|
||||
val aaYaxis = AAYAxis().min(min).max(max)
|
||||
val allStatData = chartPackets.flatMap { it.statData }
|
||||
val min = (allStatData.minOfOrNull { it.toDouble() } ?: 0.0) - 1.0
|
||||
val coercedMin = min.coerceAtLeast(0.0)
|
||||
val max = allStatData.maxOfOrNull { it.toDouble() } ?: 0.0
|
||||
|
||||
val aaYaxis = AAYAxis().min(coercedMin).max(max)
|
||||
val tickInterval = when (max) {
|
||||
in 0.0..10.0 -> 1.0
|
||||
in 10.0..30.0 -> 5.0
|
||||
|
@ -138,34 +198,25 @@ class ChartBuilder {
|
|||
private fun get2DElements(
|
||||
names: List<Any>,
|
||||
statData: List<Any>,
|
||||
primaryColor: Int
|
||||
): Array<Any> {
|
||||
colorByPoint: Boolean
|
||||
): AASeriesElement {
|
||||
val statValues = mutableListOf<Array<Any>>()
|
||||
for (i in statData.indices) {
|
||||
statValues.add(arrayOf(names[i], statData[i], statData[i]))
|
||||
}
|
||||
return arrayOf(
|
||||
AASeriesElement().name("Score")
|
||||
return AASeriesElement()
|
||||
.data(statValues.toTypedArray())
|
||||
.dataLabels(
|
||||
AADataLabels()
|
||||
.enabled(false)
|
||||
)
|
||||
.colorByPoint(true)
|
||||
.fillColor(AAColor.rgbaColor(
|
||||
Color.red(primaryColor),
|
||||
Color.green(primaryColor),
|
||||
Color.blue(primaryColor),
|
||||
0.9f
|
||||
))
|
||||
)
|
||||
.colorByPoint(colorByPoint)
|
||||
}
|
||||
|
||||
private fun get1DElements(
|
||||
names: List<Any>,
|
||||
statData: List<Number>,
|
||||
colors: List<Int>,
|
||||
primaryColor: Int
|
||||
colors: List<Int>
|
||||
): Array<Any> {
|
||||
val statDataElements = mutableListOf<AADataElement>()
|
||||
for (i in statData.indices) {
|
||||
|
@ -193,44 +244,17 @@ class ChartBuilder {
|
|||
}
|
||||
statDataElements.add(element)
|
||||
}
|
||||
return arrayOf(
|
||||
AASeriesElement().name("Score").color(primaryColor)
|
||||
.data(statDataElements.toTypedArray())
|
||||
)
|
||||
return statDataElements.toTypedArray()
|
||||
}
|
||||
|
||||
private fun getTypeName(statType: StatType, mediaType: MediaType): String {
|
||||
return when (statType) {
|
||||
StatType.COUNT -> "Count"
|
||||
StatType.TIME -> if (mediaType == MediaType.ANIME) "Hours Watched" else "Chapters Read"
|
||||
StatType.MEAN_SCORE -> "Mean Score"
|
||||
StatType.AVG_SCORE -> "Mean Score"
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateColorPalette(
|
||||
baseColor: Int,
|
||||
size: Int,
|
||||
hueDelta: Float = 8f,
|
||||
saturationDelta: Float = 2.02f,
|
||||
valueDelta: Float = 2.02f
|
||||
): List<Int> {
|
||||
val palette = mutableListOf<Int>()
|
||||
val hsv = FloatArray(3)
|
||||
Color.colorToHSV(baseColor, hsv)
|
||||
|
||||
for (i in 0 until size) {
|
||||
val newHue =
|
||||
(hsv[0] + hueDelta * i) % 360 // Ensure hue stays within the 0-360 range
|
||||
val newSaturation = (hsv[1] + saturationDelta * i).coerceIn(0f, 1f)
|
||||
val newValue = (hsv[2] + valueDelta * i).coerceIn(0f, 1f)
|
||||
|
||||
val newHsv = floatArrayOf(newHue, newSaturation, newValue)
|
||||
palette.add(Color.HSVToColor(newHsv))
|
||||
}
|
||||
|
||||
return palette
|
||||
}
|
||||
|
||||
private fun setColors(aaOptions: AAOptions, context: Context, primaryColor: Int) {
|
||||
val backgroundColor = TypedValue()
|
||||
context.theme.resolveAttribute(
|
||||
|
@ -265,15 +289,15 @@ class ChartBuilder {
|
|||
aaOptions.chart?.backgroundColor(backgroundStyle.color)
|
||||
aaOptions.tooltip?.backgroundColor(
|
||||
AAColor.rgbaColor(
|
||||
Color.red(primaryColor),
|
||||
Color.green(primaryColor),
|
||||
Color.blue(primaryColor),
|
||||
Color.red(backgroundColor.data),
|
||||
Color.green(backgroundColor.data),
|
||||
Color.blue(backgroundColor.data),
|
||||
0.9f
|
||||
)
|
||||
)
|
||||
aaOptions.title?.style(onBackgroundStyle)
|
||||
aaOptions.subtitle?.style(onBackgroundStyle)
|
||||
aaOptions.tooltip?.style(backgroundStyle)
|
||||
aaOptions.tooltip?.style(onBackgroundStyle)
|
||||
aaOptions.credits?.style(onBackgroundStyle)
|
||||
aaOptions.xAxis?.labels?.style(onBackgroundStyle)
|
||||
aaOptions.yAxis?.labels?.style(onBackgroundStyle)
|
||||
|
@ -287,7 +311,8 @@ class ChartBuilder {
|
|||
private fun getToolTipFunction(
|
||||
chartType: ChartType,
|
||||
type: String,
|
||||
typeName: String
|
||||
typeName: String,
|
||||
chartSize: Int
|
||||
): String {
|
||||
return when (chartType) {
|
||||
ChartType.OneDimensional -> {
|
||||
|
@ -305,7 +330,8 @@ class ChartBuilder {
|
|||
}
|
||||
|
||||
ChartType.TwoDimensional -> {
|
||||
"""
|
||||
if (chartSize == 1) {
|
||||
"""
|
||||
function () {
|
||||
return '$type: ' +
|
||||
this.x +
|
||||
|
@ -314,8 +340,34 @@ class ChartBuilder {
|
|||
this.y
|
||||
}
|
||||
""".trimIndent()
|
||||
} else {
|
||||
"""
|
||||
function() {
|
||||
let wholeContentStr = '<span style=\"' + 'color:gray; font-size:13px\"' + '>◉${type}: ' + this.x + '</span><br/>';
|
||||
if (this.points) {
|
||||
let length = this.points.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
let thisPoint = this.points[i];
|
||||
let yValue = thisPoint.y;
|
||||
if (yValue != 0) {
|
||||
let spanStyleStartStr = '<span style=\"' + 'color: ' + thisPoint.color + '; font-size:13px\"' + '>◉ ';
|
||||
let spanStyleEndStr = '</span> <br/>';
|
||||
wholeContentStr += spanStyleStartStr + thisPoint.series.name + ': ' + yValue + spanStyleEndStr;
|
||||
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let spanStyleStartStr = '<span style=\"' + 'color: ' + this.point.color + '; font-size:13px\"' + '>◉ ';
|
||||
let spanStyleEndStr = '</span> <br/>';
|
||||
wholeContentStr += spanStyleStartStr + this.point.series.name + ': ' + this.point.y + spanStyleEndStr;
|
||||
}
|
||||
return wholeContentStr;
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -15,19 +15,19 @@ import ani.dantotsu.databinding.FragmentStatisticsBinding
|
|||
import ani.dantotsu.profile.ChartBuilder.Companion.ChartType
|
||||
import ani.dantotsu.profile.ChartBuilder.Companion.StatType
|
||||
import ani.dantotsu.profile.ChartBuilder.Companion.MediaType
|
||||
import ani.dantotsu.profile.ChartBuilder.Companion.ChartPacket
|
||||
import com.github.aachartmodel.aainfographics.aachartcreator.AAChartType
|
||||
import com.github.aachartmodel.aainfographics.aaoptionsmodel.AAYAxis
|
||||
import com.xwray.groupie.GroupieAdapter
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.Locale
|
||||
|
||||
class StatsFragment() :
|
||||
class StatsFragment :
|
||||
Fragment() {
|
||||
private lateinit var binding: FragmentStatisticsBinding
|
||||
private var adapter: GroupieAdapter = GroupieAdapter()
|
||||
private var stats: Query.StatisticsResponse? = null
|
||||
private var stats: MutableList<Query.StatisticsUser?> = mutableListOf()
|
||||
private var type: MediaType = MediaType.ANIME
|
||||
private var statType: StatType = StatType.COUNT
|
||||
private lateinit var user: Query.UserProfile
|
||||
|
@ -52,25 +52,55 @@ class StatsFragment() :
|
|||
binding.statisticList.isNestedScrollingEnabled = false
|
||||
binding.statisticList.layoutManager = LinearLayoutManager(requireContext())
|
||||
binding.statisticProgressBar.visibility = View.VISIBLE
|
||||
binding.compare.visibility = if (user.id == Anilist.userid) View.GONE else View.VISIBLE
|
||||
|
||||
binding.sourceType.setAdapter(
|
||||
ArrayAdapter(
|
||||
requireContext(),
|
||||
R.layout.item_dropdown,
|
||||
MediaType.entries.map { it.name.uppercase(Locale.ROOT) }
|
||||
MediaType.entries.map { it.name.uppercase(Locale.ROOT).replace("_", " ") }
|
||||
)
|
||||
)
|
||||
binding.sourceFilter.setAdapter(
|
||||
ArrayAdapter(
|
||||
requireContext(),
|
||||
R.layout.item_dropdown,
|
||||
StatType.entries.map { it.name.uppercase(Locale.ROOT) }
|
||||
StatType.entries.map { it.name.uppercase(Locale.ROOT).replace("_", " ") }
|
||||
)
|
||||
)
|
||||
|
||||
binding.compare.setOnCheckedChangeListener { _, isChecked ->
|
||||
if (isChecked) {
|
||||
activity.lifecycleScope.launch {
|
||||
if (Anilist.userid != null) {
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.statisticProgressBar.visibility = View.VISIBLE
|
||||
binding.statisticList.visibility = View.GONE
|
||||
}
|
||||
val userStats =
|
||||
Anilist.query.getUserStatistics(Anilist.userid!!)?.data?.user
|
||||
if (userStats != null) {
|
||||
stats.add(userStats)
|
||||
withContext(Dispatchers.Main) {
|
||||
loadStats(type == MediaType.ANIME)
|
||||
binding.statisticProgressBar.visibility = View.GONE
|
||||
binding.statisticList.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
stats.removeAll(
|
||||
stats.filter { it?.id == Anilist.userid }
|
||||
)
|
||||
loadStats(type == MediaType.ANIME)
|
||||
}
|
||||
}
|
||||
|
||||
binding.filterContainer.visibility = View.GONE
|
||||
activity.lifecycleScope.launch {
|
||||
stats = Anilist.query.getUserStatistics(user.id)
|
||||
stats.clear()
|
||||
stats.add(Anilist.query.getUserStatistics(user.id)?.data?.user)
|
||||
withContext(Dispatchers.Main) {
|
||||
binding.filterContainer.visibility = View.VISIBLE
|
||||
binding.sourceType.setOnItemClickListener { _, _, i, _ ->
|
||||
|
@ -116,99 +146,114 @@ class StatsFragment() :
|
|||
}
|
||||
|
||||
private fun loadFormatChart(anime: Boolean) {
|
||||
val names: List<String> = if (anime) {
|
||||
stats?.data?.user?.statistics?.anime?.formats?.map { it.format } ?: emptyList()
|
||||
} else {
|
||||
stats?.data?.user?.statistics?.manga?.formats?.map { it.format } ?: emptyList()
|
||||
val chartPackets = mutableListOf<ChartPacket>()
|
||||
stats.forEach {stat ->
|
||||
val names: List<String> = if (anime) {
|
||||
stat?.statistics?.anime?.formats?.map { it.format } ?: emptyList()
|
||||
} else {
|
||||
stat?.statistics?.manga?.formats?.map { it.format } ?: emptyList()
|
||||
}
|
||||
val values: List<Number> = if (anime) {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.anime?.formats?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.anime?.formats?.map { it.minutesWatched / 60 }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.anime?.formats?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
} else {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.manga?.formats?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.manga?.formats?.map { it.chaptersRead }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.manga?.formats?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
}
|
||||
if (names.isNotEmpty() && values.isNotEmpty()) {
|
||||
chartPackets.add(ChartPacket(stat?.name?:"Unknown", names, values))
|
||||
}
|
||||
}
|
||||
val values: List<Number> = if (anime) {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stats?.data?.user?.statistics?.anime?.formats?.map { it.count }
|
||||
StatType.TIME -> stats?.data?.user?.statistics?.anime?.formats?.map { it.minutesWatched / 60 }
|
||||
StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.anime?.formats?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
} else {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stats?.data?.user?.statistics?.manga?.formats?.map { it.count }
|
||||
StatType.TIME -> stats?.data?.user?.statistics?.manga?.formats?.map { it.chaptersRead }
|
||||
StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.manga?.formats?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
}
|
||||
if (names.isNotEmpty() || values.isNotEmpty()) {
|
||||
if (chartPackets.isNotEmpty()) {
|
||||
val formatChart = ChartBuilder.buildChart(
|
||||
activity,
|
||||
ChartType.OneDimensional,
|
||||
AAChartType.Pie,
|
||||
statType,
|
||||
type,
|
||||
names,
|
||||
values
|
||||
chartPackets,
|
||||
)
|
||||
adapter.add(ChartItem("Format", formatChart, activity))
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadStatusChart(anime: Boolean) {
|
||||
val names: List<String> = if (anime) {
|
||||
stats?.data?.user?.statistics?.anime?.statuses?.map { it.status } ?: emptyList()
|
||||
} else {
|
||||
stats?.data?.user?.statistics?.manga?.statuses?.map { it.status } ?: emptyList()
|
||||
val chartPackets = mutableListOf<ChartPacket>()
|
||||
stats.forEach { stat ->
|
||||
val names: List<String> = if (anime) {
|
||||
stat?.statistics?.anime?.statuses?.map { it.status } ?: emptyList()
|
||||
} else {
|
||||
stat?.statistics?.manga?.statuses?.map { it.status } ?: emptyList()
|
||||
}
|
||||
val values: List<Number> = if (anime) {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.anime?.statuses?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.anime?.statuses?.map { it.minutesWatched / 60 }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.anime?.statuses?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
} else {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.manga?.statuses?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.manga?.statuses?.map { it.chaptersRead }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.manga?.statuses?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
}
|
||||
if (names.isNotEmpty() && values.isNotEmpty()) {
|
||||
chartPackets.add(ChartPacket(stat?.name ?: "Unknown", names, values))
|
||||
}
|
||||
}
|
||||
val values: List<Number> = if (anime) {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stats?.data?.user?.statistics?.anime?.statuses?.map { it.count }
|
||||
StatType.TIME -> stats?.data?.user?.statistics?.anime?.statuses?.map { it.minutesWatched / 60 }
|
||||
StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.anime?.statuses?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
} else {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stats?.data?.user?.statistics?.manga?.statuses?.map { it.count }
|
||||
StatType.TIME -> stats?.data?.user?.statistics?.manga?.statuses?.map { it.chaptersRead }
|
||||
StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.manga?.statuses?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
}
|
||||
if (names.isNotEmpty() || values.isNotEmpty()) {
|
||||
if (chartPackets.isNotEmpty()) {
|
||||
val statusChart = ChartBuilder.buildChart(
|
||||
activity,
|
||||
ChartType.OneDimensional,
|
||||
AAChartType.Funnel,
|
||||
statType,
|
||||
type,
|
||||
names,
|
||||
values
|
||||
chartPackets
|
||||
)
|
||||
adapter.add(ChartItem("Status", statusChart, activity))
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadScoreChart(anime: Boolean) {
|
||||
val names: List<Int> = if (anime) {
|
||||
stats?.data?.user?.statistics?.anime?.scores?.map { it.score } ?: emptyList()
|
||||
} else {
|
||||
stats?.data?.user?.statistics?.manga?.scores?.map { it.score } ?: emptyList()
|
||||
val chartPackets = mutableListOf<ChartPacket>()
|
||||
stats.forEach { stat ->
|
||||
val names: List<Int> = if (anime) {
|
||||
stat?.statistics?.anime?.scores?.map { it.score } ?: emptyList()
|
||||
} else {
|
||||
stat?.statistics?.manga?.scores?.map { it.score } ?: emptyList()
|
||||
}
|
||||
val values: List<Number> = if (anime) {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.anime?.scores?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.anime?.scores?.map { it.minutesWatched / 60 }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.anime?.scores?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
} else {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.manga?.scores?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.manga?.scores?.map { it.chaptersRead }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.manga?.scores?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
}
|
||||
if (names.isNotEmpty() || values.isNotEmpty()) {
|
||||
chartPackets.add(ChartPacket(stat?.name ?: "Unknown", names, values))
|
||||
}
|
||||
}
|
||||
val values: List<Number> = if (anime) {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stats?.data?.user?.statistics?.anime?.scores?.map { it.count }
|
||||
StatType.TIME -> stats?.data?.user?.statistics?.anime?.scores?.map { it.minutesWatched / 60 }
|
||||
StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.anime?.scores?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
} else {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stats?.data?.user?.statistics?.manga?.scores?.map { it.count }
|
||||
StatType.TIME -> stats?.data?.user?.statistics?.manga?.scores?.map { it.chaptersRead }
|
||||
StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.manga?.scores?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
}
|
||||
if (names.isNotEmpty() || values.isNotEmpty()) {
|
||||
if (chartPackets.isNotEmpty()) {
|
||||
val scoreChart = ChartBuilder.buildChart(
|
||||
activity,
|
||||
ChartType.TwoDimensional,
|
||||
AAChartType.Column,
|
||||
statType,
|
||||
type,
|
||||
names,
|
||||
values,
|
||||
chartPackets,
|
||||
xAxisName = "Score",
|
||||
)
|
||||
adapter.add(ChartItem("Score", scoreChart, activity))
|
||||
|
@ -216,35 +261,40 @@ class StatsFragment() :
|
|||
}
|
||||
|
||||
private fun loadLengthChart(anime: Boolean) {
|
||||
val names: List<String> = if (anime) {
|
||||
stats?.data?.user?.statistics?.anime?.lengths?.map { it.length ?: "unknown" }
|
||||
?: emptyList()
|
||||
} else {
|
||||
stats?.data?.user?.statistics?.manga?.lengths?.map { it.length ?: "unknown" }
|
||||
?: emptyList()
|
||||
val chartPackets = mutableListOf<ChartPacket>()
|
||||
stats.forEach { stat ->
|
||||
val names: List<String> = if (anime) {
|
||||
stat?.statistics?.anime?.lengths?.map { it.length ?: "unknown" }
|
||||
?: emptyList()
|
||||
} else {
|
||||
stat?.statistics?.manga?.lengths?.map { it.length ?: "unknown" }
|
||||
?: emptyList()
|
||||
}
|
||||
val values: List<Number> = if (anime) {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.anime?.lengths?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.anime?.lengths?.map { it.minutesWatched / 60 }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.anime?.lengths?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
} else {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.manga?.lengths?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.manga?.lengths?.map { it.chaptersRead }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.manga?.lengths?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
}
|
||||
if (names.isNotEmpty() || values.isNotEmpty()) {
|
||||
chartPackets.add(ChartPacket(stat?.name ?: "Unknown", names, values))
|
||||
}
|
||||
}
|
||||
val values: List<Number> = if (anime) {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stats?.data?.user?.statistics?.anime?.lengths?.map { it.count }
|
||||
StatType.TIME -> stats?.data?.user?.statistics?.anime?.lengths?.map { it.minutesWatched / 60 }
|
||||
StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.anime?.lengths?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
} else {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stats?.data?.user?.statistics?.manga?.lengths?.map { it.count }
|
||||
StatType.TIME -> stats?.data?.user?.statistics?.manga?.lengths?.map { it.chaptersRead }
|
||||
StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.manga?.lengths?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
}
|
||||
if (names.isNotEmpty() || values.isNotEmpty()) {
|
||||
if (chartPackets.isNotEmpty()) {
|
||||
val lengthChart = ChartBuilder.buildChart(
|
||||
activity,
|
||||
ChartType.OneDimensional,
|
||||
AAChartType.Pyramid,
|
||||
statType,
|
||||
type,
|
||||
names,
|
||||
values,
|
||||
chartPackets,
|
||||
xAxisName = "Length",
|
||||
)
|
||||
adapter.add(ChartItem("Length", lengthChart, activity))
|
||||
|
@ -252,35 +302,40 @@ class StatsFragment() :
|
|||
}
|
||||
|
||||
private fun loadReleaseYearChart(anime: Boolean) {
|
||||
val names: List<Number> = if (anime) {
|
||||
stats?.data?.user?.statistics?.anime?.releaseYears?.map { it.releaseYear }
|
||||
?: emptyList()
|
||||
} else {
|
||||
stats?.data?.user?.statistics?.manga?.releaseYears?.map { it.releaseYear }
|
||||
?: emptyList()
|
||||
val chartPackets = mutableListOf<ChartPacket>()
|
||||
stats.forEach { stat ->
|
||||
val names: List<Number> = if (anime) {
|
||||
stat?.statistics?.anime?.releaseYears?.map { it.releaseYear }
|
||||
?: emptyList()
|
||||
} else {
|
||||
stat?.statistics?.manga?.releaseYears?.map { it.releaseYear }
|
||||
?: emptyList()
|
||||
}
|
||||
val values: List<Number> = if (anime) {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.anime?.releaseYears?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.anime?.releaseYears?.map { it.minutesWatched / 60 }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.anime?.releaseYears?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
} else {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.manga?.releaseYears?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.manga?.releaseYears?.map { it.chaptersRead }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.manga?.releaseYears?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
}
|
||||
if (names.isNotEmpty() || values.isNotEmpty()) {
|
||||
chartPackets.add(ChartPacket(stat?.name ?: "Unknown", names, values))
|
||||
}
|
||||
}
|
||||
val values: List<Number> = if (anime) {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stats?.data?.user?.statistics?.anime?.releaseYears?.map { it.count }
|
||||
StatType.TIME -> stats?.data?.user?.statistics?.anime?.releaseYears?.map { it.minutesWatched / 60 }
|
||||
StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.anime?.releaseYears?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
} else {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stats?.data?.user?.statistics?.manga?.releaseYears?.map { it.count }
|
||||
StatType.TIME -> stats?.data?.user?.statistics?.manga?.releaseYears?.map { it.chaptersRead }
|
||||
StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.manga?.releaseYears?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
}
|
||||
if (names.isNotEmpty() || values.isNotEmpty()) {
|
||||
if (chartPackets.isNotEmpty()) {
|
||||
val releaseYearChart = ChartBuilder.buildChart(
|
||||
activity,
|
||||
ChartType.TwoDimensional,
|
||||
AAChartType.Bubble,
|
||||
statType,
|
||||
type,
|
||||
names,
|
||||
values,
|
||||
chartPackets,
|
||||
xAxisName = "Year",
|
||||
)
|
||||
adapter.add(ChartItem("Release Year", releaseYearChart, activity))
|
||||
|
@ -288,33 +343,38 @@ class StatsFragment() :
|
|||
}
|
||||
|
||||
private fun loadStartYearChart(anime: Boolean) {
|
||||
val names: List<Number> = if (anime) {
|
||||
stats?.data?.user?.statistics?.anime?.startYears?.map { it.startYear } ?: emptyList()
|
||||
} else {
|
||||
stats?.data?.user?.statistics?.manga?.startYears?.map { it.startYear } ?: emptyList()
|
||||
val chartPackets = mutableListOf<ChartPacket>()
|
||||
stats.forEach { stat ->
|
||||
val names: List<Number> = if (anime) {
|
||||
stat?.statistics?.anime?.startYears?.map { it.startYear } ?: emptyList()
|
||||
} else {
|
||||
stat?.statistics?.manga?.startYears?.map { it.startYear } ?: emptyList()
|
||||
}
|
||||
val values: List<Number> = if (anime) {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.anime?.startYears?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.anime?.startYears?.map { it.minutesWatched / 60 }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.anime?.startYears?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
} else {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.manga?.startYears?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.manga?.startYears?.map { it.chaptersRead }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.manga?.startYears?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
}
|
||||
if (names.isNotEmpty() || values.isNotEmpty()) {
|
||||
chartPackets.add(ChartPacket(stat?.name ?: "Unknown", names, values))
|
||||
}
|
||||
}
|
||||
val values: List<Number> = 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.isNotEmpty() || values.isNotEmpty()) {
|
||||
if (chartPackets.isNotEmpty()) {
|
||||
val startYearChart = ChartBuilder.buildChart(
|
||||
activity,
|
||||
ChartType.TwoDimensional,
|
||||
AAChartType.Bar,
|
||||
statType,
|
||||
type,
|
||||
names,
|
||||
values,
|
||||
chartPackets,
|
||||
xAxisName = "Year",
|
||||
)
|
||||
adapter.add(ChartItem("Start Year", startYearChart, activity))
|
||||
|
@ -322,112 +382,160 @@ class StatsFragment() :
|
|||
}
|
||||
|
||||
private fun loadGenreChart(anime: Boolean) {
|
||||
val names: List<String> = if (anime) {
|
||||
stats?.data?.user?.statistics?.anime?.genres?.map { it.genre } ?: emptyList()
|
||||
} else {
|
||||
stats?.data?.user?.statistics?.manga?.genres?.map { it.genre } ?: emptyList()
|
||||
val chartPackets = mutableListOf<ChartPacket>()
|
||||
stats.forEach { stat ->
|
||||
val names: List<String> = if (anime) {
|
||||
stat?.statistics?.anime?.genres?.map { it.genre } ?: emptyList()
|
||||
} else {
|
||||
stat?.statistics?.manga?.genres?.map { it.genre } ?: emptyList()
|
||||
}
|
||||
val values: List<Number> = if (anime) {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.anime?.genres?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.anime?.genres?.map { it.minutesWatched / 60 }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.anime?.genres?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
} else {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.manga?.genres?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.manga?.genres?.map { it.chaptersRead }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.manga?.genres?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
}
|
||||
if (names.isNotEmpty() || values.isNotEmpty()) {
|
||||
chartPackets.add(ChartPacket(stat?.name ?: "Unknown", names, values))
|
||||
}
|
||||
}
|
||||
val values: List<Number> = 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.isNotEmpty() || values.isNotEmpty()) {
|
||||
if (chartPackets.isNotEmpty()) {
|
||||
val referenceNames = chartPackets.first().names.map { it.toString() }
|
||||
val standardizedPackets = chartPackets.map { packet ->
|
||||
val valuesMap = packet.names.map { it.toString() }.zip(packet.statData).toMap()
|
||||
val standardizedValues = referenceNames.map { name ->
|
||||
valuesMap[name] ?: 0
|
||||
}
|
||||
|
||||
// Create a new ChartPacket with standardized names and values.
|
||||
ChartPacket(packet.username, referenceNames, standardizedValues)
|
||||
}.toMutableList()
|
||||
chartPackets.clear()
|
||||
chartPackets.addAll(standardizedPackets)
|
||||
val genreChart = ChartBuilder.buildChart(
|
||||
activity,
|
||||
ChartType.TwoDimensional,
|
||||
AAChartType.Areaspline,
|
||||
statType,
|
||||
type,
|
||||
names,
|
||||
values,
|
||||
chartPackets,
|
||||
xAxisName = "Genre",
|
||||
polar = true,
|
||||
categories = names
|
||||
passedCategories = chartPackets[0].names as List<String>,
|
||||
)
|
||||
adapter.add(ChartItem("Genre", genreChart, activity))
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadTagChart(anime: Boolean) {
|
||||
val names: List<String> = if (anime) {
|
||||
stats?.data?.user?.statistics?.anime?.tags?.map { it.tag.name } ?: emptyList()
|
||||
} else {
|
||||
stats?.data?.user?.statistics?.manga?.tags?.map { it.tag.name } ?: emptyList()
|
||||
val chartPackets = mutableListOf<ChartPacket>()
|
||||
stats.forEach { stat ->
|
||||
val names: List<String> = if (anime) {
|
||||
stat?.statistics?.anime?.tags?.map { it.tag.name } ?: emptyList()
|
||||
} else {
|
||||
stat?.statistics?.manga?.tags?.map { it.tag.name } ?: emptyList()
|
||||
}
|
||||
val values: List<Number> = if (anime) {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.anime?.tags?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.anime?.tags?.map { it.minutesWatched / 60 }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.anime?.tags?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
} else {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.manga?.tags?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.manga?.tags?.map { it.chaptersRead }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.manga?.tags?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
}
|
||||
if (names.isNotEmpty() || values.isNotEmpty()) {
|
||||
chartPackets.add(ChartPacket(stat?.name ?: "Unknown", names, values))
|
||||
}
|
||||
}
|
||||
val values: List<Number> = if (anime) {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stats?.data?.user?.statistics?.anime?.tags?.map { it.count }
|
||||
StatType.TIME -> stats?.data?.user?.statistics?.anime?.tags?.map { it.minutesWatched / 60 }
|
||||
StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.anime?.tags?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
} else {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stats?.data?.user?.statistics?.manga?.tags?.map { it.count }
|
||||
StatType.TIME -> stats?.data?.user?.statistics?.manga?.tags?.map { it.chaptersRead }
|
||||
StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.manga?.tags?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
}
|
||||
if (names.isNotEmpty() || values.isNotEmpty()) {
|
||||
val min = values.minOf { it.toInt() }
|
||||
val max = values.maxOf { it.toInt() }
|
||||
if (chartPackets.isNotEmpty()) {
|
||||
val referenceNames = chartPackets.first().names.map { it.toString() }
|
||||
val standardizedPackets = chartPackets.map { packet ->
|
||||
val valuesMap = packet.names.map { it.toString() }.zip(packet.statData).toMap()
|
||||
val standardizedValues = referenceNames.map { name ->
|
||||
valuesMap[name] ?: 0
|
||||
}
|
||||
|
||||
// Create a new ChartPacket with standardized names and values.
|
||||
ChartPacket(packet.username, referenceNames, standardizedValues)
|
||||
}.toMutableList()
|
||||
chartPackets.clear()
|
||||
chartPackets.addAll(standardizedPackets)
|
||||
val tagChart = ChartBuilder.buildChart(
|
||||
activity,
|
||||
ChartType.TwoDimensional,
|
||||
AAChartType.Areaspline,
|
||||
statType,
|
||||
type,
|
||||
names,
|
||||
values,
|
||||
chartPackets,
|
||||
xAxisName = "Tag",
|
||||
polar = false,
|
||||
categories = names,
|
||||
passedCategories = chartPackets[0].names as List<String>,
|
||||
scrollPos = 0.0f
|
||||
)
|
||||
tagChart.yAxis = AAYAxis().min(min).max(max).tickInterval(if (max > 100) 20 else 10)
|
||||
adapter.add(ChartItem("Tag", tagChart, activity))
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadCountryChart(anime: Boolean) {
|
||||
val names: List<String> = if (anime) {
|
||||
stats?.data?.user?.statistics?.anime?.countries?.map { it.country } ?: emptyList()
|
||||
} else {
|
||||
stats?.data?.user?.statistics?.manga?.countries?.map { it.country } ?: emptyList()
|
||||
val chartPackets = mutableListOf<ChartPacket>()
|
||||
stats.forEach { stat ->
|
||||
val names: List<String> = if (anime) {
|
||||
stat?.statistics?.anime?.countries?.map { it.country } ?: emptyList()
|
||||
} else {
|
||||
stat?.statistics?.manga?.countries?.map { it.country } ?: emptyList()
|
||||
}
|
||||
val values: List<Number> = if (anime) {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.anime?.countries?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.anime?.countries?.map { it.minutesWatched / 60 }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.anime?.countries?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
} else {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.manga?.countries?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.manga?.countries?.map { it.chaptersRead }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.manga?.countries?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
}
|
||||
if (names.isNotEmpty() || values.isNotEmpty()) {
|
||||
chartPackets.add(ChartPacket(stat?.name ?: "Unknown", names, values))
|
||||
}
|
||||
}
|
||||
val values: List<Number> = if (anime) {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stats?.data?.user?.statistics?.anime?.countries?.map { it.count }
|
||||
StatType.TIME -> stats?.data?.user?.statistics?.anime?.countries?.map { it.minutesWatched / 60 }
|
||||
StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.anime?.countries?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
} else {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stats?.data?.user?.statistics?.manga?.countries?.map { it.count }
|
||||
StatType.TIME -> stats?.data?.user?.statistics?.manga?.countries?.map { it.chaptersRead }
|
||||
StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.manga?.countries?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
}
|
||||
if (names.isNotEmpty() || values.isNotEmpty()) {
|
||||
if (chartPackets.isNotEmpty()) {
|
||||
val referenceNames = chartPackets.first().names.map { it.toString() }
|
||||
val standardizedPackets = chartPackets.map { packet ->
|
||||
val valuesMap = packet.names.map { it.toString() }.zip(packet.statData).toMap()
|
||||
val standardizedValues = referenceNames.map { name ->
|
||||
valuesMap[name] ?: 0
|
||||
}
|
||||
|
||||
// Create a new ChartPacket with standardized names and values.
|
||||
ChartPacket(packet.username, referenceNames, standardizedValues)
|
||||
}.toMutableList()
|
||||
chartPackets.clear()
|
||||
chartPackets.addAll(standardizedPackets)
|
||||
val countryChart = ChartBuilder.buildChart(
|
||||
activity,
|
||||
ChartType.OneDimensional,
|
||||
AAChartType.Pie,
|
||||
statType,
|
||||
type,
|
||||
names,
|
||||
values,
|
||||
chartPackets,
|
||||
xAxisName = "Country",
|
||||
polar = false,
|
||||
categories = names,
|
||||
passedCategories = chartPackets[0].names as List<String>,
|
||||
scrollPos = null
|
||||
)
|
||||
adapter.add(ChartItem("Country", countryChart, activity))
|
||||
|
@ -435,116 +543,167 @@ class StatsFragment() :
|
|||
}
|
||||
|
||||
private fun loadVoiceActorsChart(anime: Boolean) {
|
||||
val names: List<String> = if (anime) {
|
||||
stats?.data?.user?.statistics?.anime?.voiceActors?.map { it.voiceActor.name.full?:"unknown" } ?: emptyList()
|
||||
} else {
|
||||
stats?.data?.user?.statistics?.manga?.voiceActors?.map { it.voiceActor.name.full?:"unknown" } ?: emptyList()
|
||||
val chartPackets = mutableListOf<ChartPacket>()
|
||||
stats.forEach { stat ->
|
||||
val names: List<String> = if (anime) {
|
||||
stat?.statistics?.anime?.voiceActors?.map { it.voiceActor.name.full?:"unknown" } ?: emptyList()
|
||||
} else {
|
||||
stat?.statistics?.manga?.voiceActors?.map { it.voiceActor.name.full?:"unknown" } ?: emptyList()
|
||||
}
|
||||
val values: List<Number> = if (anime) {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.anime?.voiceActors?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.anime?.voiceActors?.map { it.minutesWatched / 60 }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.anime?.voiceActors?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
} else {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.manga?.voiceActors?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.manga?.voiceActors?.map { it.chaptersRead }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.manga?.voiceActors?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
}
|
||||
if (names.isNotEmpty() || values.isNotEmpty()) {
|
||||
chartPackets.add(ChartPacket(stat?.name ?: "Unknown", names, values))
|
||||
}
|
||||
}
|
||||
val values: List<Number> = if (anime) {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stats?.data?.user?.statistics?.anime?.voiceActors?.map { it.count }
|
||||
StatType.TIME -> stats?.data?.user?.statistics?.anime?.voiceActors?.map { it.minutesWatched / 60 }
|
||||
StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.anime?.voiceActors?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
} else {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stats?.data?.user?.statistics?.manga?.voiceActors?.map { it.count }
|
||||
StatType.TIME -> stats?.data?.user?.statistics?.manga?.voiceActors?.map { it.chaptersRead }
|
||||
StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.manga?.voiceActors?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
}
|
||||
if (names.isNotEmpty() || values.isNotEmpty()) {
|
||||
if (chartPackets.isNotEmpty()) {
|
||||
val referenceNames = chartPackets.first().names.map { it.toString() }
|
||||
val standardizedPackets = chartPackets.map { packet ->
|
||||
val valuesMap = packet.names.map { it.toString() }.zip(packet.statData).toMap()
|
||||
val standardizedValues = referenceNames.map { name ->
|
||||
valuesMap[name] ?: 0
|
||||
}
|
||||
|
||||
// Create a new ChartPacket with standardized names and values.
|
||||
ChartPacket(packet.username, referenceNames, standardizedValues)
|
||||
}.toMutableList()
|
||||
chartPackets.clear()
|
||||
chartPackets.addAll(standardizedPackets)
|
||||
val voiceActorsChart = ChartBuilder.buildChart(
|
||||
activity,
|
||||
ChartType.TwoDimensional,
|
||||
AAChartType.Column,
|
||||
statType,
|
||||
type,
|
||||
names,
|
||||
values,
|
||||
chartPackets,
|
||||
xAxisName = "Voice Actor",
|
||||
polar = false,
|
||||
categories = names,
|
||||
passedCategories = chartPackets[0].names as List<String>,
|
||||
scrollPos = 0.0f
|
||||
)
|
||||
adapter.add(ChartItem("Voice Actor", voiceActorsChart, activity))
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadStaffChart(anime: Boolean) {
|
||||
val names: List<String> = if (anime) {
|
||||
stats?.data?.user?.statistics?.anime?.staff?.map { it.staff.name.full?:"unknown" } ?: emptyList()
|
||||
} else {
|
||||
stats?.data?.user?.statistics?.manga?.staff?.map { it.staff.name.full?:"unknown" } ?: emptyList()
|
||||
}
|
||||
val values: List<Number> = if (anime) {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stats?.data?.user?.statistics?.anime?.staff?.map { it.count }
|
||||
StatType.TIME -> stats?.data?.user?.statistics?.anime?.staff?.map { it.minutesWatched / 60 }
|
||||
StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.anime?.staff?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
} else {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stats?.data?.user?.statistics?.manga?.staff?.map { it.count }
|
||||
StatType.TIME -> stats?.data?.user?.statistics?.manga?.staff?.map { it.chaptersRead }
|
||||
StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.manga?.staff?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
}
|
||||
if (names.isNotEmpty() || values.isNotEmpty()) {
|
||||
val staffChart = ChartBuilder.buildChart(
|
||||
activity,
|
||||
ChartType.TwoDimensional,
|
||||
AAChartType.Line,
|
||||
statType,
|
||||
type,
|
||||
names,
|
||||
values,
|
||||
xAxisName = "Staff",
|
||||
polar = false,
|
||||
categories = names,
|
||||
scrollPos = 0.0f
|
||||
)
|
||||
adapter.add(ChartItem("Staff", staffChart, activity))
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadStudioChart(anime: Boolean) {
|
||||
val names: List<String> = if (anime) {
|
||||
stats?.data?.user?.statistics?.anime?.studios?.map { it.studio.name } ?: emptyList()
|
||||
} else {
|
||||
stats?.data?.user?.statistics?.manga?.studios?.map { it.studio.name } ?: emptyList()
|
||||
val chartPackets = mutableListOf<ChartPacket>()
|
||||
stats.forEach { stat ->
|
||||
val names: List<String> = if (anime) {
|
||||
stat?.statistics?.anime?.studios?.map { it.studio.name } ?: emptyList()
|
||||
} else {
|
||||
stat?.statistics?.manga?.studios?.map { it.studio.name } ?: emptyList()
|
||||
}
|
||||
val values: List<Number> = if (anime) {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.anime?.studios?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.anime?.studios?.map { it.minutesWatched / 60 }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.anime?.studios?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
} else {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.manga?.studios?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.manga?.studios?.map { it.chaptersRead }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.manga?.studios?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
}
|
||||
if (names.isNotEmpty() || values.isNotEmpty()) {
|
||||
chartPackets.add(ChartPacket(stat?.name ?: "Unknown", names, values))
|
||||
}
|
||||
}
|
||||
val values: List<Number> = if (anime) {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stats?.data?.user?.statistics?.anime?.studios?.map { it.count }
|
||||
StatType.TIME -> stats?.data?.user?.statistics?.anime?.studios?.map { it.minutesWatched / 60 }
|
||||
StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.anime?.studios?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
} else {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stats?.data?.user?.statistics?.manga?.studios?.map { it.count }
|
||||
StatType.TIME -> stats?.data?.user?.statistics?.manga?.studios?.map { it.chaptersRead }
|
||||
StatType.MEAN_SCORE -> stats?.data?.user?.statistics?.manga?.studios?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
}
|
||||
if (names.isNotEmpty() || values.isNotEmpty()) {
|
||||
if (chartPackets.isNotEmpty()) {
|
||||
val referenceNames = chartPackets.first().names.map { it.toString() }
|
||||
val standardizedPackets = chartPackets.map { packet ->
|
||||
val valuesMap = packet.names.map { it.toString() }.zip(packet.statData).toMap()
|
||||
val standardizedValues = referenceNames.map { name ->
|
||||
valuesMap[name] ?: 0
|
||||
}
|
||||
|
||||
// Create a new ChartPacket with standardized names and values.
|
||||
ChartPacket(packet.username, referenceNames, standardizedValues)
|
||||
}.toMutableList()
|
||||
chartPackets.clear()
|
||||
chartPackets.addAll(standardizedPackets)
|
||||
val studioChart = ChartBuilder.buildChart(
|
||||
activity,
|
||||
ChartType.TwoDimensional,
|
||||
AAChartType.Spline,
|
||||
statType,
|
||||
type,
|
||||
names.take(15),
|
||||
values.take(15),
|
||||
chartPackets,
|
||||
xAxisName = "Studio",
|
||||
polar = true,
|
||||
categories = names,
|
||||
passedCategories = chartPackets[0].names as List<String>,
|
||||
scrollPos = null
|
||||
)
|
||||
adapter.add(ChartItem("Studio", studioChart, activity))
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadStaffChart(anime: Boolean) {
|
||||
val chartPackets = mutableListOf<ChartPacket>()
|
||||
stats.forEach { stat ->
|
||||
val names: List<String> = if (anime) {
|
||||
stat?.statistics?.anime?.staff?.map { it.staff.name.full?:"unknown" } ?: emptyList()
|
||||
} else {
|
||||
stat?.statistics?.manga?.staff?.map { it.staff.name.full?:"unknown" } ?: emptyList()
|
||||
}
|
||||
val values: List<Number> = if (anime) {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.anime?.staff?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.anime?.staff?.map { it.minutesWatched / 60 }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.anime?.staff?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
} else {
|
||||
when (statType) {
|
||||
StatType.COUNT -> stat?.statistics?.manga?.staff?.map { it.count }
|
||||
StatType.TIME -> stat?.statistics?.manga?.staff?.map { it.chaptersRead }
|
||||
StatType.AVG_SCORE -> stat?.statistics?.manga?.staff?.map { it.meanScore }
|
||||
} ?: emptyList()
|
||||
}
|
||||
if (names.isNotEmpty() || values.isNotEmpty()) {
|
||||
chartPackets.add(ChartPacket(stat?.name ?: "Unknown", names, values))
|
||||
}
|
||||
}
|
||||
if (chartPackets.isNotEmpty()) {
|
||||
val referenceNames = chartPackets.first().names.map { it.toString() }
|
||||
val standardizedPackets = chartPackets.map { packet ->
|
||||
val valuesMap = packet.names.map { it.toString() }.zip(packet.statData).toMap()
|
||||
val standardizedValues = referenceNames.map { name ->
|
||||
valuesMap[name] ?: 0
|
||||
}
|
||||
|
||||
// Create a new ChartPacket with standardized names and values.
|
||||
ChartPacket(packet.username, referenceNames, standardizedValues)
|
||||
}.toMutableList()
|
||||
chartPackets.clear()
|
||||
chartPackets.addAll(standardizedPackets)
|
||||
val staffChart = ChartBuilder.buildChart(
|
||||
activity,
|
||||
ChartType.TwoDimensional,
|
||||
AAChartType.Line,
|
||||
statType,
|
||||
type,
|
||||
chartPackets,
|
||||
xAxisName = "Staff",
|
||||
polar = false,
|
||||
passedCategories = chartPackets[0].names as List<String>,
|
||||
scrollPos = 0.0f
|
||||
)
|
||||
adapter.add(ChartItem("Staff", staffChart, activity))
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun newInstance(user: Query.UserProfile): StatsFragment {
|
||||
val args = Bundle().apply {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue