Compute sum and ratio in stats
This commit is contained in:
parent
6aef6dabb2
commit
fd0ae64c0d
@ -4,6 +4,7 @@ import android.os.Bundle
|
|||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import androidx.viewpager2.adapter.FragmentStateAdapter
|
import androidx.viewpager2.adapter.FragmentStateAdapter
|
||||||
@ -12,14 +13,17 @@ import com.google.android.material.tabs.TabLayoutMediator
|
|||||||
import net.helcel.beans.R
|
import net.helcel.beans.R
|
||||||
import net.helcel.beans.activity.adapter.StatsListAdapter
|
import net.helcel.beans.activity.adapter.StatsListAdapter
|
||||||
import net.helcel.beans.databinding.ActivityStatBinding
|
import net.helcel.beans.databinding.ActivityStatBinding
|
||||||
|
import net.helcel.beans.helper.Settings
|
||||||
import net.helcel.beans.helper.Theme.createActionBar
|
import net.helcel.beans.helper.Theme.createActionBar
|
||||||
|
|
||||||
private val MODE_LIST = listOf("World", "Country", "Region")
|
const val WORLD = "Continents"
|
||||||
|
const val COUNTRY = "Countries"
|
||||||
|
const val REGION = "Regions"
|
||||||
|
private val MODE_LIST = listOf(WORLD, COUNTRY, REGION)
|
||||||
|
|
||||||
class StatActivity : AppCompatActivity() {
|
class StatActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private lateinit var _binding: ActivityStatBinding
|
private lateinit var _binding: ActivityStatBinding
|
||||||
private var activeMode: String = "World"
|
private var activeMode: String = WORLD
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@ -29,11 +33,11 @@ class StatActivity : AppCompatActivity() {
|
|||||||
|
|
||||||
_binding.stats.layoutManager =
|
_binding.stats.layoutManager =
|
||||||
LinearLayoutManager(this, RecyclerView.VERTICAL, false)
|
LinearLayoutManager(this, RecyclerView.VERTICAL, false)
|
||||||
val adapter = StatsListAdapter(_binding.stats)
|
val adapter = StatsListAdapter(_binding.stats, _binding.name)
|
||||||
_binding.stats.adapter = adapter
|
_binding.stats.adapter = adapter
|
||||||
|
|
||||||
_binding.pager.adapter = object : FragmentStateAdapter(supportFragmentManager, lifecycle) {
|
_binding.pager.adapter = object : FragmentStateAdapter(supportFragmentManager, lifecycle) {
|
||||||
override fun getItemCount(): Int = 3
|
override fun getItemCount(): Int = if (Settings.isRegional(applicationContext)) 3 else 2
|
||||||
override fun createFragment(position: Int): Fragment = Fragment()
|
override fun createFragment(position: Int): Fragment = Fragment()
|
||||||
}
|
}
|
||||||
TabLayoutMediator(_binding.tab, _binding.pager) { tab, position ->
|
TabLayoutMediator(_binding.tab, _binding.pager) { tab, position ->
|
||||||
@ -46,7 +50,7 @@ class StatActivity : AppCompatActivity() {
|
|||||||
adapter.refreshMode(activeMode)
|
adapter.refreshMode(activeMode)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
adapter.refreshMode(activeMode)
|
//adapter.refreshMode(activeMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
@ -153,14 +153,7 @@ class GeolocListAdapter(
|
|||||||
val numerator =
|
val numerator =
|
||||||
geoLoc.children.map { Data.visits.getVisited(it) != NO_GROUP }.count { it }
|
geoLoc.children.map { Data.visits.getVisited(it) != NO_GROUP }.count { it }
|
||||||
val denominator = geoLoc.children.size
|
val denominator = geoLoc.children.size
|
||||||
_binding.count.text = when (Settings.getStatPref(ctx)) {
|
_binding.count.text = Settings.getStats(ctx, numerator, denominator)
|
||||||
ctx.getString(R.string.percentages) -> ctx.getString(
|
|
||||||
R.string.percentage,
|
|
||||||
(100 * (numerator.toFloat() / denominator.toFloat())).toInt()
|
|
||||||
)
|
|
||||||
|
|
||||||
else -> ctx.getString(R.string.rate, numerator, denominator)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun refresh(geoLoc: GeoLoc) {
|
private fun refresh(geoLoc: GeoLoc) {
|
||||||
|
@ -1,40 +1,80 @@
|
|||||||
package net.helcel.beans.activity.adapter
|
package net.helcel.beans.activity.adapter
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.Context
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.google.android.material.textview.MaterialTextView
|
||||||
|
import net.helcel.beans.R
|
||||||
|
import net.helcel.beans.activity.COUNTRY
|
||||||
|
import net.helcel.beans.activity.REGION
|
||||||
|
import net.helcel.beans.activity.WORLD
|
||||||
import net.helcel.beans.countries.GeoLoc
|
import net.helcel.beans.countries.GeoLoc
|
||||||
import net.helcel.beans.countries.World
|
import net.helcel.beans.countries.World
|
||||||
import net.helcel.beans.databinding.ItemListGroupBinding
|
import net.helcel.beans.databinding.ItemListGroupBinding
|
||||||
|
import net.helcel.beans.helper.AUTO_GROUP
|
||||||
import net.helcel.beans.helper.Data
|
import net.helcel.beans.helper.Data
|
||||||
import net.helcel.beans.helper.Groups
|
import net.helcel.beans.helper.Groups
|
||||||
|
import net.helcel.beans.helper.Settings
|
||||||
import net.helcel.beans.helper.Theme.getContrastColor
|
import net.helcel.beans.helper.Theme.getContrastColor
|
||||||
|
|
||||||
class StatsListAdapter(private val stats: RecyclerView) :
|
class StatsListAdapter(private val stats: RecyclerView, private val total: MaterialTextView) :
|
||||||
RecyclerView.Adapter<StatsListAdapter.StatsViewHolder>() {
|
RecyclerView.Adapter<StatsListAdapter.StatsViewHolder>() {
|
||||||
|
private var locMode: String = WORLD
|
||||||
|
private lateinit var ctx: Context
|
||||||
|
private var countMode: Boolean = true
|
||||||
|
private var initialSum: Int = 0
|
||||||
|
|
||||||
|
private val wwwTotal: List<GeoLoc> = World.WWW.children.toList()
|
||||||
|
private val countryTotal: List<GeoLoc> = World.WWW.children.flatMap { it.children }
|
||||||
|
private val stateTotal: List<GeoLoc> = World.WWW.children.flatMap{ it.children.flatMap { itt -> itt.children } }
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StatsViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StatsViewHolder {
|
||||||
|
ctx = parent.context
|
||||||
val binding =
|
val binding =
|
||||||
ItemListGroupBinding.inflate(LayoutInflater.from(parent.context), parent, false)
|
ItemListGroupBinding.inflate(LayoutInflater.from(ctx), parent, false)
|
||||||
|
|
||||||
|
|
||||||
return StatsViewHolder(binding)
|
return StatsViewHolder(binding)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: StatsViewHolder, pos: Int) {
|
override fun onBindViewHolder(holder: StatsViewHolder, pos: Int) {
|
||||||
holder.bind(Data.groups.getGroupFromPos(pos))
|
initialSum += if (pos == itemCount - 1) {
|
||||||
|
holder.bind(Pair(AUTO_GROUP, Groups.Group(AUTO_GROUP, ctx.getString(R.string.uncategorized))))
|
||||||
|
} else {
|
||||||
|
holder.bind(Data.groups.getGroupFromPos(pos))
|
||||||
|
}
|
||||||
|
total.text = Settings.getStats(ctx, initialSum, getTotal())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount(): Int {
|
override fun getItemCount(): Int {
|
||||||
return Data.groups.size()
|
return Data.groups.size() + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getTotal(): Int {
|
||||||
|
return if (countMode) {
|
||||||
|
when (locMode) {
|
||||||
|
WORLD -> wwwTotal.size
|
||||||
|
COUNTRY -> countryTotal.size
|
||||||
|
REGION -> stateTotal.size
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
when (locMode) {
|
||||||
|
WORLD -> wwwTotal.sumOf { it.area }
|
||||||
|
COUNTRY -> countryTotal.sumOf { it.area }
|
||||||
|
REGION -> stateTotal.sumOf { it.area }
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun refreshMode(mode: String) {
|
fun refreshMode(mode: String) {
|
||||||
for (i in 0 until itemCount) {
|
val sum = (0 until itemCount).map {
|
||||||
val viewHolder = stats.findViewHolderForAdapterPosition(i) as? StatsViewHolder
|
val viewHolder = stats.findViewHolderForAdapterPosition(it) as? StatsViewHolder
|
||||||
viewHolder?.refresh(mode)
|
viewHolder?.refresh(mode)
|
||||||
}
|
}.reduce { acc, i -> acc?.plus((i ?: 0)) }
|
||||||
|
total.text = Settings.getStats(ctx, sum, getTotal())
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class StatsViewHolder(
|
inner class StatsViewHolder(
|
||||||
@ -42,13 +82,12 @@ class StatsListAdapter(private val stats: RecyclerView) :
|
|||||||
) : RecyclerView.ViewHolder(_binding.root) {
|
) : RecyclerView.ViewHolder(_binding.root) {
|
||||||
|
|
||||||
private lateinit var data: Pair<Int, Groups.Group>
|
private lateinit var data: Pair<Int, Groups.Group>
|
||||||
private var countMode: Boolean = true
|
|
||||||
private var locMode: String = "World"
|
|
||||||
|
|
||||||
private lateinit var wwwCount: List<GeoLoc>
|
private lateinit var wwwCount: List<GeoLoc>
|
||||||
private lateinit var countryCount: List<GeoLoc>
|
private lateinit var countryCount: List<GeoLoc>
|
||||||
private lateinit var stateCount: List<GeoLoc>
|
private lateinit var stateCount: List<GeoLoc>
|
||||||
fun bind(entry: Pair<Int, Groups.Group>) {
|
|
||||||
|
fun bind(entry: Pair<Int, Groups.Group>): Int {
|
||||||
data = entry
|
data = entry
|
||||||
_binding.groupColor.text = entry.second.name
|
_binding.groupColor.text = entry.second.name
|
||||||
|
|
||||||
@ -60,10 +99,10 @@ class StatsListAdapter(private val stats: RecyclerView) :
|
|||||||
|
|
||||||
_binding.groupColor.setOnClickListener {
|
_binding.groupColor.setOnClickListener {
|
||||||
countMode = !countMode
|
countMode = !countMode
|
||||||
refresh(locMode)
|
refreshMode(locMode)
|
||||||
}
|
}
|
||||||
compute()
|
compute()
|
||||||
refresh(locMode)
|
return refresh(locMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun compute() {
|
private fun compute() {
|
||||||
@ -77,24 +116,27 @@ class StatsListAdapter(private val stats: RecyclerView) :
|
|||||||
.flatten().flatten()
|
.flatten().flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun refresh(mode: String) {
|
fun refresh(mode: String): Int {
|
||||||
locMode = mode
|
locMode = mode
|
||||||
if (countMode) {
|
return if (countMode) {
|
||||||
_binding.name.text = when (locMode) {
|
val count = when (locMode) {
|
||||||
"World" -> wwwCount.size
|
WORLD -> wwwCount.size
|
||||||
"Country" -> countryCount.size
|
COUNTRY -> countryCount.size
|
||||||
"Region" -> stateCount.size
|
REGION -> stateCount.size
|
||||||
else -> "?"
|
else -> -1
|
||||||
}.toString()
|
}
|
||||||
|
_binding.name.text = count.toString()
|
||||||
|
count
|
||||||
} else {
|
} else {
|
||||||
_binding.name.text = when (locMode) {
|
val area = when (locMode) {
|
||||||
"World" -> wwwCount.sumOf { it.area }
|
WORLD -> wwwCount.sumOf { it.area }
|
||||||
"Country" -> countryCount.sumOf { it.area }
|
COUNTRY -> countryCount.sumOf { it.area }
|
||||||
"Region" -> stateCount.sumOf { it.area }
|
REGION -> stateCount.sumOf { it.area }
|
||||||
else -> "?"
|
else -> -1
|
||||||
}.toString()
|
}
|
||||||
|
_binding.name.text = area.toString()
|
||||||
|
area
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,14 @@ package net.helcel.beans.helper
|
|||||||
|
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
import android.graphics.drawable.ColorDrawable
|
import android.graphics.drawable.ColorDrawable
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.Serializer
|
import kotlinx.serialization.Serializer
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
import net.helcel.beans.R
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
import kotlin.coroutines.coroutineContext
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
|
||||||
@ -65,10 +68,6 @@ class Groups(val id: Int, private val grps: HashMap<Int, Group>) {
|
|||||||
return grps.keys.toList().indexOf(key)
|
return grps.keys.toList().indexOf(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun forEach(action: (Map.Entry<Int, Group>) -> Unit) {
|
|
||||||
grps.forEach { action(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
class EmptyGroup : Group(0, "")
|
class EmptyGroup : Group(0, "")
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -76,7 +75,7 @@ class Groups(val id: Int, private val grps: HashMap<Int, Group>) {
|
|||||||
val key: Int,
|
val key: Int,
|
||||||
val name: String,
|
val name: String,
|
||||||
@Serializable(with = Theme.ColorDrawableSerializer::class) val color: ColorDrawable = ColorDrawable(
|
@Serializable(with = Theme.ColorDrawableSerializer::class) val color: ColorDrawable = ColorDrawable(
|
||||||
Color.TRANSPARENT
|
Color.GRAY
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -44,4 +44,18 @@ object Settings {
|
|||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getStats(ctx: Context, numerator: Int?, denominator: Int?): String {
|
||||||
|
if (numerator == null || denominator == null || denominator == 0) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return when (getStatPref(ctx)) {
|
||||||
|
ctx.getString(R.string.percentages) -> ctx.getString(
|
||||||
|
R.string.percentage,
|
||||||
|
(100 * (numerator.toFloat() / denominator.toFloat())).toInt()
|
||||||
|
)
|
||||||
|
|
||||||
|
else -> ctx.getString(R.string.rate, numerator, denominator)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -49,7 +49,7 @@
|
|||||||
android:gravity="start|center_vertical"
|
android:gravity="start|center_vertical"
|
||||||
android:paddingStart="20dp"
|
android:paddingStart="20dp"
|
||||||
android:paddingEnd="52dp"
|
android:paddingEnd="52dp"
|
||||||
android:text="TODO"
|
android:text=""
|
||||||
android:textColor="?attr/colorOnPrimary"
|
android:textColor="?attr/colorOnPrimary"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/group_color"
|
app:layout_constraintBottom_toBottomOf="@id/group_color"
|
||||||
app:layout_constraintEnd_toEndOf="@id/group_color"
|
app:layout_constraintEnd_toEndOf="@id/group_color"
|
||||||
|
@ -36,4 +36,5 @@
|
|||||||
<string name="cancel">Cancel</string>
|
<string name="cancel">Cancel</string>
|
||||||
<string name="ok">Ok</string>
|
<string name="ok">Ok</string>
|
||||||
<string name="total">Total</string>
|
<string name="total">Total</string>
|
||||||
|
<string name="uncategorized">Uncategorized</string>
|
||||||
</resources>
|
</resources>
|
Loading…
x
Reference in New Issue
Block a user