Animated stat values, truncate text if needed,

This commit is contained in:
Hafiz 2022-06-24 12:43:55 -04:00
parent bd7caff14f
commit aa1ec21668
4 changed files with 94 additions and 20 deletions

View file

@ -1,7 +1,8 @@
package com.habitrpg.wearos.habitica.ui.activities package com.habitrpg.wearos.habitica.ui.activities
import android.animation.ValueAnimator
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View.*
import androidx.activity.viewModels import androidx.activity.viewModels
import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.databinding.ActivityStatsBinding import com.habitrpg.android.habitica.databinding.ActivityStatsBinding
@ -9,8 +10,10 @@ import com.habitrpg.common.habitica.views.HabiticaIconsHelper
import com.habitrpg.wearos.habitica.models.user.Stats import com.habitrpg.wearos.habitica.models.user.Stats
import com.habitrpg.wearos.habitica.models.user.User import com.habitrpg.wearos.habitica.models.user.User
import com.habitrpg.wearos.habitica.ui.viewmodels.StatsViewModel import com.habitrpg.wearos.habitica.ui.viewmodels.StatsViewModel
import com.habitrpg.wearos.habitica.ui.views.StatValue
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint @AndroidEntryPoint
class StatsActivity : BaseActivity<ActivityStatsBinding, StatsViewModel>() { class StatsActivity : BaseActivity<ActivityStatsBinding, StatsViewModel>() {
override val viewModel: StatsViewModel by viewModels() override val viewModel: StatsViewModel by viewModels()
@ -18,14 +21,36 @@ class StatsActivity : BaseActivity<ActivityStatsBinding, StatsViewModel>() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
binding = ActivityStatsBinding.inflate(layoutInflater) binding = ActivityStatsBinding.inflate(layoutInflater)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setViews()
setStatViews()
viewModel.user.observe(this) { viewModel.user.observe(this) {
updateStats(it) loadViews(it)
} }
} }
private fun setViews() {
binding.statsImageview.visibility = VISIBLE
loadingManager.startLoading()
setBarViews()
setStatViews()
}
private fun loadViews(user: User) {
binding.statsImageview.visibility = GONE
loadingManager.endLoading()
updateStats(user)
}
private fun setBarViews() {
binding.hpBar.visibility = INVISIBLE
binding.expBar.visibility = INVISIBLE
binding.mpBar.visibility = INVISIBLE
}
private fun setStatViews() { private fun setStatViews() {
binding.hpStatValue.visibility = INVISIBLE
binding.expStatValue.visibility = INVISIBLE
binding.mpStatValue.visibility = INVISIBLE
binding.hpStatValue.setStatValueResources(HabiticaIconsHelper.imageOfHeartLightBg(), R.color.hp_bar_color) binding.hpStatValue.setStatValueResources(HabiticaIconsHelper.imageOfHeartLightBg(), R.color.hp_bar_color)
binding.expStatValue.setStatValueResources(HabiticaIconsHelper.imageOfExperience(), R.color.exp_bar_color) binding.expStatValue.setStatValueResources(HabiticaIconsHelper.imageOfExperience(), R.color.exp_bar_color)
binding.mpStatValue.setStatValueResources(HabiticaIconsHelper.imageOfMagic(), R.color.mpColor) binding.mpStatValue.setStatValueResources(HabiticaIconsHelper.imageOfMagic(), R.color.mpColor)
@ -38,6 +63,10 @@ class StatsActivity : BaseActivity<ActivityStatsBinding, StatsViewModel>() {
} }
private fun updateBarViews(stats: Stats) { private fun updateBarViews(stats: Stats) {
binding.hpBar.visibility = VISIBLE
binding.expBar.visibility = VISIBLE
binding.mpBar.visibility = VISIBLE
binding.hpBar.setPercentageValues(stats.hp?.toFloat() ?: 0f, stats.maxHealth?.toFloat() ?: 0f) binding.hpBar.setPercentageValues(stats.hp?.toFloat() ?: 0f, stats.maxHealth?.toFloat() ?: 0f)
binding.hpBar.animateProgress() binding.hpBar.animateProgress()
@ -45,7 +74,7 @@ class StatsActivity : BaseActivity<ActivityStatsBinding, StatsViewModel>() {
binding.expBar.animateProgress() binding.expBar.animateProgress()
if ((stats.lvl ?: 0) < 10) { if ((stats.lvl ?: 0) < 10) {
binding.mpBar.visibility = View.GONE binding.mpBar.visibility = GONE
} else { } else {
binding.mpBar.setPercentageValues(stats.mp?.toFloat() ?: 0f, stats.maxMP?.toFloat() ?: 0f) binding.mpBar.setPercentageValues(stats.mp?.toFloat() ?: 0f, stats.maxMP?.toFloat() ?: 0f)
binding.mpBar.animateProgress() binding.mpBar.animateProgress()
@ -53,14 +82,19 @@ class StatsActivity : BaseActivity<ActivityStatsBinding, StatsViewModel>() {
} }
private fun updateStatViews(stats: Stats) { private fun updateStatViews(stats: Stats) {
binding.hpStatValue.setStatValue(stats.maxHealth ?: 0, stats.hp?.toInt() ?: 0) binding.hpStatValue.visibility = VISIBLE
binding.expStatValue.setStatValue(stats.toNextLevel ?: 0, stats.exp?.toInt() ?: 0) binding.expStatValue.visibility = VISIBLE
binding.mpStatValue.visibility = VISIBLE
binding.hpStatValue.setStatValues(stats.maxHealth ?: 0, stats.hp?.toInt() ?: 0)
binding.expStatValue.setStatValues(stats.toNextLevel ?: 0, stats.exp?.toInt() ?: 0)
if ((stats.lvl ?: 0) < 10) { if ((stats.lvl ?: 0) < 10) {
binding.mpStatValue.visibility = View.GONE binding.mpStatValue.visibility = GONE
} else { } else {
binding.mpStatValue.setStatValue(stats.maxMP ?: 0, stats.mp?.toInt() ?: 0) binding.mpStatValue.setStatValues(stats.maxMP ?: 0, stats.mp?.toInt() ?: 0)
} }
} }
} }

View file

@ -1,5 +1,6 @@
package com.habitrpg.wearos.habitica.ui.views package com.habitrpg.wearos.habitica.ui.views
import android.animation.ValueAnimator
import android.content.Context import android.content.Context
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Color import android.graphics.Color
@ -7,8 +8,15 @@ import android.util.AttributeSet
import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout
import com.habitrpg.android.habitica.databinding.StatValueLayoutBinding import com.habitrpg.android.habitica.databinding.StatValueLayoutBinding
import com.habitrpg.common.habitica.extensions.layoutInflater import com.habitrpg.common.habitica.extensions.layoutInflater
import kotlin.math.abs
import kotlin.math.ln
import kotlin.math.pow
class StatValue @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) : class StatValue @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyle: Int = 0
) :
ConstraintLayout( ConstraintLayout(
context, context,
attrs, attrs,
@ -17,10 +25,12 @@ class StatValue @JvmOverloads constructor(context: Context, attrs: AttributeSet?
var binding = StatValueLayoutBinding.inflate(context.layoutInflater, this) var binding = StatValueLayoutBinding.inflate(context.layoutInflater, this)
fun setStatValue(maxValue: Int, currentValue: Int) { fun setStatValues(maxValue: Int, currentValue: Int) {
binding.currentValue.text = currentValue.toString() binding.currentValue.text = currentValue.toString()
binding.maxValue.text = "/$maxValue" binding.maxValue.text = "/$maxValue"
invalidate() invalidate()
startUpdateCountAnimation(currentValue)
} }
fun setStatValueResources(bitmap: Bitmap, bitmapColor: Int) { fun setStatValueResources(bitmap: Bitmap, bitmapColor: Int) {
@ -30,5 +40,27 @@ class StatValue @JvmOverloads constructor(context: Context, attrs: AttributeSet?
) )
} }
private fun startUpdateCountAnimation(statValue: Int) {
val animator = ValueAnimator.ofInt(0, statValue)
animator.duration = 1000
animator.addUpdateListener { animation ->
binding.currentValue.text =
(truncateFormat(animation.animatedValue.toString().toLong()))
}
animator.start()
}
private fun truncateFormat(statCount: Long): String {
//If we want to truncate and remove text after decimal (Example 1200 -> 1k)
if (statCount < 1000) return "" + statCount
return (statCount / 1000).toString() + "k";
//If we want to truncate including text after decimal (Example 1200 -> 1.2k)
// val exp = (ln(statCount.toDouble()) / ln(1000.0)).toInt()
// binding.currentValue.letterSpacing = -.07f
// return String.format("%.1f%c", statCount / 1000.0.pow(exp.toDouble()), "kMGTPE"[exp - 1])
}
} }

View file

@ -4,6 +4,13 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<ImageView
android:id="@+id/stats_imageview"
android:layout_width="35dp"
android:layout_height="35dp"
android:src="@drawable/icon_stats"
android:layout_centerInParent="true"/>
<com.habitrpg.wearos.habitica.ui.views.CircularProgressView <com.habitrpg.wearos.habitica.ui.views.CircularProgressView
android:id="@+id/hp_bar" android:id="@+id/hp_bar"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -37,17 +44,19 @@
<com.habitrpg.wearos.habitica.ui.views.StatValue <com.habitrpg.wearos.habitica.ui.views.StatValue
android:id="@+id/hp_stat_value" android:id="@+id/hp_stat_value"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content"
android:layout_marginBottom="4dp"/>
<com.habitrpg.wearos.habitica.ui.views.StatValue <com.habitrpg.wearos.habitica.ui.views.StatValue
android:id="@+id/exp_stat_value" android:id="@+id/exp_stat_value"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_marginBottom="4dp"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<com.habitrpg.wearos.habitica.ui.views.StatValue <com.habitrpg.wearos.habitica.ui.views.StatValue
android:id="@+id/mp_stat_value" android:id="@+id/mp_stat_value"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
</LinearLayout> </LinearLayout>

View file

@ -4,8 +4,6 @@
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="30dp" android:layout_height="30dp"
android:layout_marginStart="4dp"
android:layout_marginTop="4dp"
tools:parentTag="com.habitrpg.wearos.habitica.ui.views.StatValue"> tools:parentTag="com.habitrpg.wearos.habitica.ui.views.StatValue">
<View <View
@ -21,9 +19,10 @@
<ImageView <ImageView
android:id="@+id/bitmap" android:id="@+id/bitmap"
android:layout_width="22dp" android:layout_width="18dp"
android:layout_height="22dp" android:layout_height="18dp"
android:layout_marginBottom="2dp" android:layout_marginBottom="5dp"
android:layout_marginEnd="6dp"
app:layout_constraintBottom_toBottomOf="@+id/current_value" app:layout_constraintBottom_toBottomOf="@+id/current_value"
app:layout_constraintEnd_toStartOf="@+id/current_value" app:layout_constraintEnd_toStartOf="@+id/current_value"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />