mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-05-20 04:39:04 +00:00
Implement more avatar customization options. Fixes #1137
This commit is contained in:
parent
3d9a4eb950
commit
dadc3885fa
20 changed files with 363 additions and 144 deletions
|
|
@ -155,7 +155,7 @@ android {
|
|||
multiDexEnabled true
|
||||
resConfigs "en", "bg", "de", "en-rGB", "es", "fr", "hr-rHR", "in", "it", "iw", "ja", "ko", "lt", "nl", "pl", "pt-rBR", "pt-rPT", "ru", "tr", "zh", "zh-rTW"
|
||||
|
||||
versionCode 2386
|
||||
versionCode 2388
|
||||
versionName "2.5"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/gray_700" />
|
||||
<corners android:radius="@dimen/rounded_button_radius"/>
|
||||
<padding android:left="0dip" android:top="0dip" android:right="0dip" android:bottom="0dip" />
|
||||
<stroke android:color="@color/brand_300" android:width="2dp" />
|
||||
</shape>
|
||||
|
|
@ -1,37 +1,41 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/card_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent">
|
||||
<RelativeLayout
|
||||
android:id="@+id/linearLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="90dp"
|
||||
android:minHeight="60dp"
|
||||
android:minHeight="60dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/wrapper"
|
||||
android:layout_width="76dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/layout_rounded_bg_gray_700"
|
||||
android:orientation="vertical"
|
||||
android:clickable="true"
|
||||
android:background="@drawable/selection_highlight">
|
||||
<View
|
||||
android:id="@+id/purchaseOverlay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:background="@android:color/black" />
|
||||
android:layout_gravity="center">
|
||||
|
||||
<com.facebook.drawee.view.SimpleDraweeView
|
||||
android:id="@+id/imageView"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:scaleType="fitEnd"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_centerHorizontal="true" />
|
||||
|
||||
</RelativeLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
android:layout_height="76dp"
|
||||
android:layout_gravity="start"
|
||||
android:scaleType="fitEnd" />
|
||||
<FrameLayout
|
||||
android:id="@+id/buy_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="32dp"
|
||||
android:background="@drawable/layout_rounded_bg_shopitem_price">
|
||||
<com.habitrpg.android.habitica.ui.views.CurrencyView
|
||||
android:id="@+id/price_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="32dp"
|
||||
android:textColor="@color/gray_300"
|
||||
tools:text="150"
|
||||
style="@style/Body1"
|
||||
app:hasLightBackground="true"
|
||||
android:textSize="15sp"
|
||||
android:layout_gravity="center" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
|
|
@ -1,21 +1,42 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal" android:layout_width="match_parent"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="65dp"
|
||||
android:paddingTop="16dp">
|
||||
android:paddingTop="16dp"
|
||||
android:gravity="bottom"
|
||||
android:layout_marginStart="20dp"
|
||||
android:layout_marginEnd="20dp">
|
||||
<TextView
|
||||
android:id="@+id/label"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_gravity="bottom"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:layout_marginLeft="@dimen/section_leftright_padding"
|
||||
android:layout_marginRight="@dimen/section_leftright_padding"/>
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"/>
|
||||
|
||||
<Button
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="40dp"
|
||||
android:id="@+id/purchaseSetButton"
|
||||
android:visibility="gone" />
|
||||
android:visibility="gone"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center"
|
||||
tools:visibility="visible"
|
||||
android:paddingStart="@dimen/spacing_medium"
|
||||
android:paddingEnd="@dimen/spacing_medium"
|
||||
android:background="@drawable/layout_rounded_bg_gray_700">
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/buy_all"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@color/brand_300"
|
||||
style="@style/Body1"
|
||||
android:layout_marginEnd="@dimen/spacing_medium"/>
|
||||
<com.habitrpg.android.habitica.ui.views.CurrencyView
|
||||
android:id="@+id/set_price_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
|
@ -33,7 +33,8 @@
|
|||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp">
|
||||
android:layout_height="50dp"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
|
|
@ -52,7 +53,6 @@
|
|||
android:layout_height="match_parent"
|
||||
android:id="@+id/avatarSizeSpinner"
|
||||
android:spinnerMode="dropdown"
|
||||
android:layout_marginRight="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:entries="@array/avatar_sizes"/>
|
||||
</LinearLayout>
|
||||
|
|
@ -66,6 +66,30 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:id="@+id/avatarSkinView"
|
||||
app:equipmentTitle="@string/avatar_skin"/>
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/avatar_extras"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
style="@style/SectionTitle"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
style="@style/CardView.Default">
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:divider="?android:listDivider"
|
||||
android:showDividers="middle">
|
||||
<com.habitrpg.android.habitica.ui.views.EquipmentItemRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/avatar_glasses_view"
|
||||
app:equipmentTitle="@string/avatar_glasses"/>
|
||||
<com.habitrpg.android.habitica.ui.views.EquipmentItemRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -74,8 +98,8 @@
|
|||
<com.habitrpg.android.habitica.ui.views.EquipmentItemRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/avatar_glasses_view"
|
||||
app:equipmentTitle="@string/avatar_glasses"/>
|
||||
android:id="@+id/avatar_accent_view"
|
||||
app:equipmentTitle="@string/avatar_accent" />
|
||||
<com.habitrpg.android.habitica.ui.views.EquipmentItemRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
@ -86,6 +110,11 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:id="@+id/avatar_animal_tail_view"
|
||||
app:equipmentTitle="@string/animal_tail"/>
|
||||
<com.habitrpg.android.habitica.ui.views.EquipmentItemRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/avatar_headband_view"
|
||||
app:equipmentTitle="@string/avatar_headband"/>
|
||||
</LinearLayout>
|
||||
</androidx.cardview.widget.CardView>
|
||||
<TextView
|
||||
|
|
@ -120,11 +149,6 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:id="@+id/avatarHairBangsView"
|
||||
app:equipmentTitle="@string/avatar_bangs" />
|
||||
<com.habitrpg.android.habitica.ui.views.EquipmentItemRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/avatarHairFlowerView"
|
||||
app:equipmentTitle="@string/avatar_flower" />
|
||||
<com.habitrpg.android.habitica.ui.views.EquipmentItemRow
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
|
|||
|
|
@ -123,6 +123,9 @@
|
|||
<action
|
||||
android:id="@+id/openAvatarDetail"
|
||||
app:destination="@id/avatarCustomizationFragment" />
|
||||
<action
|
||||
android:id="@+id/openAvatarEquipment"
|
||||
app:destination="@id/avatarEquipmentFragment" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/itemsFragment"
|
||||
|
|
@ -254,6 +257,17 @@
|
|||
android:name="category"
|
||||
app:argType="string" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/avatarEquipmentFragment"
|
||||
android:name="com.habitrpg.android.habitica.ui.fragments.inventory.customization.AvatarEquipmentFragment"
|
||||
android:label="@string/sidebar_avatar" >
|
||||
<argument
|
||||
android:name="type"
|
||||
app:argType="string" />
|
||||
<argument
|
||||
android:name="category"
|
||||
app:argType="string" />
|
||||
</fragment>
|
||||
<activity
|
||||
android:id="@+id/prefsActivity"
|
||||
android:name="com.habitrpg.android.habitica.ui.activities.PrefsActivity"
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
<dimen name="grid_item_margin">6dp</dimen>
|
||||
<dimen name="avatar_small_width">90dp</dimen>
|
||||
<dimen name="avatar_small_height">90dp</dimen>
|
||||
<dimen name="customization_width">100dp</dimen>
|
||||
<dimen name="customization_width">76dp</dimen>
|
||||
<dimen name="gear_image_size">68dp</dimen>
|
||||
<dimen name="row_padding">12dp</dimen>
|
||||
<dimen name="row_title_size">16sp</dimen>
|
||||
|
|
|
|||
|
|
@ -1001,4 +1001,7 @@
|
|||
<string name="could_not_find_user">Could not find user</string>
|
||||
<string name="animal_ears">Animal Ears</string>
|
||||
<string name="animal_tail">Animal Tail</string>
|
||||
<string name="avatar_headband">Headband</string>
|
||||
<string name="avatar_accent">Accent</string>
|
||||
<string name="buy_all">Buy All</string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ interface InventoryRepository : BaseRepository {
|
|||
fun retrieveInAppRewards(): Flowable<List<ShopItem>>
|
||||
|
||||
fun getOwnedEquipment(type: String): Flowable<RealmResults<Equipment>>
|
||||
fun getEquipmentType(type: String, set: String): Flowable<RealmResults<Equipment>>
|
||||
|
||||
fun getOwnedItems(itemType: String): Flowable<RealmResults<OwnedItem>>
|
||||
fun getOwnedItems(): Flowable<Map<String, OwnedItem>>
|
||||
|
|
|
|||
|
|
@ -46,6 +46,10 @@ class InventoryRepositoryImpl(localRepository: InventoryLocalRepository, apiClie
|
|||
return localRepository.getOwnedEquipment()
|
||||
}
|
||||
|
||||
override fun getEquipmentType(type: String, set: String): Flowable<RealmResults<Equipment>> {
|
||||
return localRepository.getEquipmentType(type, set)
|
||||
}
|
||||
|
||||
override fun getOwnedItems(itemType: String): Flowable<RealmResults<OwnedItem>> {
|
||||
return localRepository.getOwnedItems(itemType, userID)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ interface InventoryLocalRepository : ContentLocalRepository {
|
|||
fun getItems(itemClass: Class<out Item>, keys: Array<String>, user: User?): Flowable<out RealmResults<out Item>>
|
||||
fun getOwnedItems(itemType: String, userID: String): Flowable<RealmResults<OwnedItem>>
|
||||
fun getOwnedItems(userID: String): Flowable<Map<String, OwnedItem>>
|
||||
fun getEquipmentType(type: String, set: String): Flowable<RealmResults<Equipment>>
|
||||
|
||||
fun getEquipment(key: String): Flowable<Equipment>
|
||||
fun getMounts(type: String, group: String, color: String?): Flowable<RealmResults<Mount>>
|
||||
|
|
|
|||
|
|
@ -70,6 +70,15 @@ class RealmInventoryLocalRepository(realm: Realm, private val context: Context)
|
|||
.filter { it.isLoaded }
|
||||
}
|
||||
|
||||
override fun getEquipmentType(type: String, set: String): Flowable<RealmResults<Equipment>> {
|
||||
return realm.where(Equipment::class.java)
|
||||
.equalTo("type", type)
|
||||
.equalTo("gearSet", set)
|
||||
.findAll()
|
||||
.asFlowable()
|
||||
.filter { it.isLoaded }
|
||||
}
|
||||
|
||||
override fun getOwnedItems(itemType: String, userID: String): Flowable<RealmResults<OwnedItem>> {
|
||||
return realm.where(OwnedItem::class.java)
|
||||
.greaterThan("numberOwned", 0)
|
||||
|
|
|
|||
|
|
@ -24,4 +24,5 @@ open class Equipment : RealmObject() {
|
|||
var owned: Boolean? = null
|
||||
var twoHanded = false
|
||||
var mystery = ""
|
||||
var gearSet = ""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,157 @@
|
|||
package com.habitrpg.android.habitica.ui.adapter
|
||||
|
||||
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.os.bundleOf
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.databinding.CustomizationGridItemBinding
|
||||
import com.habitrpg.android.habitica.helpers.MainNavigationController
|
||||
import com.habitrpg.android.habitica.models.inventory.CustomizationSet
|
||||
import com.habitrpg.android.habitica.models.inventory.Equipment
|
||||
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 io.reactivex.BackpressureStrategy
|
||||
import io.reactivex.Flowable
|
||||
import io.reactivex.subjects.PublishSubject
|
||||
import java.util.*
|
||||
|
||||
class CustomizationEquipmentRecyclerViewAdapter : androidx.recyclerview.widget.RecyclerView.Adapter<androidx.recyclerview.widget.RecyclerView.ViewHolder>() {
|
||||
|
||||
var gemBalance: Int = 0
|
||||
var equipmentList
|
||||
: MutableList<Equipment> = ArrayList()
|
||||
set(value) {
|
||||
field = value
|
||||
notifyDataSetChanged()
|
||||
}
|
||||
var activeEquipment: String? = null
|
||||
set(value) {
|
||||
field = value
|
||||
this.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
private val selectCustomizationEvents = PublishSubject.create<Equipment>()
|
||||
private val unlockCustomizationEvents = PublishSubject.create<Equipment>()
|
||||
private val unlockSetEvents = PublishSubject.create<CustomizationSet>()
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): androidx.recyclerview.widget.RecyclerView.ViewHolder {
|
||||
val viewID: Int = R.layout.customization_grid_item
|
||||
|
||||
val view = LayoutInflater.from(parent.context).inflate(viewID, parent, false)
|
||||
return EquipmentViewHolder(view)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: androidx.recyclerview.widget.RecyclerView.ViewHolder, position: Int) {
|
||||
(holder as EquipmentViewHolder).bind(equipmentList[position])
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return equipmentList.size
|
||||
}
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
return if (this.equipmentList[position].javaClass == CustomizationSet::class.java) {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
fun setEquipment(newEquipmentList: List<Equipment>) {
|
||||
this.equipmentList = newEquipmentList.toMutableList()
|
||||
this.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
fun getSelectCustomizationEvents(): Flowable<Equipment> {
|
||||
return selectCustomizationEvents.toFlowable(BackpressureStrategy.DROP)
|
||||
}
|
||||
|
||||
fun getUnlockCustomizationEvents(): Flowable<Equipment> {
|
||||
return unlockCustomizationEvents.toFlowable(BackpressureStrategy.DROP)
|
||||
}
|
||||
|
||||
fun getUnlockSetEvents(): Flowable<CustomizationSet> {
|
||||
return unlockSetEvents.toFlowable(BackpressureStrategy.DROP)
|
||||
}
|
||||
|
||||
internal inner class EquipmentViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView), View.OnClickListener {
|
||||
|
||||
private val binding = CustomizationGridItemBinding.bind(itemView)
|
||||
var equipment: Equipment? = null
|
||||
|
||||
init {
|
||||
itemView.setOnClickListener(this)
|
||||
}
|
||||
|
||||
fun bind(equipment: Equipment) {
|
||||
this.equipment = equipment
|
||||
DataBindingUtils.loadImage(binding.imageView, "shop_" + this.equipment?.key)
|
||||
if (equipment.owned == true || equipment.value == 0.0) {
|
||||
binding.buyButton.visibility = View.GONE
|
||||
} else {
|
||||
binding.buyButton.visibility = View.VISIBLE
|
||||
binding.priceLabel.currency = "gems"
|
||||
binding.priceLabel.value = if (equipment.gearSet == "animal") {
|
||||
2.0
|
||||
} else {
|
||||
equipment.value
|
||||
}
|
||||
}
|
||||
|
||||
if (activeEquipment == equipment.key) {
|
||||
binding.wrapper.background = itemView.context.getDrawable(R.drawable.layout_rounded_bg_gray_700_brand_border)
|
||||
} else {
|
||||
binding.wrapper.background = itemView.context.getDrawable(R.drawable.layout_rounded_bg_gray_700)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClick(v: View) {
|
||||
if (equipment?.owned != true && (equipment?.value ?: 0.0) > 0.0) {
|
||||
val dialogContent = LayoutInflater.from(itemView.context).inflate(R.layout.dialog_purchase_customization, null) as LinearLayout
|
||||
|
||||
val imageView = dialogContent.findViewById<SimpleDraweeView>(R.id.imageView)
|
||||
DataBindingUtils.loadImage(imageView, "shop_" + this.equipment?.key)
|
||||
|
||||
val priceLabel = dialogContent.findViewById<TextView>(R.id.priceLabel)
|
||||
priceLabel.text = if (equipment?.gearSet == "animal") {
|
||||
2.0
|
||||
} else {
|
||||
equipment?.value ?: 0
|
||||
}.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 (equipment?.value ?: 0.0 > gemBalance) {
|
||||
MainNavigationController.navigate(R.id.gemPurchaseActivity, bundleOf(Pair("openSubscription", false)))
|
||||
return@addButton
|
||||
}
|
||||
|
||||
equipment?.let {
|
||||
unlockCustomizationEvents.onNext(it)
|
||||
}
|
||||
}
|
||||
dialog.setTitle(R.string.purchase_customization)
|
||||
dialog.setAdditionalContentView(dialogContent)
|
||||
dialog.addButton(R.string.reward_dialog_dismiss, false)
|
||||
dialog.show()
|
||||
return
|
||||
}
|
||||
|
||||
if (equipment?.key == activeEquipment) {
|
||||
return
|
||||
}
|
||||
|
||||
equipment?.let {
|
||||
selectCustomizationEvents.onNext(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,11 +4,14 @@ import android.content.Context
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.*
|
||||
import androidx.core.content.ContextCompat
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.core.os.bundleOf
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.databinding.CustomizationGridItemBinding
|
||||
import com.habitrpg.android.habitica.databinding.CustomizationSectionHeaderBinding
|
||||
import com.habitrpg.android.habitica.helpers.MainNavigationController
|
||||
import com.habitrpg.android.habitica.models.inventory.Customization
|
||||
import com.habitrpg.android.habitica.models.inventory.CustomizationSet
|
||||
|
|
@ -125,35 +128,33 @@ class CustomizationRecyclerViewAdapter : androidx.recyclerview.widget.RecyclerVi
|
|||
|
||||
internal inner class CustomizationViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView), View.OnClickListener {
|
||||
|
||||
private val cardView: androidx.cardview.widget.CardView by bindView(itemView, R.id.card_view)
|
||||
private val linearLayout: RelativeLayout by bindView(itemView, R.id.linearLayout)
|
||||
private val imageView: SimpleDraweeView by bindView(itemView, R.id.imageView)
|
||||
private val purchaseOverlay: View by bindView(itemView, R.id.purchaseOverlay)
|
||||
|
||||
private val binding = CustomizationGridItemBinding.bind(itemView)
|
||||
var customization: Customization? = null
|
||||
|
||||
init {
|
||||
linearLayout.setOnClickListener(this)
|
||||
itemView.setOnClickListener(this)
|
||||
}
|
||||
|
||||
fun bind(customization: Customization) {
|
||||
this.customization = customization
|
||||
|
||||
if (customization.customizationSet?.contains("timeTravel") == true) {
|
||||
DataBindingUtils.loadImage(this.imageView, customization.getImageName(userSize, hairColor), imageFormat = "gif")
|
||||
DataBindingUtils.loadImage(binding.imageView, customization.getImageName(userSize, hairColor), imageFormat = "gif")
|
||||
} else {
|
||||
DataBindingUtils.loadImage(this.imageView, customization.getImageName(userSize, hairColor))
|
||||
DataBindingUtils.loadImage(binding.imageView, customization.getImageName(userSize, hairColor))
|
||||
}
|
||||
cardView.setCardBackgroundColor(ContextCompat.getColor(itemView.context, android.R.color.white))
|
||||
if (customization.isUsable) {
|
||||
imageView.alpha = 1.0f
|
||||
purchaseOverlay.alpha = 0.0f
|
||||
if (customization.identifier == activeCustomization) {
|
||||
cardView.setCardBackgroundColor(ContextCompat.getColor(itemView.context, R.color.brand_500))
|
||||
}
|
||||
binding.buyButton.visibility = View.GONE
|
||||
} else {
|
||||
imageView.alpha = 0.3f
|
||||
purchaseOverlay.alpha = 0.8f
|
||||
binding.buyButton.visibility = View.VISIBLE
|
||||
binding.priceLabel.currency = "gems"
|
||||
binding.priceLabel.value = customization.price.toDouble()
|
||||
}
|
||||
|
||||
if (activeCustomization == customization.identifier) {
|
||||
binding.wrapper.background = itemView.context.getDrawable(R.drawable.layout_rounded_bg_gray_700_brand_border)
|
||||
} else {
|
||||
binding.wrapper.background = itemView.context.getDrawable(R.drawable.layout_rounded_bg_gray_700)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -209,23 +210,24 @@ class CustomizationRecyclerViewAdapter : androidx.recyclerview.widget.RecyclerVi
|
|||
|
||||
internal inner class SectionViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView), View.OnClickListener {
|
||||
|
||||
private val binding = CustomizationSectionHeaderBinding.bind(itemView)
|
||||
private val label: TextView by bindView(itemView, R.id.label)
|
||||
private val purchaseSetButton: Button by bindView(itemView, R.id.purchaseSetButton)
|
||||
var context: Context = itemView.context
|
||||
private var set: CustomizationSet? = null
|
||||
|
||||
init {
|
||||
purchaseSetButton.setOnClickListener(this)
|
||||
binding.purchaseSetButton.setOnClickListener(this)
|
||||
}
|
||||
|
||||
fun bind(set: CustomizationSet) {
|
||||
this.set = set
|
||||
this.label.text = set.text
|
||||
if (set.hasPurchasable && !set.identifier.contains("timeTravel")) {
|
||||
this.purchaseSetButton.visibility = View.VISIBLE
|
||||
this.purchaseSetButton.text = context.getString(R.string.purchase_set_button, set.price)
|
||||
binding.purchaseSetButton.visibility = View.VISIBLE
|
||||
binding.setPriceLabel.value = set.price.toDouble()
|
||||
binding.setPriceLabel.currency = "gems"
|
||||
} else {
|
||||
this.purchaseSetButton.visibility = View.GONE
|
||||
binding.purchaseSetButton.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -83,8 +83,7 @@ class AvatarCustomizationFragment : BaseMainFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
setGridSpanCount(view.width)
|
||||
val layoutManager = GridLayoutManager(activity, 2)
|
||||
val layoutManager = GridLayoutManager(activity, 4)
|
||||
layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
|
||||
override fun getSpanSize(position: Int): Int {
|
||||
return if (adapter.getItemViewType(position) == 0) {
|
||||
|
|
@ -94,6 +93,7 @@ class AvatarCustomizationFragment : BaseMainFragment() {
|
|||
}
|
||||
}
|
||||
}
|
||||
setGridSpanCount(view.width)
|
||||
recyclerView.layoutManager = layoutManager
|
||||
recyclerView.addItemDecoration(MarginDecoration(context))
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import com.habitrpg.android.habitica.extensions.subscribeWithErrorHandler
|
|||
import com.habitrpg.android.habitica.helpers.RxErrorHandler
|
||||
import com.habitrpg.android.habitica.models.responses.UnlockResponse
|
||||
import com.habitrpg.android.habitica.models.user.User
|
||||
import com.habitrpg.android.habitica.ui.adapter.CustomizationRecyclerViewAdapter
|
||||
import com.habitrpg.android.habitica.ui.adapter.CustomizationEquipmentRecyclerViewAdapter
|
||||
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment
|
||||
import com.habitrpg.android.habitica.ui.helpers.MarginDecoration
|
||||
import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator
|
||||
|
|
@ -30,7 +30,7 @@ class AvatarEquipmentFragment : BaseMainFragment() {
|
|||
var category: String? = null
|
||||
private var activeEquipment: String? = null
|
||||
|
||||
internal var adapter: CustomizationRecyclerViewAdapter = CustomizationRecyclerViewAdapter()
|
||||
internal var adapter: CustomizationEquipmentRecyclerViewAdapter = CustomizationEquipmentRecyclerViewAdapter()
|
||||
internal var layoutManager: GridLayoutManager = GridLayoutManager(activity, 2)
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
|
|
@ -39,18 +39,13 @@ class AvatarEquipmentFragment : BaseMainFragment() {
|
|||
val view = inflater.inflate(R.layout.fragment_recyclerview, container, false)
|
||||
|
||||
compositeSubscription.add(adapter.getSelectCustomizationEvents()
|
||||
.flatMap { customization ->
|
||||
userRepository.useCustomization(user, customization.type ?: "", customization.category, customization.identifier ?: "")
|
||||
.flatMap { equipment ->
|
||||
inventoryRepository.equip(user, if (user?.preferences?.costume == true) "costume" else "equipped", equipment.key ?: "")
|
||||
}
|
||||
.subscribe(Consumer { }, RxErrorHandler.handleEmptyError()))
|
||||
compositeSubscription.add(adapter.getUnlockCustomizationEvents()
|
||||
.flatMap<UnlockResponse> { customization ->
|
||||
val user = this.user
|
||||
if (user != null) {
|
||||
userRepository.unlockPath(user, customization)
|
||||
} else {
|
||||
Flowable.empty()
|
||||
}
|
||||
.flatMap<UnlockResponse> {
|
||||
Flowable.empty()
|
||||
}
|
||||
.subscribe(Consumer { }, RxErrorHandler.handleEmptyError()))
|
||||
compositeSubscription.add(adapter.getUnlockSetEvents()
|
||||
|
|
@ -69,7 +64,7 @@ class AvatarEquipmentFragment : BaseMainFragment() {
|
|||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
arguments?.let {
|
||||
val args = AvatarCustomizationFragmentArgs.fromBundle(it)
|
||||
val args = AvatarEquipmentFragmentArgs.fromBundle(it)
|
||||
type = args.type
|
||||
if (args.category.isNotEmpty()) {
|
||||
category = args.category
|
||||
|
|
@ -77,7 +72,7 @@ class AvatarEquipmentFragment : BaseMainFragment() {
|
|||
}
|
||||
|
||||
setGridSpanCount(view.width)
|
||||
val layoutManager = GridLayoutManager(activity, 2)
|
||||
val layoutManager = GridLayoutManager(activity, 4)
|
||||
layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
|
||||
override fun getSpanSize(position: Int): Int {
|
||||
return if (adapter.getItemViewType(position) == 0) {
|
||||
|
|
@ -105,6 +100,9 @@ class AvatarEquipmentFragment : BaseMainFragment() {
|
|||
|
||||
private fun loadEquipment() {
|
||||
val type = this.type ?: return
|
||||
inventoryRepository.getEquipmentType(type, category ?: "").subscribe(Consumer {
|
||||
adapter.setEquipment(it)
|
||||
}, RxErrorHandler.handleEmptyError())
|
||||
}
|
||||
|
||||
private fun setGridSpanCount(width: Int) {
|
||||
|
|
@ -118,15 +116,6 @@ class AvatarEquipmentFragment : BaseMainFragment() {
|
|||
|
||||
fun updateUser(user: User) {
|
||||
this.updateActiveCustomization(user)
|
||||
if (adapter.customizationList.size != 0) {
|
||||
val ownedCustomizations = ArrayList<String>()
|
||||
user.purchased?.customizations?.filter { it.type == this.type }?.mapTo(ownedCustomizations) { it.id }
|
||||
adapter.updateOwnership(ownedCustomizations)
|
||||
} else {
|
||||
this.loadEquipment()
|
||||
}
|
||||
this.adapter.userSize = this.user?.preferences?.size
|
||||
this.adapter.hairColor = this.user?.preferences?.hair?.color
|
||||
this.adapter.gemBalance = user.gemCount
|
||||
adapter.notifyDataSetChanged()
|
||||
}
|
||||
|
|
@ -135,25 +124,16 @@ class AvatarEquipmentFragment : BaseMainFragment() {
|
|||
if (this.type == null || user.preferences == null) {
|
||||
return
|
||||
}
|
||||
val prefs = this.user?.preferences
|
||||
val outfit = if (user.preferences?.costume == true) this.user?.items?.gear?.costume else this.user?.items?.gear?.equipped
|
||||
val activeEquipment = when (this.type) {
|
||||
"skin" -> prefs?.skin
|
||||
"shirt" -> prefs?.shirt
|
||||
"background" -> prefs?.background
|
||||
"hair" -> when (this.category) {
|
||||
"bangs" -> prefs?.hair?.bangs.toString()
|
||||
"base" -> prefs?.hair?.base.toString()
|
||||
"color" -> prefs?.hair?.color
|
||||
"flower" -> prefs?.hair?.flower.toString()
|
||||
"beard" -> prefs?.hair?.beard.toString()
|
||||
"mustache" -> prefs?.hair?.mustache.toString()
|
||||
else -> ""
|
||||
}
|
||||
"headAccessory" -> outfit?.headAccessory
|
||||
"back" -> outfit?.back
|
||||
"eyewear" -> outfit?.eyeWear
|
||||
else -> ""
|
||||
}
|
||||
if (activeEquipment != null) {
|
||||
this.activeEquipment = activeEquipment
|
||||
this.adapter.activeCustomization = activeEquipment
|
||||
this.adapter.activeEquipment = activeEquipment
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -32,13 +32,14 @@ class AvatarOverviewFragment : BaseMainFragment(), AdapterView.OnItemSelectedLis
|
|||
binding.avatarShirtView.setOnClickListener { displayCustomizationFragment("shirt", null) }
|
||||
binding.avatarSkinView.setOnClickListener { displayCustomizationFragment("skin", null) }
|
||||
binding.avatarChairView.setOnClickListener { displayCustomizationFragment("chair", null) }
|
||||
binding.avatarGlassesView.setOnClickListener { displayCustomizationFragment("eyewear", null) }
|
||||
binding.avatarAnimalEarsView.setOnClickListener { displayCustomizationFragment("animal_ears", null) }
|
||||
binding.avatarAnimalTailView.setOnClickListener { displayCustomizationFragment("animal_tails", null) }
|
||||
binding.avatarGlassesView.setOnClickListener { displayEquipmentFragment("eyewear", "glasses") }
|
||||
binding.avatarAnimalEarsView.setOnClickListener { displayEquipmentFragment("headAccessory", "animal") }
|
||||
binding.avatarAnimalTailView.setOnClickListener { displayEquipmentFragment("back", "animal") }
|
||||
binding.avatarHeadbandView.setOnClickListener { displayEquipmentFragment("headAccessory", "headband") }
|
||||
binding.avatarHairColorView.setOnClickListener { displayCustomizationFragment("hair", "color") }
|
||||
binding.avatarHairBangsView.setOnClickListener { displayCustomizationFragment("hair", "bangs") }
|
||||
binding.avatarHairBaseView.setOnClickListener { displayCustomizationFragment("hair", "base") }
|
||||
binding.avatarHairFlowerView.setOnClickListener { displayCustomizationFragment("hair", "flower") }
|
||||
binding.avatarAccentView.setOnClickListener { displayCustomizationFragment("hair", "flower") }
|
||||
binding.avatarHairBeardView.setOnClickListener { displayCustomizationFragment("hair", "beard") }
|
||||
binding.avatarHairMustacheView.setOnClickListener { displayCustomizationFragment("hair", "mustache") }
|
||||
binding.avatarBackgroundView.setOnClickListener { displayCustomizationFragment("background", null) }
|
||||
|
|
@ -56,6 +57,10 @@ class AvatarOverviewFragment : BaseMainFragment(), AdapterView.OnItemSelectedLis
|
|||
MainNavigationController.navigate(AvatarOverviewFragmentDirections.openAvatarDetail(type, category ?: ""))
|
||||
}
|
||||
|
||||
private fun displayEquipmentFragment(type: String, category: String?) {
|
||||
MainNavigationController.navigate(AvatarOverviewFragmentDirections.openAvatarEquipment(type, category ?: ""))
|
||||
}
|
||||
|
||||
fun updateUser(user: User) {
|
||||
this.setSize(user.preferences?.size)
|
||||
setCustomizations(user)
|
||||
|
|
@ -63,32 +68,20 @@ class AvatarOverviewFragment : BaseMainFragment(), AdapterView.OnItemSelectedLis
|
|||
|
||||
private fun setCustomizations(user: User) {
|
||||
binding.avatarShirtView.customizationIdentifier = user.preferences?.size + "_shirt_" + user.preferences?.shirt
|
||||
binding.avatarShirtView.equipmentName = user.preferences?.shirt
|
||||
binding.avatarSkinView.customizationIdentifier = "skin_" + user.preferences?.skin
|
||||
binding.avatarSkinView.equipmentName = user.preferences?.skin
|
||||
val chair = user.preferences?.chair
|
||||
binding.avatarChairView.customizationIdentifier = if (chair?.startsWith("handleless") == true) "chair_$chair" else chair
|
||||
binding.avatarChairView.equipmentName = chair?.removePrefix("chair_")
|
||||
binding.avatarGlassesView.customizationIdentifier = "shop_" + user.equipped?.eyeWear
|
||||
binding.avatarGlassesView.equipmentName = user.equipped?.eyeWear
|
||||
binding.avatarAnimalEarsView.customizationIdentifier = "shop_" + user.equipped?.headAccessory
|
||||
binding.avatarAnimalEarsView.equipmentName = user.equipped?.headAccessory
|
||||
binding.avatarAnimalTailView.customizationIdentifier = "shop_" + user.equipped?.back
|
||||
binding.avatarAnimalTailView.equipmentName = user.equipped?.back
|
||||
binding.avatarGlassesView.equipmentIdentifier = user.equipped?.eyeWear
|
||||
binding.avatarAnimalEarsView.equipmentIdentifier = user.equipped?.headAccessory
|
||||
binding.avatarHeadbandView.equipmentIdentifier = user.equipped?.headAccessory
|
||||
binding.avatarAnimalTailView.equipmentIdentifier = user.equipped?.back
|
||||
binding.avatarHairColorView.customizationIdentifier = if (user.preferences?.hair?.color != null && user.preferences?.hair?.color != "") "hair_bangs_1_" + user.preferences?.hair?.color else ""
|
||||
binding.avatarHairColorView.equipmentName = user.preferences?.hair?.color
|
||||
binding.avatarHairBangsView.customizationIdentifier = if (user.preferences?.hair?.bangs != null && user.preferences?.hair?.bangs != 0) "hair_bangs_" + user.preferences?.hair?.bangs + "_" + user.preferences?.hair?.color else ""
|
||||
binding.avatarHairBangsView.equipmentName = user.preferences?.hair?.bangs.toString()
|
||||
binding.avatarHairBaseView.customizationIdentifier = if (user.preferences?.hair?.base != null && user.preferences?.hair?.base != 0) "hair_base_" + user.preferences?.hair?.base + "_" + user.preferences?.hair?.color else ""
|
||||
binding.avatarHairBaseView.equipmentName = user.preferences?.hair?.base.toString()
|
||||
binding.avatarHairFlowerView.customizationIdentifier = if (user.preferences?.hair?.flower != null && user.preferences?.hair?.flower != 0) "hair_flower_" + user.preferences?.hair?.flower else ""
|
||||
binding.avatarHairFlowerView.equipmentName = user.preferences?.hair?.bangs.toString()
|
||||
binding.avatarAccentView.customizationIdentifier = if (user.preferences?.hair?.flower != null && user.preferences?.hair?.flower != 0) "hair_flower_" + user.preferences?.hair?.flower else ""
|
||||
binding.avatarHairBeardView.customizationIdentifier = if (user.preferences?.hair?.beard != null && user.preferences?.hair?.beard != 0) "hair_beard_" + user.preferences?.hair?.beard + "_" + user.preferences?.hair?.color else ""
|
||||
binding.avatarHairBeardView.equipmentName = user.preferences?.hair?.beard.toString()
|
||||
binding.avatarHairMustacheView.customizationIdentifier = if (user.preferences?.hair?.mustache != null && user.preferences?.hair?.mustache != 0) "hair_mustache_" + user.preferences?.hair?.mustache + "_" + user.preferences?.hair?.color else ""
|
||||
binding.avatarHairMustacheView.equipmentName = user.preferences?.hair?.mustache.toString()
|
||||
binding.avatarBackgroundView.customizationIdentifier = "background_" + user.preferences?.background
|
||||
binding.avatarBackgroundView.equipmentName = user.preferences?.background
|
||||
}
|
||||
|
||||
private fun setSize(size: String?) {
|
||||
|
|
|
|||
|
|
@ -5,40 +5,37 @@ import android.util.AttributeSet
|
|||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import com.habitrpg.android.habitica.R
|
||||
import com.habitrpg.android.habitica.databinding.ItemImageRowBinding
|
||||
import com.habitrpg.android.habitica.extensions.layoutInflater
|
||||
import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils
|
||||
import kotlinx.android.synthetic.main.item_image_row.view.*
|
||||
|
||||
class EquipmentItemRow(context: Context?, attrs: AttributeSet?) : LinearLayout(context, attrs) {
|
||||
class EquipmentItemRow(context: Context, attrs: AttributeSet?) : LinearLayout(context, attrs) {
|
||||
|
||||
private val binding: ItemImageRowBinding = ItemImageRowBinding.inflate(context.layoutInflater, this)
|
||||
var equipmentIdentifier: String? = null
|
||||
set(value) {
|
||||
field = value
|
||||
val imageName = if (equipmentIdentifier?.isNotEmpty() == true && equipmentIdentifier?.endsWith("base_0") == false) "shop_$equipmentIdentifier" else "head_0"
|
||||
DataBindingUtils.loadImage(imageView, imageName)
|
||||
DataBindingUtils.loadImage(binding.imageView, imageName)
|
||||
}
|
||||
|
||||
var customizationIdentifier: String? = null
|
||||
set(value) {
|
||||
field = value
|
||||
val imageName = if (customizationIdentifier?.isNotEmpty() == true) customizationIdentifier else "head_0"
|
||||
DataBindingUtils.loadImage(imageView, imageName)
|
||||
}
|
||||
|
||||
var equipmentName: String? = ""
|
||||
set(value) {
|
||||
field = value
|
||||
valueTextView.text = equipmentName
|
||||
DataBindingUtils.loadImage(binding.imageView, imageName)
|
||||
}
|
||||
|
||||
init {
|
||||
View.inflate(context, R.layout.item_image_row, this)
|
||||
isClickable = true
|
||||
|
||||
val attributes = context?.theme?.obtainStyledAttributes(
|
||||
val attributes = context.theme?.obtainStyledAttributes(
|
||||
attrs,
|
||||
R.styleable.EquipmentItemRow,
|
||||
0, 0)
|
||||
|
||||
titleTextView.text = attributes?.getString(R.styleable.EquipmentItemRow_equipmentTitle)
|
||||
binding.titleTextView.text = attributes?.getString(R.styleable.EquipmentItemRow_equipmentTitle)
|
||||
binding.valueTextView.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ public class EquipmentListDeserializer implements JsonDeserializer<List<Equipmen
|
|||
item.set_int(parsedItem.get_int());
|
||||
item.setTwoHanded(parsedItem.getTwoHanded());
|
||||
item.setMystery(parsedItem.getMystery());
|
||||
item.setGearSet(parsedItem.getGearSet());
|
||||
} else {
|
||||
item.setOwned(itemObject.getAsBoolean());
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue