diff --git a/Habitica/res/drawable-hdpi/icon_lock.png b/Habitica/res/drawable-hdpi/icon_lock.png
new file mode 100644
index 000000000..e83bc8636
Binary files /dev/null and b/Habitica/res/drawable-hdpi/icon_lock.png differ
diff --git a/Habitica/res/drawable-hdpi/shop_locked.png b/Habitica/res/drawable-hdpi/shop_locked.png
deleted file mode 100644
index 21c480b88..000000000
Binary files a/Habitica/res/drawable-hdpi/shop_locked.png and /dev/null differ
diff --git a/Habitica/res/drawable-mdpi/icon_lock.png b/Habitica/res/drawable-mdpi/icon_lock.png
new file mode 100644
index 000000000..181b86336
Binary files /dev/null and b/Habitica/res/drawable-mdpi/icon_lock.png differ
diff --git a/Habitica/res/drawable-xhdpi/icon_lock.png b/Habitica/res/drawable-xhdpi/icon_lock.png
new file mode 100644
index 000000000..70e12a938
Binary files /dev/null and b/Habitica/res/drawable-xhdpi/icon_lock.png differ
diff --git a/Habitica/res/drawable-xhdpi/shop_locked.png b/Habitica/res/drawable-xhdpi/shop_locked.png
deleted file mode 100644
index 29ed84289..000000000
Binary files a/Habitica/res/drawable-xhdpi/shop_locked.png and /dev/null differ
diff --git a/Habitica/res/drawable-xxhdpi/icon_lock.png b/Habitica/res/drawable-xxhdpi/icon_lock.png
new file mode 100644
index 000000000..7a694af4b
Binary files /dev/null and b/Habitica/res/drawable-xxhdpi/icon_lock.png differ
diff --git a/Habitica/res/drawable-xxhdpi/shop_locked.png b/Habitica/res/drawable-xxhdpi/shop_locked.png
deleted file mode 100644
index a3aab0006..000000000
Binary files a/Habitica/res/drawable-xxhdpi/shop_locked.png and /dev/null differ
diff --git a/Habitica/res/drawable/shop_locked.xml b/Habitica/res/drawable/shop_locked.xml
new file mode 100644
index 000000000..59cfd6f02
--- /dev/null
+++ b/Habitica/res/drawable/shop_locked.xml
@@ -0,0 +1,14 @@
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
diff --git a/Habitica/res/layout/activity_armoire.xml b/Habitica/res/layout/activity_armoire.xml
index 4c448b16a..34e05f5e7 100644
--- a/Habitica/res/layout/activity_armoire.xml
+++ b/Habitica/res/layout/activity_armoire.xml
@@ -85,6 +85,7 @@
android:textStyle="bold"
android:textSize="28sp"
android:gravity="center"
+ android:alpha="0"
android:textColor="@color/text_primary"/>
-
-
+ android:layout_height="65dp"
+ android:paddingStart="24dp"
+ android:paddingEnd="18dp">
+
+
+
-
+ android:text="@string/subscription_benefit_armoire_sub"
+ android:textColor="@color/white"
+ style="@style/Body2"
+ android:gravity="center"
+ android:paddingHorizontal="48dp"
+ android:layout_marginTop="6dp"/>
+
+ android:textColor="@color/text_secondary"
+ android:paddingVertical="2dp"/>
-
\ No newline at end of file
+
diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml
index f374adcf3..66ce8ca01 100644
--- a/Habitica/res/values/strings.xml
+++ b/Habitica/res/values/strings.xml
@@ -1457,6 +1457,7 @@
Invited to Group Plan
\@Mentions in Group Plans
Subscribe to hold on with 1HP!
+ Your subscription gives you an extra chance at the Armoire!
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ArmoireActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ArmoireActivity.kt
index 0bb373701..edc53c761 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ArmoireActivity.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ArmoireActivity.kt
@@ -36,6 +36,7 @@ import com.habitrpg.common.habitica.helpers.launchCatching
import com.plattysoft.leonids.ParticleSystem
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.launch
import java.util.Locale
@@ -173,8 +174,36 @@ class ArmoireActivity : BaseActivity() {
}
private fun giveUserArmoire(): Boolean {
+ binding.iconWrapper.post {
+ binding.iconView.bitmap = null
+ Animations.circularHide(binding.iconWrapper)
+ }
+ binding.titleView.animate().apply {
+ alpha(0f)
+ duration = 300
+ startDelay = 0
+ start()
+ }
+ binding.subtitleView.animate().apply {
+ alpha(0f)
+ duration = 300
+ startDelay = 0
+ start()
+ }
+
+ binding.goldView.animate().apply {
+ alpha(0f)
+ start()
+ }
+
val user = userViewModel.user.value ?: return true
val currentGold = user.stats?.gp ?: return true
+ if (binding.adButton.visibility == View.VISIBLE) {
+ binding.adButton.state = AdButton.State.UNAVAILABLE
+ binding.adButton.visibility = View.INVISIBLE
+ } else if (binding.openArmoireSubscriberWrapper.visibility == View.VISIBLE) {
+ binding.openArmoireSubscriberWrapper.visibility = View.INVISIBLE
+ }
lifecycleScope.launch(ExceptionHandler.coroutine()) {
userRepository.updateUser("stats.gp", currentGold + 100)
val buyResponse =
@@ -185,27 +214,25 @@ class ArmoireActivity : BaseActivity() {
buyResponse.armoire["dropText"] ?: "",
buyResponse.armoire["value"] ?: ""
)
- if (binding.adButton.visibility == View.VISIBLE) {
- binding.adButton.state = AdButton.State.UNAVAILABLE
- binding.adButton.visibility = View.INVISIBLE
- } else if (binding.openArmoireSubscriberWrapper.visibility == View.VISIBLE) {
- binding.openArmoireSubscriberWrapper.visibility = View.INVISIBLE
- }
hasAnimatedChanges = false
gold = null
+ startAnimation(false)
}
return false
}
override fun onResume() {
super.onResume()
- startAnimation()
+ lifecycleScope.launchCatching {
+ delay(500L)
+ startAnimation(true)
+ }
}
- private fun startAnimation() {
+ private fun startAnimation(decreaseGold: Boolean) {
val gold = gold?.toInt()
if (hasAnimatedChanges) return
- if (gold != null) {
+ if (gold != null && decreaseGold) {
/**
* We are adding 100 as the gold is already "deducted" before the animation starts,
* and animating to show the current user's gold amount.
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyDetailFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyDetailFragment.kt
index 408921dc9..b8621fef8 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyDetailFragment.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/social/party/PartyDetailFragment.kt
@@ -291,7 +291,7 @@ class PartyDetailFragment : BaseFragment() {
binding?.questParticipationView?.setTextColor(
ContextCompat.getColor(
it,
- R.color.text_quad
+ R.color.text_ternary
)
)
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/MountViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/MountViewHolder.kt
index 0bc6bae05..5bb436e8d 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/MountViewHolder.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/MountViewHolder.kt
@@ -1,5 +1,6 @@
package com.habitrpg.android.habitica.ui.viewHolders
+import android.app.Activity
import android.content.res.Resources
import android.graphics.drawable.BitmapDrawable
import android.view.View
@@ -11,7 +12,11 @@ import com.habitrpg.android.habitica.extensions.inflate
import com.habitrpg.android.habitica.models.inventory.Mount
import com.habitrpg.android.habitica.ui.menu.BottomSheetMenu
import com.habitrpg.android.habitica.ui.menu.BottomSheetMenuItem
+import com.habitrpg.android.habitica.ui.views.showAsBottomSheet
+import com.habitrpg.android.habitica.ui.views.stable.MountBottomSheet
+import com.habitrpg.android.habitica.ui.views.stable.PetBottomSheet
import com.habitrpg.common.habitica.extensions.DataBindingUtils
+import dagger.hilt.android.internal.managers.ViewComponentManager
class MountViewHolder(parent: ViewGroup, private val onEquip: ((String) -> Unit)?) : androidx.recyclerview.widget.RecyclerView.ViewHolder(parent.inflate(R.layout.mount_overview_item)), View.OnClickListener {
private var binding: MountOverviewItemBinding = MountOverviewItemBinding.bind(itemView)
@@ -51,16 +56,20 @@ class MountViewHolder(parent: ViewGroup, private val onEquip: ((String) -> Unit)
if (!owned) {
return
}
- val menu = BottomSheetMenu(itemView.context)
- menu.setTitle(animal?.text)
- menu.setImage("stable_Mount_Icon_" + animal?.animal + "-" + animal?.color)
-
- val hasCurrentMount = currentMount.equals(animal?.key)
- val labelId = if (hasCurrentMount) R.string.unequip else R.string.equip
- menu.addMenuItem(BottomSheetMenuItem(resources.getString(labelId)))
- menu.setSelectionRunnable {
- animal?.let { onEquip?.invoke(it.key ?: "") }
+ val context = itemView.context
+ animal?.let { pet ->
+ (if (context is ViewComponentManager.FragmentContextWrapper) {
+ context.baseContext
+ } else {
+ context
+ }as Activity).showAsBottomSheet {
+ MountBottomSheet(
+ pet,
+ currentMount.equals(animal?.key),
+ onEquip,
+ it
+ )
+ }
}
- menu.show()
}
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/ShopItemViewHolder.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/ShopItemViewHolder.kt
index 1e9f9d804..15af97893 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/ShopItemViewHolder.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/ShopItemViewHolder.kt
@@ -72,8 +72,7 @@ class ShopItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), Vi
binding.itemDetailIndicator.background =
AppCompatResources.getDrawable(context, R.drawable.pill_bg_gray)
binding.itemDetailIndicator.visibility = View.VISIBLE
- }
- if (item.locked) {
+ } else if (item.locked) {
binding.itemDetailIndicator.background = AppCompatResources.getDrawable(context, R.drawable.shop_locked)
binding.itemDetailIndicator.visibility = View.VISIBLE
} else if (isLimited) {
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/BackgroundScene.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/BackgroundScene.kt
new file mode 100644
index 000000000..68b596bf8
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/BackgroundScene.kt
@@ -0,0 +1,73 @@
+package com.habitrpg.android.habitica.ui.views
+
+import android.graphics.Bitmap
+import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.graphics.ImageShader
+import androidx.compose.ui.graphics.Paint
+import androidx.compose.ui.graphics.TileMode
+import androidx.compose.ui.graphics.asAndroidBitmap
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
+import androidx.compose.ui.graphics.nativeCanvas
+import androidx.compose.ui.res.imageResource
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.zIndex
+import com.habitrpg.android.habitica.R
+import java.util.Calendar
+
+@Composable
+private fun getBackgroundPainter(): ImageBitmap {
+ val calendar = Calendar.getInstance()
+ val month = calendar.get(Calendar.MONTH)
+ return ImageBitmap.imageResource(
+ when (month) {
+ Calendar.JANUARY -> R.drawable.stable_tile_janurary
+ Calendar.FEBRUARY -> R.drawable.stable_tile_february
+ Calendar.MARCH -> R.drawable.stable_tile_march
+ Calendar.APRIL -> R.drawable.stable_tile_april
+ Calendar.MAY -> R.drawable.stable_tile_may
+ Calendar.JUNE -> R.drawable.stable_tile_june
+ Calendar.JULY -> R.drawable.stable_tile_july
+ Calendar.AUGUST -> R.drawable.stable_tile_august
+ Calendar.SEPTEMBER -> R.drawable.stable_tile_september
+ Calendar.OCTOBER -> R.drawable.stable_tile_october
+ Calendar.NOVEMBER -> R.drawable.stable_tile_november
+ Calendar.DECEMBER -> R.drawable.stable_tile_december
+ else -> R.drawable.stable_tile_may
+ }
+ )
+}
+
+@Composable
+fun BackgroundScene() {
+ val image = getBackgroundPainter()
+ Canvas(
+ modifier = Modifier
+ .height(124.dp)
+ .fillMaxWidth()
+ .zIndex(1f), onDraw = {
+ val bitmap = Bitmap.createScaledBitmap(
+ image.asAndroidBitmap(),
+ image.width.dp.roundToPx(),
+ 124.dp.roundToPx(),
+ false
+ )
+ val paint = Paint().asFrameworkPaint().apply {
+ isAntiAlias = true
+ shader = ImageShader(
+ bitmap.asImageBitmap(),
+ TileMode.Repeated,
+ TileMode.Repeated
+ )
+ }
+ drawIntoCanvas {
+ it.nativeCanvas.drawPaint(paint)
+ }
+ paint.reset()
+ })
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/HabiticaButton.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/HabiticaButton.kt
index affa2b626..ff9d5b67b 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/HabiticaButton.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/HabiticaButton.kt
@@ -31,8 +31,8 @@ fun HabiticaButton(
Box(
contentAlignment = Alignment.Center,
modifier = modifier
- .clickable { onClick() }
.background(background, HabiticaTheme.shapes.medium)
+ .clickable { onClick() }
.fillMaxWidth()
.padding(contentPadding)
) {
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/stable/MountBottomSheet.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/stable/MountBottomSheet.kt
new file mode 100644
index 000000000..0fe089a15
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/stable/MountBottomSheet.kt
@@ -0,0 +1,179 @@
+package com.habitrpg.android.habitica.ui.views.stable
+
+import com.habitrpg.android.habitica.models.inventory.Animal
+import com.habitrpg.android.habitica.models.inventory.Mount
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.core.CubicBezierEasing
+import androidx.compose.animation.core.FastOutSlowInEasing
+import androidx.compose.animation.core.LinearOutSlowInEasing
+import androidx.compose.animation.core.RepeatMode
+import androidx.compose.animation.core.StartOffset
+import androidx.compose.animation.core.animateFloat
+import androidx.compose.animation.core.animateFloatAsState
+import androidx.compose.animation.core.infiniteRepeatable
+import androidx.compose.animation.core.keyframes
+import androidx.compose.animation.core.rememberInfiniteTransition
+import androidx.compose.animation.core.tween
+import androidx.compose.animation.fadeIn
+import androidx.compose.animation.fadeOut
+import androidx.compose.animation.scaleIn
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.offset
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.material.LinearProgressIndicator
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
+import androidx.compose.ui.draw.clip
+import androidx.compose.ui.draw.scale
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.graphics.StrokeCap
+import androidx.compose.ui.res.imageResource
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import androidx.compose.ui.zIndex
+import com.habitrpg.android.habitica.R
+import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
+import com.habitrpg.android.habitica.ui.views.BackgroundScene
+import com.habitrpg.android.habitica.ui.views.HabiticaButton
+import java.util.Calendar
+import kotlin.math.sin
+
+@Composable
+private fun getBackgroundPainter(): ImageBitmap {
+ val calendar = Calendar.getInstance()
+ val month = calendar.get(Calendar.MONTH)
+ return ImageBitmap.imageResource(
+ when (month) {
+ Calendar.JANUARY -> R.drawable.stable_tile_janurary
+ Calendar.FEBRUARY -> R.drawable.stable_tile_february
+ Calendar.MARCH -> R.drawable.stable_tile_march
+ Calendar.APRIL -> R.drawable.stable_tile_april
+ Calendar.MAY -> R.drawable.stable_tile_may
+ Calendar.JUNE -> R.drawable.stable_tile_june
+ Calendar.JULY -> R.drawable.stable_tile_july
+ Calendar.AUGUST -> R.drawable.stable_tile_august
+ Calendar.SEPTEMBER -> R.drawable.stable_tile_september
+ Calendar.OCTOBER -> R.drawable.stable_tile_october
+ Calendar.NOVEMBER -> R.drawable.stable_tile_november
+ Calendar.DECEMBER -> R.drawable.stable_tile_december
+ else -> R.drawable.stable_tile_may
+ }
+ )
+}
+
+@Composable
+fun MountBottomSheet(
+ mount: Mount,
+ isCurrentMount: Boolean,
+ onEquip: ((String) -> Unit)?,
+ onDismiss: () -> Unit,
+ modifier: Modifier = Modifier
+) {
+ val infiniteTransition = rememberInfiniteTransition()
+
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier = modifier.padding(horizontal = 22.dp)
+ ) {
+ Text(
+ mount.text ?: "",
+ fontSize = 16.sp,
+ fontWeight = FontWeight.Medium,
+ color = HabiticaTheme.colors.textTertiary
+ )
+ Box(
+ modifier = Modifier
+ .padding(top = 9.dp, bottom = 16.dp)
+ .fillMaxWidth()
+ .height(124.dp)
+ .clip(HabiticaTheme.shapes.medium)
+ ) {
+ BackgroundScene()
+
+ val regularPosition = 33f
+ val highJump = 22f
+ val lowJump = 30f
+ val position by if (isAnimalFlying(mount)) {
+ infiniteTransition.animateFloat(
+ initialValue = 24f,
+ targetValue = 16f,
+ animationSpec = infiniteRepeatable(
+ tween(
+ 2500,
+ easing = CubicBezierEasing(0.3f, 0.0f, 0.2f, 1.0f)
+ ), RepeatMode.Reverse
+ ),
+ label = "animalPosition"
+ )
+ } else {
+ infiniteTransition.animateFloat(
+ initialValue = regularPosition,
+ targetValue = highJump,
+ animationSpec = infiniteRepeatable(animation = keyframes {
+ durationMillis = 6000
+ regularPosition at 0 with LinearOutSlowInEasing
+ highJump at 150 with LinearOutSlowInEasing
+ regularPosition at 300 with FastOutSlowInEasing
+ regularPosition at 1800 with FastOutSlowInEasing
+ lowJump at 1850 with LinearOutSlowInEasing
+ regularPosition at 1900 with LinearOutSlowInEasing
+ regularPosition at 2100 with FastOutSlowInEasing
+ lowJump at 2200 with LinearOutSlowInEasing
+ regularPosition at 2350 with LinearOutSlowInEasing
+ regularPosition at 6000
+ }, RepeatMode.Restart, StartOffset(1500)), label = "animalPosition"
+ )
+ }
+ MountView(mount, modifier = Modifier
+ .offset(0.dp, position.dp)
+ .size(68.dp)
+ .align(Alignment.TopCenter)
+ .zIndex(2f)
+ )
+ }
+ HabiticaButton(
+ background = HabiticaTheme.colors.tintedUiSub,
+ color = Color.White,
+ contentPadding = PaddingValues(12.dp),
+ onClick = {
+ onEquip?.invoke(mount.key)
+ onDismiss()
+ }) {
+ if (isCurrentMount) {
+ Text(stringResource(id = R.string.unequip))
+ } else {
+ Text(stringResource(id = R.string.equip))
+ }
+ }
+ }
+}
+
+fun isAnimalFlying(animal: Animal): Boolean {
+ if (listOf(
+ "FlyingPig",
+ "Bee"
+ ).contains(animal.animal)
+ ) return true
+ return listOf(
+ "Ghost",
+ "Cupid",
+ "Fairy",
+ "SolarSystem",
+ "Vampire"
+ ).contains(animal.color)
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/stable/MountView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/stable/MountView.kt
new file mode 100644
index 000000000..68c66e2f2
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/stable/MountView.kt
@@ -0,0 +1,48 @@
+package com.habitrpg.android.habitica.ui.views.stable
+
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.FrameLayout
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.asAndroidBitmap
+import androidx.compose.ui.viewinterop.AndroidView
+import com.habitrpg.android.habitica.models.inventory.Mount
+import com.habitrpg.common.habitica.extensions.loadImage
+import com.habitrpg.common.habitica.views.PixelArtView
+
+class MountView @JvmOverloads constructor(
+ context: Context, attrs: AttributeSet? = null
+) : FrameLayout(context, attrs) {
+
+ private val bodyView: PixelArtView = PixelArtView(context)
+ private val headView: PixelArtView = PixelArtView(context)
+
+ fun setMount(key: String) {
+ bodyView.loadImage("Mount_Body_$key")
+ headView.loadImage("Mount_Head_$key")
+ }
+
+ init {
+ addView(bodyView)
+ addView(headView)
+ }
+}
+
+@Composable
+fun MountView(mount: Mount, modifier: Modifier = Modifier) {
+ MountView(mount.key, modifier)
+}
+
+@Composable
+fun MountView(mountKey: String, modifier: Modifier = Modifier) {
+ AndroidView(
+ modifier = modifier,
+ factory = { context ->
+ MountView(context)
+ },
+ update = { view ->
+ view.setMount(mountKey)
+ }
+ )
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/stable/PetBottomSheet.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/stable/PetBottomSheet.kt
index d34b1ff36..7ba70dbae 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/stable/PetBottomSheet.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/stable/PetBottomSheet.kt
@@ -55,6 +55,7 @@ import androidx.compose.ui.graphics.asAndroidBitmap
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.nativeCanvas
+import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.imageResource
import androidx.compose.ui.res.stringResource
@@ -67,38 +68,16 @@ import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.models.inventory.Food
import com.habitrpg.android.habitica.models.inventory.Pet
import com.habitrpg.android.habitica.ui.theme.HabiticaTheme
+import com.habitrpg.android.habitica.ui.views.BackgroundScene
import com.habitrpg.android.habitica.ui.views.HabiticaButton
import com.habitrpg.android.habitica.ui.views.PixelArtView
+import com.habitrpg.common.habitica.extensions.getThemeColor
import com.habitrpg.common.habitica.helpers.MainNavigationController
import com.habitrpg.common.habitica.helpers.launchCatching
import com.habitrpg.shared.habitica.models.responses.FeedResponse
import kotlinx.coroutines.delay
-import java.util.Calendar
import kotlin.math.sin
-@Composable
-private fun getBackgroundPainter(): ImageBitmap {
- val calendar = Calendar.getInstance()
- val month = calendar.get(Calendar.MONTH)
- return ImageBitmap.imageResource(
- when (month) {
- Calendar.JANUARY -> R.drawable.stable_tile_janurary
- Calendar.FEBRUARY -> R.drawable.stable_tile_february
- Calendar.MARCH -> R.drawable.stable_tile_march
- Calendar.APRIL -> R.drawable.stable_tile_april
- Calendar.MAY -> R.drawable.stable_tile_may
- Calendar.JUNE -> R.drawable.stable_tile_june
- Calendar.JULY -> R.drawable.stable_tile_july
- Calendar.AUGUST -> R.drawable.stable_tile_august
- Calendar.SEPTEMBER -> R.drawable.stable_tile_september
- Calendar.OCTOBER -> R.drawable.stable_tile_october
- Calendar.NOVEMBER -> R.drawable.stable_tile_november
- Calendar.DECEMBER -> R.drawable.stable_tile_december
- else -> R.drawable.stable_tile_may
- }
- )
-}
-
@Composable
private fun getFoodPainter(petColor: String): ImageBitmap {
return ImageBitmap.imageResource(
@@ -152,7 +131,6 @@ fun PetBottomSheet(
fontWeight = FontWeight.Medium,
color = HabiticaTheme.colors.textTertiary
)
- val image = getBackgroundPainter()
Box(
modifier = Modifier
.padding(top = 9.dp, bottom = 16.dp)
@@ -160,30 +138,7 @@ fun PetBottomSheet(
.height(124.dp)
.clip(HabiticaTheme.shapes.medium)
) {
- Canvas(
- modifier = Modifier
- .height(124.dp)
- .fillMaxWidth()
- .zIndex(1f), onDraw = {
- val bitmap = Bitmap.createScaledBitmap(
- image.asAndroidBitmap(),
- image.width.dp.roundToPx(),
- 124.dp.roundToPx(),
- false
- )
- val paint = Paint().asFrameworkPaint().apply {
- isAntiAlias = true
- shader = ImageShader(
- bitmap.asImageBitmap(),
- TileMode.Repeated,
- TileMode.Repeated
- )
- }
- drawIntoCanvas {
- it.nativeCanvas.drawPaint(paint)
- }
- paint.reset()
- })
+ BackgroundScene()
this@Column.AnimatedVisibility(
visible = showFeedResponse, modifier = Modifier
@@ -298,7 +253,7 @@ fun PetBottomSheet(
modifier = Modifier.padding(bottom = 16.dp)
) {
HabiticaButton(
- colorResource(id = R.color.offset_background_30),
+ Color(LocalContext.current.getThemeColor(R.attr.colorTintedBackgroundOffset)),
HabiticaTheme.colors.textPrimary,
onClick = {
if (ownsSaddles) {
@@ -324,7 +279,7 @@ fun PetBottomSheet(
}
}
HabiticaButton(
- colorResource(id = R.color.offset_background_30),
+ Color(LocalContext.current.getThemeColor(R.attr.colorTintedBackgroundOffset)),
HabiticaTheme.colors.textPrimary,
onClick = {
coroutineScope.launchCatching {
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/form/TaskSchedulingControls.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/form/TaskSchedulingControls.kt
index 368f95f43..fca57d36d 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/form/TaskSchedulingControls.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/tasks/form/TaskSchedulingControls.kt
@@ -3,6 +3,7 @@ package com.habitrpg.android.habitica.ui.views.tasks.form
import android.app.DatePickerDialog
import android.content.Context
import android.content.DialogInterface
+import android.content.res.ColorStateList
import android.icu.text.MessageFormat
import android.os.Build
import android.text.TextUtils
@@ -321,14 +322,14 @@ class TaskSchedulingControls @JvmOverloads constructor(
}
private fun styleButtonAsActive(button: TextView) {
- button.setTextColor(context.getThemeColor(R.attr.colorTintedBackground))
- button.background.mutate().setTint(tintColor)
+ button.setTextColor(context.getThemeColor(R.attr.tintedUiDetails))
+ button.backgroundTintList = ColorStateList.valueOf(context.getThemeColor(R.attr.tintedUiMain))
button.contentDescription = toContentDescription(button.text, true)
}
private fun styleButtonAsInactive(button: TextView) {
- button.setTextColor(context.getThemeColor(R.attr.colorPrimaryDark))
- button.background.mutate().setTint(context.getThemeColor(R.attr.colorTintedBackgroundOffset))
+ button.setTextColor(context.getThemeColor(R.attr.textColorTintedSecondary))
+ button.backgroundTintList = ColorStateList.valueOf(context.getThemeColor(R.attr.colorTintedBackgroundOffset))
button.contentDescription = toContentDescription(button.text, false)
}
diff --git a/common/src/main/java/com/habitrpg/common/habitica/extensions/DataBindingUtils.kt b/common/src/main/java/com/habitrpg/common/habitica/extensions/DataBindingUtils.kt
index c19de6748..2e4322fd1 100644
--- a/common/src/main/java/com/habitrpg/common/habitica/extensions/DataBindingUtils.kt
+++ b/common/src/main/java/com/habitrpg/common/habitica/extensions/DataBindingUtils.kt
@@ -153,6 +153,7 @@ object DataBindingUtils {
tempMap["shield_special_ks2019"] = "gif"
tempMap["weapon_special_ks2019"] = "gif"
tempMap["Pet-Gryphon-Gryphatrice"] = "gif"
+ tempMap["stable_Pet-Gryphon-Gryphatrice"] = "gif"
tempMap["Mount_Head_Gryphon-Gryphatrice"] = "gif"
tempMap["Mount_Body_Gryphon-Gryphatrice"] = "gif"
tempMap["background_clocktower"] = "gif"
diff --git a/common/src/main/java/com/habitrpg/common/habitica/helpers/Animations.kt b/common/src/main/java/com/habitrpg/common/habitica/helpers/Animations.kt
index b746c08a7..478c02369 100644
--- a/common/src/main/java/com/habitrpg/common/habitica/helpers/Animations.kt
+++ b/common/src/main/java/com/habitrpg/common/habitica/helpers/Animations.kt
@@ -61,11 +61,13 @@ object Animations {
anim.start()
}
- fun circularHide(view: View) {
+ fun circularHide(view: View, duration: Long = 300) {
val cx = view.width / 2
val cy = view.height / 2
val initialRadius = Math.hypot(cx.toDouble(), cy.toDouble()).toFloat()
val anim = ViewAnimationUtils.createCircularReveal(view, cx, cy, initialRadius, 0f)
+ anim.duration = duration
+ anim.interpolator = AccelerateInterpolator()
anim.doOnEnd {
view.visibility = View.INVISIBLE
}
diff --git a/common/src/main/java/com/habitrpg/common/habitica/views/ValueBar.kt b/common/src/main/java/com/habitrpg/common/habitica/views/ValueBar.kt
index 0ceeeef42..fda887a2f 100644
--- a/common/src/main/java/com/habitrpg/common/habitica/views/ValueBar.kt
+++ b/common/src/main/java/com/habitrpg/common/habitica/views/ValueBar.kt
@@ -84,7 +84,7 @@ class ValueBar(context: Context, attrs: AttributeSet?) : FrameLayout(context, at
private fun updateBar() {
binding.progressBar.set(currentValue, maxValue)
binding.progressBar.pendingValue = pendingValue
- setValueText(formatter.format(currentValue) + " / " + formatter.format(maxValue.toInt()) + " " + valueSuffix)
+ setValueText(formatter.format(currentValue) + " / " + formatter.format(maxValue.toInt()) + " " + (valueSuffix ?: ""))
}
init {
diff --git a/version.properties b/version.properties
index 406f1a950..98dc2e560 100644
--- a/version.properties
+++ b/version.properties
@@ -1,2 +1,2 @@
NAME=4.3
-CODE=6471
\ No newline at end of file
+CODE=6491
\ No newline at end of file