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