add sheet for mounts
BIN
Habitica/res/drawable-hdpi/icon_lock.png
Normal file
|
After Width: | Height: | Size: 418 B |
|
Before Width: | Height: | Size: 1.5 KiB |
BIN
Habitica/res/drawable-mdpi/icon_lock.png
Normal file
|
After Width: | Height: | Size: 331 B |
BIN
Habitica/res/drawable-xhdpi/icon_lock.png
Normal file
|
After Width: | Height: | Size: 495 B |
|
Before Width: | Height: | Size: 2.2 KiB |
BIN
Habitica/res/drawable-xxhdpi/icon_lock.png
Normal file
|
After Width: | Height: | Size: 664 B |
|
Before Width: | Height: | Size: 3.5 KiB |
14
Habitica/res/drawable/shop_locked.xml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:width="24dp" android:height="24dp">
|
||||
<shape>
|
||||
<solid android:color="@color/offset_background"/>
|
||||
<corners android:radius="20dip"/>
|
||||
<padding android:left="0dip" android:top="0dip" android:right="0dip" android:bottom="0dip" />
|
||||
</shape>
|
||||
</item>
|
||||
<item android:width="10dp" android:height="12dp" android:gravity="center">
|
||||
<bitmap android:src="@drawable/icon_lock" android:tintMode="src_atop" android:tint="@color/text_quad">
|
||||
</bitmap>
|
||||
</item>
|
||||
</layer-list>
|
||||
|
|
@ -85,6 +85,7 @@
|
|||
android:textStyle="bold"
|
||||
android:textSize="28sp"
|
||||
android:gravity="center"
|
||||
android:alpha="0"
|
||||
android:textColor="@color/text_primary"/>
|
||||
<TextView
|
||||
android:id="@+id/subtitle_view"
|
||||
|
|
@ -98,6 +99,7 @@
|
|||
android:textSize="20sp"
|
||||
android:letterSpacing="0.04"
|
||||
android:lineSpacingExtra="2dp"
|
||||
android:alpha="0"
|
||||
/>
|
||||
</LinearLayout>
|
||||
<Space
|
||||
|
|
@ -160,38 +162,52 @@
|
|||
android:layout_marginHorizontal="24dp"
|
||||
app:currency="gold" />
|
||||
|
||||
<FrameLayout
|
||||
<LinearLayout
|
||||
android:id="@+id/open_armoire_subscriber_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="65dp"
|
||||
android:paddingStart="24dp"
|
||||
android:paddingEnd="18dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginTop="4dp">
|
||||
<TextView
|
||||
android:id="@+id/open_armoire_subscriber_button"
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
android:text="@string/subscriber_button_armoire"
|
||||
android:textStyle="bold"
|
||||
android:background="@drawable/subscriber_benefit_button_bg"
|
||||
android:gravity="center"
|
||||
android:textSize="16sp"
|
||||
android:backgroundTint="@null"
|
||||
android:textColor="@color/green_1"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:padding="0dp"/>
|
||||
android:layout_height="65dp"
|
||||
android:paddingStart="24dp"
|
||||
android:paddingEnd="18dp">
|
||||
<TextView
|
||||
android:id="@+id/open_armoire_subscriber_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="60dp"
|
||||
android:text="@string/subscriber_button_armoire"
|
||||
android:textStyle="bold"
|
||||
android:background="@drawable/subscriber_benefit_button_bg"
|
||||
android:gravity="center"
|
||||
android:textSize="16sp"
|
||||
android:backgroundTint="@null"
|
||||
android:textColor="@color/green_1"
|
||||
android:layout_marginEnd="6dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:padding="0dp"/>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/sub_perk_bg"
|
||||
android:textColor="@color/green_500"
|
||||
android:paddingHorizontal="6dp"
|
||||
android:paddingVertical="4dp"
|
||||
style="@style/Caption2"
|
||||
android:layout_gravity="top|end"
|
||||
android:text="@string/sub_perk"/>
|
||||
</FrameLayout>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/sub_perk_bg"
|
||||
android:textColor="@color/green_500"
|
||||
android:paddingHorizontal="6dp"
|
||||
android:paddingVertical="4dp"
|
||||
style="@style/Caption2"
|
||||
android:layout_gravity="top|end"
|
||||
android:text="@string/sub_perk"/>
|
||||
</FrameLayout>
|
||||
android:text="@string/subscription_benefit_armoire_sub"
|
||||
android:textColor="@color/white"
|
||||
style="@style/Body2"
|
||||
android:gravity="center"
|
||||
android:paddingHorizontal="48dp"
|
||||
android:layout_marginTop="6dp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/unsubbed_wrapper"
|
||||
|
|
|
|||
|
|
@ -103,7 +103,8 @@
|
|||
tools:text="1"
|
||||
android:inputType="number"
|
||||
android:background="@color/transparent"
|
||||
android:textColor="@color/text_secondary"/>
|
||||
android:textColor="@color/text_secondary"
|
||||
android:paddingVertical="2dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/repeats_every_title"
|
||||
|
|
@ -128,19 +129,21 @@
|
|||
android:orientation="horizontal">
|
||||
<TextView
|
||||
android:id="@+id/monthly_repeat_days"
|
||||
style="@style/TaskFormToggle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="28dp"
|
||||
android:layout_height="48dp"
|
||||
android:gravity="center"
|
||||
android:background="@drawable/layout_rounded_bg_content"
|
||||
android:text="@string/repeatables_frequency_day_of_month"
|
||||
android:layout_marginEnd="@dimen/spacing_medium"/>
|
||||
<TextView
|
||||
android:id="@+id/monthly_repeat_weeks"
|
||||
style="@style/TaskFormToggle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="28dp"
|
||||
android:layout_height="48dp"
|
||||
android:text="@string/repeatables_frequency_day_of_week"
|
||||
android:gravity="center"
|
||||
android:background="@drawable/layout_rounded_bg_content"
|
||||
android:layout_marginStart="@dimen/spacing_medium"/>
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
|
|
@ -150,4 +153,4 @@
|
|||
android:textColor="?textColorTintedSecondary"
|
||||
android:textSize="12sp"
|
||||
android:layout_marginTop="@dimen/spacing_medium"/>
|
||||
</merge>
|
||||
</merge>
|
||||
|
|
|
|||
|
|
@ -1457,6 +1457,7 @@
|
|||
<string name="preference_push_invited_to_group_plan">Invited to Group Plan</string>
|
||||
<string name="preference_push_joined_group_plan_mention">\@Mentions in Group Plans</string>
|
||||
<string name="subscribe_incentive_button_faint">Subscribe to hold on with 1HP!</string>
|
||||
<string name="subscription_benefit_armoire_sub">Your subscription gives you an extra chance at the Armoire!</string>
|
||||
|
||||
|
||||
<plurals name="you_x_others">
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -291,7 +291,7 @@ class PartyDetailFragment : BaseFragment<FragmentPartyDetailBinding>() {
|
|||
binding?.questParticipationView?.setTextColor(
|
||||
ContextCompat.getColor(
|
||||
it,
|
||||
R.color.text_quad
|
||||
R.color.text_ternary
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
})
|
||||
}
|
||||
|
|
@ -31,8 +31,8 @@ fun HabiticaButton(
|
|||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = modifier
|
||||
.clickable { onClick() }
|
||||
.background(background, HabiticaTheme.shapes.medium)
|
||||
.clickable { onClick() }
|
||||
.fillMaxWidth()
|
||||
.padding(contentPadding)
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
NAME=4.3
|
||||
CODE=6471
|
||||
CODE=6491
|
||||