Implement fainting

This commit is contained in:
Phillip Thelen 2022-06-22 11:50:42 +02:00
parent b7742bb6c3
commit f464e61b9a
19 changed files with 226 additions and 31 deletions

View file

@ -40,9 +40,12 @@
<activity android:name="com.habitrpg.wearos.habitica.ui.activities.TaskDetailActivity" />
<activity android:name="com.habitrpg.wearos.habitica.ui.activities.HabitDirectionActivity" />
<activity android:name="com.habitrpg.wearos.habitica.ui.activities.TaskResultActivity" />
<activity android:name="com.habitrpg.wearos.habitica.ui.activities.RYAActivity" />
<activity android:name="com.habitrpg.wearos.habitica.ui.activities.AvatarActivity" />
<activity android:name="com.habitrpg.wearos.habitica.ui.activities.StatsActivity" />
<activity android:name="com.habitrpg.wearos.habitica.ui.activities.FaintActivity" />
<activity android:name="com.habitrpg.wearos.habitica.ui.activities.SettingsActivity" />
<activity android:name="androidx.wear.activity.ConfirmationActivity" />

View file

@ -1,17 +1,39 @@
package com.habitrpg.wearos.habitica
import android.app.Application
import android.content.Intent
import com.habitrpg.common.habitica.extensions.setupCoil
import com.habitrpg.common.habitica.helpers.MarkdownParser
import com.habitrpg.common.habitica.views.HabiticaIconsHelper
import com.habitrpg.wearos.habitica.data.repositories.UserRepository
import com.habitrpg.wearos.habitica.ui.activities.BaseActivity
import com.habitrpg.wearos.habitica.ui.activities.FaintActivity
import dagger.hilt.android.HiltAndroidApp
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltAndroidApp
class MainApplication : Application() {
@Inject lateinit var userRepository: UserRepository
override fun onCreate() {
super.onCreate()
HabiticaIconsHelper.init(this)
MarkdownParser.setup(this)
setupCoil()
MainScope().launch {
userRepository.getUser().onEach {
if (it.isDead && BaseActivity.currentActivityClassName != FaintActivity::class.java.name) {
val intent = Intent(this@MainApplication, FaintActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
}
}.collect()
}
}
}

View file

@ -5,6 +5,8 @@ import com.squareup.moshi.JsonClass
@JsonClass(generateAdapter = true)
class User: Avatar {
val isDead: Boolean
get() = (stats?.hp ?: 0.0) <= 0.0
override val currentMount: String?
get() = items?.currentMount
override val currentPet: String?

View file

@ -13,6 +13,9 @@ import com.habitrpg.wearos.habitica.ui.viewmodels.BaseViewModel
import com.habitrpg.wearos.habitica.ui.views.IndeterminateProgressView
abstract class BaseActivity<B: ViewBinding, VM: BaseViewModel> : ComponentActivity() {
companion object {
var currentActivityClassName: String? = null
}
private lateinit var wrapperBinding: ActivityWrapperBinding
protected lateinit var binding: B
abstract val viewModel: VM
@ -35,6 +38,11 @@ abstract class BaseActivity<B: ViewBinding, VM: BaseViewModel> : ComponentActivi
}
}
override fun onResume() {
super.onResume()
currentActivityClassName = this.localClassName
}
fun startAnimatingProgress() {
if (progressView == null) {
progressView = IndeterminateProgressView(this)

View file

@ -0,0 +1,38 @@
package com.habitrpg.wearos.habitica.ui.activities
import android.os.Bundle
import androidx.activity.viewModels
import androidx.lifecycle.lifecycleScope
import com.habitrpg.android.habitica.databinding.ActivityFaintBinding
import com.habitrpg.wearos.habitica.ui.viewmodels.FaintViewModel
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.launch
@AndroidEntryPoint
class FaintActivity: BaseActivity<ActivityFaintBinding, FaintViewModel>() {
override val viewModel: FaintViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
binding = ActivityFaintBinding.inflate(layoutInflater)
super.onCreate(savedInstanceState)
binding.continueButton.setOnClickListener {
binding.continueButton.isEnabled = false
startAnimatingProgress()
lifecycleScope.launch(CoroutineExceptionHandler { _, _ ->
stopAnimatingProgress()
binding.continueButton.isEnabled = true
}) {
viewModel.revive()
finish()
}
}
binding.hpBar.setPercentageValues(0f, 50f)
}
override fun onResume() {
super.onResume()
binding.hpBar.animateProgress(50f, 2000)
}
}

View file

@ -0,0 +1,17 @@
package com.habitrpg.wearos.habitica.ui.activities
import android.os.Bundle
import androidx.activity.viewModels
import com.habitrpg.android.habitica.databinding.ActivityRyaBinding
import com.habitrpg.wearos.habitica.ui.viewmodels.RYAViewModel
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class RYAActivity: BaseActivity<ActivityRyaBinding, RYAViewModel>() {
override val viewModel: RYAViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
binding = ActivityRyaBinding.inflate(layoutInflater)
super.onCreate(savedInstanceState)
}
}

View file

@ -38,16 +38,16 @@ class StatsActivity : BaseActivity<ActivityStatsBinding, StatsViewModel>() {
}
private fun updateBarViews(stats: Stats) {
binding.hpBar.setPercentageValues(stats.hp?.toInt() ?: 0, stats.maxHealth ?: 0)
binding.hpBar.setPercentageValues(stats.hp?.toFloat() ?: 0f, stats.maxHealth?.toFloat() ?: 0f)
binding.hpBar.animateProgress()
binding.expBar.setPercentageValues(stats.exp?.toInt() ?: 0, stats.toNextLevel ?: 0)
binding.expBar.setPercentageValues(stats.exp?.toFloat() ?: 0f, stats.toNextLevel?.toFloat() ?: 0f)
binding.expBar.animateProgress()
if ((stats.lvl ?: 0) < 10) {
binding.mpBar.visibility = View.GONE
} else {
binding.mpBar.setPercentageValues(stats.mp?.toInt() ?: 0, stats.maxMP ?: 0)
binding.mpBar.setPercentageValues(stats.mp?.toFloat() ?: 0f, stats.maxMP?.toFloat() ?: 0f)
binding.mpBar.animateProgress()
}
}

View file

@ -0,0 +1,15 @@
package com.habitrpg.wearos.habitica.ui.viewmodels
import com.habitrpg.wearos.habitica.data.repositories.UserRepository
import com.habitrpg.wearos.habitica.util.ExceptionHandlerBuilder
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@HiltViewModel
class FaintViewModel @Inject constructor(userRepository: UserRepository,
exceptionBuilder: ExceptionHandlerBuilder
) : BaseViewModel(userRepository, exceptionBuilder) {
suspend fun revive() {
userRepository.revive()
}
}

View file

@ -0,0 +1,13 @@
package com.habitrpg.wearos.habitica.ui.viewmodels
import com.habitrpg.wearos.habitica.data.repositories.UserRepository
import com.habitrpg.wearos.habitica.util.ExceptionHandlerBuilder
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@HiltViewModel
class RYAViewModel @Inject constructor(userRepository: UserRepository,
exceptionBuilder: ExceptionHandlerBuilder
) : BaseViewModel(userRepository, exceptionBuilder) {
}

View file

@ -3,12 +3,15 @@ package com.habitrpg.wearos.habitica.ui.views
import android.animation.PropertyValuesHolder
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.*
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.RectF
import android.util.AttributeSet
import android.view.View
import android.view.animation.AccelerateDecelerateInterpolator
import com.habitrpg.android.habitica.R
import com.habitrpg.common.habitica.extensions.dpToPx
class CircularProgressView(
context: Context?,
@ -16,31 +19,34 @@ class CircularProgressView(
) : View(context, attrs) {
private val ovalSpace = RectF()
private var ovalSize = (resources.displayMetrics.heightPixels / 2)
private var currentPercentage = 55
private var PERCENTAGE_DIVIDER = 180
private var currentPercentage = 55f
private var PERCENTAGE_DIVIDER = 180f
private val ARC_FULL_ROTATION_DEGREE = 360
val attributes = context?.theme?.obtainStyledAttributes(
attrs,
R.styleable.CircularProgressView,
0, 0
)
private val offset = attributes?.getInt(R.styleable.CircularProgressView_offset, 0)
private val offset = attributes?.getDimension(R.styleable.CircularProgressView_offset, 0f)?.toInt()
private val backgroundArcColor = attributes?.getColor(R.styleable.CircularProgressView_backgroundArcColor, 0) ?: Color.GRAY
private var fillArcColor = attributes?.getColor(R.styleable.CircularProgressView_arcFillColor, 0) ?: Color.GRAY
set(value) {
field = value
fillArcPaint.color = fillArcColor
}
private val parentArcPaint = Paint().apply {
style = Paint.Style.STROKE
isAntiAlias = true
color = backgroundArcColor
strokeWidth = 10f
strokeWidth = 5f.dpToPx(context)
}
private var fillArcPaint = Paint().apply {
style = Paint.Style.STROKE
isAntiAlias = true
color = fillArcColor
strokeWidth = 10f
strokeWidth = 5f.dpToPx(context)
strokeCap = Paint.Cap.ROUND
}
@ -82,36 +88,29 @@ class CircularProgressView(
fun setBarColor(barColor: Int) {
fillArcColor = context?.resources?.getColor(barColor, null) ?: backgroundArcColor
fillArcPaint = Paint().apply {
style = Paint.Style.STROKE
isAntiAlias = true
color = fillArcColor
strokeWidth = 10f
strokeCap = Paint.Cap.ROUND
}
}
fun setPercentageValues(currentValue: Int, maxValue: Int) {
fun setPercentageValues(currentValue: Float, maxValue: Float) {
currentPercentage = currentValue
PERCENTAGE_DIVIDER = maxValue
}
fun animateProgress() {
val currentPercent: Int = currentPercentage
fun animateProgress(startValue: Float = 0f, animationDuration: Long = 1000) {
val currentPercent = currentPercentage
val valuesHolder = PropertyValuesHolder.ofFloat(
PERCENTAGE_VALUE_HOLDER,
1f,
startValue,
currentPercent.toFloat()
)
val animator = ValueAnimator().apply {
setValues(valuesHolder)
duration = 1000
duration = animationDuration
interpolator = AccelerateDecelerateInterpolator()
addUpdateListener {
val percentage = it.getAnimatedValue(PERCENTAGE_VALUE_HOLDER) as Float
currentPercentage = percentage.toInt()
currentPercentage = percentage
invalidate()
}
}
@ -122,6 +121,6 @@ class CircularProgressView(
const val PERCENTAGE_VALUE_HOLDER = "percentage"
}
private fun getCurrentAngleToFill() = if(currentPercentage > 0) {(ARC_FULL_ROTATION_DEGREE.toFloat() * (currentPercentage.toFloat() / PERCENTAGE_DIVIDER.toFloat()))} else {1f}
private fun getCurrentAngleToFill() = if(currentPercentage > 0) {(ARC_FULL_ROTATION_DEGREE.toFloat() * (currentPercentage / PERCENTAGE_DIVIDER))} else {1f}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6 KiB

View file

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.habitrpg.wearos.habitica.ui.views.CircularProgressView
android:id="@+id/hp_bar"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:arcFillColor="@color/hp_bar_color"
app:backgroundArcColor="@color/bar_background_color"
app:offset="4dp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:layout_gravity="center">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/broken_heart"
android:layout_marginBottom="@dimen/spacing_medium"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/you_ran_out_of_hp"
android:gravity="center"
android:textColor="@color/white"
style="@style/Text.Subheader1"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/faint_description"
android:textColor="@color/watch_gray_500"
android:textSize="14sp"
android:layout_marginBottom="@dimen/spacing_large"
android:gravity="center"/>
<Button
android:id="@+id/continue_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/continue_text"
style="@style/ChipButton.Small.Red"/>
</LinearLayout>
</FrameLayout>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>

View file

@ -10,7 +10,7 @@
android:layout_height="match_parent"
app:arcFillColor="@color/hp_bar_color"
app:backgroundArcColor="@color/bar_background_color"
app:offset="10" />
app:offset="5dp" />
<com.habitrpg.wearos.habitica.ui.views.CircularProgressView
android:id="@+id/exp_bar"
@ -18,7 +18,7 @@
android:layout_height="match_parent"
app:arcFillColor="@color/exp_bar_color"
app:backgroundArcColor="@color/bar_background_color"
app:offset="28" />
app:offset="14dp" />
<com.habitrpg.wearos.habitica.ui.views.CircularProgressView
android:id="@+id/mp_bar"
@ -26,7 +26,7 @@
android:layout_height="match_parent"
app:arcFillColor="@color/mp_bar_color"
app:backgroundArcColor="@color/bar_background_color"
app:offset="46" />
app:offset="23dp" />
<LinearLayout
android:layout_width="wrap_content"

View file

@ -5,7 +5,7 @@
<attr name="drawFromTop" format="boolean" />
</declare-styleable>
<declare-styleable name="CircularProgressView">
<attr name="offset" format="integer" />
<attr name="offset" format="dimension" />
<attr name="backgroundArcColor" format="color" />
<attr name="arcFillColor" format="color" />
</declare-styleable>

View file

@ -14,4 +14,7 @@
<string name="other_options">Other options</string>
<string name="create_account">Create account</string>
<string name="sign_in_password">Sign in with password</string>
<string name="continue_text">Continue</string>
<string name="you_ran_out_of_hp">You ran out of HP</string>
<string name="faint_description">You lost a Level, Exp, and Gold. Dont give up!</string>
</resources>

View file

@ -18,19 +18,40 @@
<item name="android:paddingVertical">@dimen/row_padding_vertical</item>
<item name="android:background">@drawable/row_background</item>
<item name="android:textSize">14sp</item>
<item name="fontFamily">@string/medium</item>
<item name="fontFamily">sans-serif-medium</item>
<item name="android:gravity">center</item>
<item name="android:minHeight">52dp</item>
<item name="android:textAllCaps">false</item>
<item name="android:letterSpacing">0.05</item>
<item name="android:drawablePadding">8dp</item>
<item name="android:foreground">?selectableItemBackground</item>
</style>
<style name="ChipButton.Small">
<item name="android:paddingHorizontal">@dimen/row_padding_horizontal</item>
<item name="android:paddingVertical">@dimen/row_padding_vertical</item>
<item name="android:background">@drawable/row_background</item>
<item name="android:textSize">14sp</item>
<item name="fontFamily">sans-serif-medium</item>
<item name="android:gravity">center</item>
<item name="android:minHeight">32dp</item>
<item name="android:textAllCaps">false</item>
<item name="android:letterSpacing">0.05</item>
<item name="android:drawablePadding">8dp</item>
</style>
<style name="ChipButton.Purple">
<item name="android:backgroundTint">@color/watch_purple_100</item>
</style>
<style name="ChipButton.Red">
<item name="android:backgroundTint">@color/watch_red_200</item>
</style>
<style name="ChipButton.Small.Red">
<item name="android:backgroundTint">@color/watch_red_200</item>
<item name="android:textColor">@color/black</item>
</style>
<style name="Text" />
<style name="Text.Subheader1">