mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-05-20 04:39:04 +00:00
improve customization purchase dialog
This commit is contained in:
parent
3584d06261
commit
794c2f0f12
11 changed files with 137 additions and 77 deletions
|
|
@ -1,44 +1,27 @@
|
|||
<?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="wrap_content">
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:parentTag="android.widget.LinearLayout">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="@dimen/avatar_width"
|
||||
android:layout_height="@dimen/avatar_height"
|
||||
android:layout_width="@dimen/customization_width"
|
||||
android:layout_height="@dimen/customization_width"
|
||||
android:id="@+id/imageView"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:background="@drawable/layout_rounded_bg_window"
|
||||
android:layout_marginTop="24dp"
|
||||
android:scaleType="center"/>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_horizontal">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:id="@+id/priceLabel"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginEnd="2dp"/>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/gem_icon"
|
||||
android:layout_gravity="center"/>
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:id="@+id/amount_error_label"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/titleTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:text="@string/purchase_amount_error"
|
||||
android:textSize="12sp"
|
||||
android:textColor="@color/text_ternary"
|
||||
android:layout_marginTop="@dimen/spacing_medium"
|
||||
android:visibility="gone"
|
||||
android:gravity="center_horizontal"/>
|
||||
|
||||
</LinearLayout>
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Headline"
|
||||
android:textColor="@color/text_primary"
|
||||
tools:text="This is the Title"
|
||||
android:gravity="center"
|
||||
android:layout_marginTop="14dp"
|
||||
android:layout_marginBottom="4dp"/>
|
||||
</merge>
|
||||
35
Habitica/res/layout/purchase_dialog_background.xml
Normal file
35
Habitica/res/layout/purchase_dialog_background.xml
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingStart="@dimen/shopitem_dialog_content_inset"
|
||||
android:paddingEnd="@dimen/shopitem_dialog_content_inset"
|
||||
tools:parentTag="LinearLayout"
|
||||
tools:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="@dimen/avatar_width"
|
||||
android:layout_height="@dimen/avatar_height"
|
||||
android:layout_marginTop="24dp"/>
|
||||
<TextView
|
||||
android:id="@+id/titleTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Headline"
|
||||
android:textColor="@color/text_primary"
|
||||
tools:text="This is the Title"
|
||||
android:gravity="center"
|
||||
android:layout_marginTop="14dp"
|
||||
android:layout_marginBottom="4dp"/>
|
||||
<TextView
|
||||
android:id="@+id/notesTextView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/Body2"
|
||||
android:textColor="@color/text_ternary"
|
||||
tools:text="These are the notes"
|
||||
android:gravity="center"/>
|
||||
</merge>
|
||||
|
|
@ -1044,7 +1044,7 @@
|
|||
<string name="unequip">取消裝備</string>
|
||||
<string name="excessItemsNoneLeft">你已經有得到所有%s寵物所需的一切物品。你確定你要買%2$d個%3$s?</string>
|
||||
<string name="purchaseX">買%d個</string>
|
||||
<string name="excessItemsXLeft">你只需要%d個%2$s即可孵化所有可得到的這種寵物。你確定你想要買%1$d個?</string>
|
||||
<string name="excessItemsXLeft">你只需要%3$d個%2$s即可孵化所有可得到的這種寵物。你確定你想要買%1$d個?</string>
|
||||
<string name="feedPet_description">完成任務有概率掉落寵物食品!這樣你就可以把寵物餵大長成坐騎啦!</string>
|
||||
<string name="excess_items">多餘物品</string>
|
||||
<string name="onboardingComplete_achievement_title">你完成了新手任務!</string>
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ interface UserRepository : BaseRepository {
|
|||
|
||||
fun changeClass(selectedClass: String): Flowable<User>
|
||||
|
||||
fun unlockPath(user: User?, unlockPath: String?, type: String?, price: Int): Flowable<UnlockResponse>
|
||||
fun unlockPath(user: User?, customization: Customization): Flowable<UnlockResponse>
|
||||
fun unlockPath(set: CustomizationSet): Flowable<UnlockResponse>
|
||||
|
||||
|
|
|
|||
|
|
@ -162,9 +162,9 @@ class UserRepositoryImpl(
|
|||
override fun changeClass(selectedClass: String): Flowable<User> = apiClient.changeClass(selectedClass)
|
||||
.flatMap { retrieveUser(false) }
|
||||
|
||||
override fun unlockPath(user: User?, customization: Customization): Flowable<UnlockResponse> {
|
||||
var path = customization.path
|
||||
if (path.last() == '.' && customization.type == "background") {
|
||||
override fun unlockPath(user: User?, unlockPath: String?, type: String?, price: Int): Flowable<UnlockResponse> {
|
||||
var path = unlockPath ?: return Flowable.empty()
|
||||
if (path.last() == '.' && type == "background") {
|
||||
path += user?.preferences?.background
|
||||
}
|
||||
return zipWithLiveUser(apiClient.unlockPath(path)) { unlockResponse, copiedUser ->
|
||||
|
|
@ -172,12 +172,16 @@ class UserRepositoryImpl(
|
|||
user.preferences = unlockResponse.preferences
|
||||
user.purchased = unlockResponse.purchased
|
||||
user.items = unlockResponse.items
|
||||
user.balance = copiedUser.balance - (customization.price ?: 0) / 4.0
|
||||
user.balance = copiedUser.balance - (price / 4.0)
|
||||
localRepository.saveUser(copiedUser, false)
|
||||
unlockResponse
|
||||
}
|
||||
}
|
||||
|
||||
override fun unlockPath(user: User?, customization: Customization): Flowable<UnlockResponse> {
|
||||
return unlockPath(user, customization.path, customization.type, customization.price ?: 0)
|
||||
}
|
||||
|
||||
override fun unlockPath(set: CustomizationSet): Flowable<UnlockResponse> {
|
||||
var path = ""
|
||||
for (customization in set.customizations) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import android.content.res.Resources
|
|||
import com.google.gson.annotations.SerializedName
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.models.BaseObject
|
||||
import com.habitrpg.android.habitica.models.inventory.Customization
|
||||
import com.habitrpg.android.habitica.models.inventory.ItemEvent
|
||||
import com.habitrpg.android.habitica.models.user.User
|
||||
import io.realm.RealmObject
|
||||
|
|
@ -150,5 +151,18 @@ open class ShopItem : RealmObject(), BaseObject {
|
|||
item.purchaseType = "fortify"
|
||||
return item
|
||||
}
|
||||
|
||||
fun fromCustomization(customization: Customization, userSize: String?, hairColor: String?): ShopItem {
|
||||
val item = ShopItem()
|
||||
item.key = customization.identifier ?: ""
|
||||
item.text = customization.text
|
||||
item.currency = "gems"
|
||||
item.notes = customization.notes
|
||||
item.value = customization.price ?: 0
|
||||
item.path = customization.path
|
||||
item.purchaseType = if (customization.type == "background") "background" else "customization"
|
||||
item.imageName = customization.getImageName(userSize, hairColor)
|
||||
return item
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ import android.content.Context
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.os.bundleOf
|
||||
import coil.load
|
||||
import com.habitrpg.android.habitica.HabiticaBaseApplication
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.databinding.CustomizationGridItemBinding
|
||||
import com.habitrpg.android.habitica.databinding.CustomizationSectionFooterBinding
|
||||
|
|
@ -17,9 +17,10 @@ import com.habitrpg.android.habitica.databinding.CustomizationSectionHeaderBindi
|
|||
import com.habitrpg.android.habitica.helpers.MainNavigationController
|
||||
import com.habitrpg.android.habitica.models.inventory.Customization
|
||||
import com.habitrpg.android.habitica.models.inventory.CustomizationSet
|
||||
import com.habitrpg.android.habitica.models.shops.ShopItem
|
||||
import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils
|
||||
import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper
|
||||
import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog
|
||||
import com.habitrpg.android.habitica.ui.views.shops.PurchaseDialog
|
||||
import io.reactivex.rxjava3.core.BackpressureStrategy
|
||||
import io.reactivex.rxjava3.core.Flowable
|
||||
import io.reactivex.rxjava3.subjects.PublishSubject
|
||||
|
|
@ -198,31 +199,10 @@ class CustomizationRecyclerViewAdapter() : androidx.recyclerview.widget.Recycler
|
|||
dialog.addButton(R.string.reward_dialog_dismiss, false)
|
||||
dialog.show()
|
||||
} else {
|
||||
val dialogContent = LayoutInflater.from(itemView.context).inflate(R.layout.dialog_purchase_customization, null) as LinearLayout
|
||||
|
||||
val imageView = dialogContent.findViewById<ImageView>(R.id.imageView)
|
||||
DataBindingUtils.loadImage(imageView, customization?.getImageName(userSize, hairColor))
|
||||
|
||||
val priceLabel = dialogContent.findViewById<TextView>(R.id.priceLabel)
|
||||
priceLabel.text = customization?.price.toString()
|
||||
|
||||
(dialogContent.findViewById<View>(R.id.gem_icon) as? ImageView)?.setImageBitmap(HabiticaIconsHelper.imageOfGem())
|
||||
|
||||
val dialog = HabiticaAlertDialog(itemView.context)
|
||||
dialog.addButton(R.string.purchase_button, true) { _, _ ->
|
||||
if (customization?.price ?: 0 > gemBalance) {
|
||||
MainNavigationController.navigate(R.id.gemPurchaseActivity, bundleOf(Pair("openSubscription", false)))
|
||||
return@addButton
|
||||
}
|
||||
|
||||
customization?.let {
|
||||
unlockCustomizationEvents.onNext(it)
|
||||
}
|
||||
customization?.let {
|
||||
val dialog = PurchaseDialog(itemView.context, HabiticaBaseApplication.userComponent, ShopItem.fromCustomization(it, userSize, hairColor))
|
||||
dialog.show()
|
||||
}
|
||||
dialog.setTitle(R.string.purchase_customization)
|
||||
dialog.setAdditionalContentView(dialogContent)
|
||||
dialog.addButton(R.string.reward_dialog_dismiss, false)
|
||||
dialog.show()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ open class HabiticaAlertDialog(context: Context) : AlertDialog(context, R.style.
|
|||
internal var contentView: FrameLayout
|
||||
private var scrollingSeparator: View
|
||||
internal var scrollView: LockableScrollView
|
||||
private var buttonsWrapper: LinearLayout
|
||||
protected var buttonsWrapper: LinearLayout
|
||||
private var noticeTextView: TextView
|
||||
private var closeButton: Button
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ import com.habitrpg.android.habitica.models.shops.Shop
|
|||
import com.habitrpg.android.habitica.models.shops.ShopItem
|
||||
import com.habitrpg.android.habitica.models.user.OwnedItem
|
||||
import com.habitrpg.android.habitica.models.user.User
|
||||
import com.habitrpg.android.habitica.ui.activities.ArmoireActivityArgs
|
||||
import com.habitrpg.android.habitica.ui.activities.ArmoireActivityDirections
|
||||
import com.habitrpg.android.habitica.ui.views.CurrencyView
|
||||
import com.habitrpg.android.habitica.ui.views.CurrencyViews
|
||||
|
|
@ -42,16 +41,16 @@ import com.habitrpg.android.habitica.ui.views.tasks.form.StepperValueFormView
|
|||
import io.reactivex.rxjava3.core.Flowable
|
||||
import io.reactivex.rxjava3.core.Maybe
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import java.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.max
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.ExperimentalTime
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import java.util.Date
|
||||
import javax.inject.Inject
|
||||
import kotlin.math.max
|
||||
import kotlin.time.DurationUnit
|
||||
import kotlin.time.toDuration
|
||||
|
||||
class PurchaseDialog(context: Context, component: UserComponent?, val item: ShopItem) : HabiticaAlertDialog(context) {
|
||||
|
||||
|
|
@ -106,6 +105,8 @@ class PurchaseDialog(context: Context, component: UserComponent?, val item: Shop
|
|||
checkGearClass()
|
||||
}
|
||||
"gems" == shopItem.purchaseType -> contentView = PurchaseDialogGemsContent(context)
|
||||
"background" == shopItem.purchaseType -> contentView = PurchaseDialogBackgroundContent(context)
|
||||
"customization" == shopItem.purchaseType -> contentView = PurchaseDialogCustomizationContent(context)
|
||||
else -> contentView = PurchaseDialogBaseContent(context)
|
||||
}
|
||||
|
||||
|
|
@ -168,7 +169,6 @@ class PurchaseDialog(context: Context, component: UserComponent?, val item: Shop
|
|||
|
||||
private var limitedTextViewJob: Job? = null
|
||||
|
||||
@OptIn(ExperimentalTime::class)
|
||||
private fun setLimitedTextView() {
|
||||
if (user == null) return
|
||||
if (shopItem.habitClass != null && shopItem.habitClass != "special" && shopItem.habitClass != "armoire" && user?.stats?.habitClass != shopItem.habitClass) {
|
||||
|
|
@ -182,7 +182,7 @@ class PurchaseDialog(context: Context, component: UserComponent?, val item: Shop
|
|||
while (shopItem.event?.end?.after(Date()) == true) {
|
||||
limitedTextView.text = context.getString(R.string.available_for, shopItem.event?.end?.getShortRemainingString())
|
||||
val diff = (shopItem.event?.end?.time ?: 0) - Date().time
|
||||
delay(if (diff < (60 * 60 * 1000)) Duration.seconds(1) else Duration.minutes(1))
|
||||
delay(1.toDuration(if (diff < (60 * 60 * 1000)) DurationUnit.SECONDS else DurationUnit.MINUTES))
|
||||
}
|
||||
if (shopItem.event?.end?.before(Date()) == true) {
|
||||
limitedTextView.text = context.getString(R.string.no_longer_available)
|
||||
|
|
@ -239,10 +239,11 @@ class PurchaseDialog(context: Context, component: UserComponent?, val item: Shop
|
|||
pinTextView = customHeader.findViewById(R.id.pin_text)
|
||||
|
||||
addCloseButton()
|
||||
buyButton = addButton(layoutInflater.inflate(R.layout.dialog_purchase_shopitem_button, null), autoDismiss = false) { _, _ ->
|
||||
buyButton = addButton(layoutInflater.inflate(R.layout.dialog_purchase_shopitem_button, buttonsWrapper, false), autoDismiss = false) { _, _ ->
|
||||
onBuyButtonClicked()
|
||||
}
|
||||
priceLabel = buyButton.findViewById(R.id.priceLabel)
|
||||
priceLabel.animationDuration = 0L
|
||||
buyLabel = buyButton.findViewById(R.id.buy_label)
|
||||
pinButton.setOnClickListener { inventoryRepository.togglePinnedItem(shopItem).subscribe({ isPinned = !this.isPinned }, RxErrorHandler.handleEmptyError()) }
|
||||
|
||||
|
|
@ -353,6 +354,12 @@ class PurchaseDialog(context: Context, component: UserComponent?, val item: Shop
|
|||
observable = inventoryRepository.purchaseQuest(shopItem.key).cast(Any::class.java)
|
||||
} else if (shopItem.purchaseType == "debuffPotion") {
|
||||
observable = userRepository.useSkill(shopItem.key, null).cast(Any::class.java)
|
||||
} else if (shopItem.purchaseType == "customization" || shopItem.purchaseType == "background") {
|
||||
observable = userRepository.unlockPath(user, item.path, item.purchaseType,
|
||||
item.value
|
||||
).cast(Any::class.java)
|
||||
} else if (shopItem.purchaseType == "debuffPotion") {
|
||||
observable = userRepository.useSkill(shopItem.key, null).cast(Any::class.java)
|
||||
} else if (shopItem.purchaseType == "card") {
|
||||
purchaseCardAction?.invoke(shopItem)
|
||||
dismiss()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
package com.habitrpg.android.habitica.ui.views.shops
|
||||
|
||||
import android.content.Context
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import com.habitrpg.android.habitica.databinding.PurchaseDialogBackgroundBinding
|
||||
import com.habitrpg.android.habitica.extensions.layoutInflater
|
||||
import com.habitrpg.android.habitica.models.shops.ShopItem
|
||||
|
||||
class PurchaseDialogBackgroundContent(context: Context) : PurchaseDialogContent(context) {
|
||||
val binding = PurchaseDialogBackgroundBinding.inflate(context.layoutInflater, this)
|
||||
override val imageView: ImageView
|
||||
get() = binding.imageView
|
||||
override val titleTextView: TextView
|
||||
get() = binding.titleTextView
|
||||
|
||||
override fun setItem(item: ShopItem) {
|
||||
super.setItem(item)
|
||||
binding.notesTextView.text = item.notes
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.habitrpg.android.habitica.ui.views.shops
|
||||
|
||||
import android.content.Context
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import com.habitrpg.android.habitica.databinding.DialogPurchaseCustomizationBinding
|
||||
import com.habitrpg.android.habitica.extensions.layoutInflater
|
||||
|
||||
class PurchaseDialogCustomizationContent(context: Context) : PurchaseDialogContent(context) {
|
||||
val binding = DialogPurchaseCustomizationBinding.inflate(context.layoutInflater, this)
|
||||
override val imageView: ImageView
|
||||
get() = binding.imageView
|
||||
override val titleTextView: TextView
|
||||
get() = binding.titleTextView
|
||||
}
|
||||
Loading…
Reference in a new issue