Ability to use special items from Items added

This commit is contained in:
Hafiz 2022-02-14 05:51:43 -05:00
parent 741b59b46b
commit dfbcdc7125
8 changed files with 181 additions and 44 deletions

View file

@ -466,6 +466,7 @@
<string name="myster_item_notes">Each month, subscribers will receive a mystery item. This is usually released about one week before the end of the month.</string>
<string name="open">Open</string>>
<string name="is_open">Open</string>
<string name="use_item">Use Item on party member</string>>
<string name="checkInRewardEarned">You earned a %1$s as a reward for your devotion to improving your life.</string>
<string name="nextPrizeUnlocks" tools:ignore="PluralsCandidate">Next prize in %1$d Check-Ins</string>
<string name="pending_approval">pending approval</string>

View file

@ -24,7 +24,6 @@ class ContentRepositoryImpl<T : ContentLocalRepository>(localRepository: T, apiC
return if (forced || now - this.lastContentSync > 300000) {
lastContentSync = now
apiClient.content.doOnNext {
it.special = RealmList()
it.special.add(mysteryItem)
localRepository.saveContent(it)
}

View file

@ -28,6 +28,7 @@ open class RealmContentLocalRepository(realm: Realm) : RealmBaseLocalRepository(
realm1.insertOrUpdate(contentResult.mounts)
realm1.insertOrUpdate(contentResult.spells)
realm1.insertOrUpdate(contentResult.special)
realm1.insertOrUpdate(contentResult.appearances)
realm1.insertOrUpdate(contentResult.backgrounds)
realm1.insertOrUpdate(contentResult.faq)

View file

@ -15,6 +15,7 @@ open class SpecialItem : RealmObject(), Item {
internal var notes: String = ""
override var value: Int = 0
override var event: ItemEvent? = null
var target: String? = null
var isMysteryItem: Boolean = false
companion object {

View file

@ -17,4 +17,19 @@ open class SpecialItems : RealmObject(), BaseObject {
get() {
return seafoam > 0 || shinySeed > 0 || snowball > 0 || spookySparkles > 0
}
fun getSpecialItemCount(key: String): Int{
var inventoryPresent: OwnedItem = ownedItems?.filter { it.key == "inventory_present" }?.single() ?: OwnedItem()
var count = 0
when(key){
"seafoam" -> count = seafoam
"shinySeed" -> count = shinySeed
"snowball" -> count = snowball
"spookySparkles" -> count = spookySparkles
"inventory_present" -> count = inventoryPresent.numberOwned
}
return count
}
}

View file

@ -13,6 +13,7 @@ import com.habitrpg.android.habitica.models.Skill
import com.habitrpg.android.habitica.models.inventory.*
import com.habitrpg.android.habitica.models.user.OwnedItem
import com.habitrpg.android.habitica.models.user.OwnedPet
import com.habitrpg.android.habitica.models.user.SpecialItems
import com.habitrpg.android.habitica.ui.adapter.BaseRecyclerViewAdapter
import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils
import com.habitrpg.android.habitica.ui.menu.BottomSheetMenu
@ -38,6 +39,11 @@ class ItemRecyclerAdapter(val context: Context) : BaseRecyclerViewAdapter<OwnedI
field = value
notifyDataSetChanged()
}
var specialItems: SpecialItems? = null
set(value) {
field = value
notifyDataSetChanged()
}
private val sellItemEvents = PublishSubject.create<OwnedItem>()
private val questInvitationEvents = PublishSubject.create<QuestContent>()
@ -45,6 +51,8 @@ class ItemRecyclerAdapter(val context: Context) : BaseRecyclerViewAdapter<OwnedI
private val startHatchingSubject = PublishSubject.create<Item>()
private val hatchPetSubject = PublishSubject.create<Pair<HatchingPotion, Egg>>()
private val feedPetSubject = PublishSubject.create<Food>()
private val useSpecialSubject = PublishSubject.create<SpecialItem>()
fun getSellItemFlowable(): Flowable<OwnedItem> {
return sellItemEvents.toFlowable(BackpressureStrategy.DROP)
@ -60,6 +68,7 @@ class ItemRecyclerAdapter(val context: Context) : BaseRecyclerViewAdapter<OwnedI
val startHatchingEvents: Flowable<Item> = startHatchingSubject.toFlowable(BackpressureStrategy.DROP)
val hatchPetEvents: Flowable<Pair<HatchingPotion, Egg>> = hatchPetSubject.toFlowable(BackpressureStrategy.DROP)
val feedPetEvents: Flowable<Food> = feedPetSubject.toFlowable(BackpressureStrategy.DROP)
val useSpecialEvents: Flowable<SpecialItem> = useSpecialSubject.toFlowable(BackpressureStrategy.DROP)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
return ItemViewHolder(ItemItemBinding.inflate(context.layoutInflater, parent, false))
@ -111,14 +120,15 @@ class ItemRecyclerAdapter(val context: Context) : BaseRecyclerViewAdapter<OwnedI
val imageName: String?
if (item is QuestContent) {
imageName = "inventory_quest_scroll_" + ownedItem.key
} else if (ownedItem.itemType == "special") {
if (item is SpecialItem){
} else if (item is SpecialItem) {
if (item.key == "inventory_present") {
val sdf = SimpleDateFormat("MM", Locale.getDefault())
val month = sdf.format(Date())
imageName = "inventory_present_$month"
}else{
} else {
imageName = "shop_" + ownedItem.key
}
} else {
val type = when (ownedItem.itemType) {
"eggs" -> "Egg"
@ -161,7 +171,10 @@ class ItemRecyclerAdapter(val context: Context) : BaseRecyclerViewAdapter<OwnedI
val specialItem = item as SpecialItem
if (specialItem.isMysteryItem && ownedItem?.numberOwned ?: 0 > 0) {
menu.addMenuItem(BottomSheetMenuItem(resources.getString(R.string.open)))
} else if (ownedItem?.numberOwned ?: 0 > 0){
menu.addMenuItem(BottomSheetMenuItem(resources.getString(R.string.use_item)))
}
}
menu.setSelectionRunnable { index ->
item?.let { selectedItem ->
@ -181,7 +194,7 @@ class ItemRecyclerAdapter(val context: Context) : BaseRecyclerViewAdapter<OwnedI
questInvitationEvents.onNext(selectedItem)
}
}
is SpecialItem -> openMysteryItemEvents.onNext(selectedItem)
is SpecialItem -> useSpecialSubject.onNext(selectedItem)
}
}
}
@ -209,16 +222,16 @@ class ItemRecyclerAdapter(val context: Context) : BaseRecyclerViewAdapter<OwnedI
}
}
fun setSpecialItems(skillItems: List<Skill>, ownedItems: MutableList<OwnedItem>){
fun setSpecialItems(skillItems: List<Item>){
val transformationItems: MutableList<OwnedItem> = mutableListOf()
for (item in skillItems){
val ownedTransformationItem = OwnedItem()
ownedTransformationItem.key = item.key
ownedTransformationItem.itemType = item.habitClass
ownedTransformationItem.numberOwned = 5 //Test
ownedTransformationItem.itemType = "special"
ownedTransformationItem.numberOwned = specialItems?.getSpecialItemCount(item.key) ?: 0
transformationItems.add(ownedTransformationItem)
}
data = ownedItems + transformationItems
data = transformationItems
notifyDataSetChanged()
}
}

View file

@ -1,9 +1,15 @@
package com.habitrpg.android.habitica.ui.fragments.inventory.items
import android.app.Activity
import android.content.Intent
import android.graphics.drawable.BitmapDrawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.components.UserComponent
@ -16,18 +22,28 @@ import com.habitrpg.android.habitica.extensions.subscribeWithErrorHandler
import com.habitrpg.android.habitica.helpers.MainNavigationController
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.interactors.HatchPetUseCase
import com.habitrpg.android.habitica.models.Skill
import com.habitrpg.android.habitica.models.inventory.*
import com.habitrpg.android.habitica.models.responses.SkillResponse
import com.habitrpg.android.habitica.models.user.OwnedItem
import com.habitrpg.android.habitica.models.user.OwnedPet
import com.habitrpg.android.habitica.models.user.User
import com.habitrpg.android.habitica.ui.activities.BaseActivity
import com.habitrpg.android.habitica.ui.activities.MainActivity
import com.habitrpg.android.habitica.ui.activities.SkillMemberActivity
import com.habitrpg.android.habitica.ui.activities.SkillTasksActivity
import com.habitrpg.android.habitica.ui.adapter.inventory.ItemRecyclerAdapter
import com.habitrpg.android.habitica.ui.fragments.BaseFragment
import com.habitrpg.android.habitica.ui.helpers.EmptyItem
import com.habitrpg.android.habitica.ui.helpers.SafeDefaultItemAnimator
import com.habitrpg.android.habitica.ui.helpers.loadImage
import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper
import com.habitrpg.android.habitica.ui.views.HabiticaSnackbar
import com.habitrpg.android.habitica.ui.views.dialogs.OpenedMysteryitemDialog
import io.reactivex.rxjava3.core.Flowable
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import java.util.ArrayList
import javax.inject.Inject
class ItemRecyclerFragment : BaseFragment<FragmentItemsBinding>(), SwipeRefreshLayout.OnRefreshListener {
@ -46,6 +62,7 @@ class ItemRecyclerFragment : BaseFragment<FragmentItemsBinding>(), SwipeRefreshL
var transformationItems: MutableList<OwnedItem> = mutableListOf()
var itemTypeText: String? = null
var user: User? = null
private var selectedSpecialItem: SpecialItem? = null
internal var layoutManager: androidx.recyclerview.widget.LinearLayoutManager? = null
override var binding: FragmentItemsBinding? = null
@ -91,7 +108,8 @@ class ItemRecyclerFragment : BaseFragment<FragmentItemsBinding>(), SwipeRefreshL
adapter = ItemRecyclerAdapter(context)
}
binding?.recyclerView?.adapter = adapter
adapter?.specialItems = this.user?.items?.special
adapter?.useSpecialEvents?.subscribeWithErrorHandler { onSpecialItemSelected(it) }?.let { compositeSubscription.add(it) }
adapter?.let { adapter ->
compositeSubscription.add(
adapter.getSellItemFlowable()
@ -204,35 +222,72 @@ class ItemRecyclerFragment : BaseFragment<FragmentItemsBinding>(), SwipeRefreshL
else -> Egg::class.java
}
itemType?.let { type ->
compositeSubscription.add(
inventoryRepository.getOwnedItems(type)
.map { it.distinctBy { it.key } }
.doOnNext { items ->
adapter?.data = items
if (itemType == "special") {
transformationItems = items.toMutableList()
userRepository.getTransformationItems()
.subscribe { skillItems -> adapter?.setSpecialItems(skillItems, transformationItems) }
if (type != "special"){
compositeSubscription.add(
inventoryRepository.getOwnedItems(type)
.map { it.distinctBy { it.key } }
.doOnNext { items ->
adapter?.data = items
// if (itemType == "special") {
// transformationItems = items.toMutableList()
// userRepository.getTransformationItems() //Get from RealmInventoryLocalRepository
// .subscribe { skillItems -> adapter?.setSpecialItems(skillItems, transformationItems) }
// }
}
}
.map { items -> items.mapNotNull { it.key } }
.flatMap {
inventoryRepository.getItems(itemClass, it.toTypedArray())
}
.map {
val itemMap = mutableMapOf<String, Item>()
for (item in it) {
itemMap[item.key] = item
.map { items -> items.mapNotNull { it.key } }
.flatMap {
inventoryRepository.getItems(itemClass, it.toTypedArray())
}
itemMap
.map {
val itemMap = mutableMapOf<String, Item>()
for (item in it) {
itemMap[item.key] = item
}
itemMap
}
.subscribe(
{ items ->
adapter?.items = items
},
RxErrorHandler.handleEmptyError()
)
)
} else {
val specialItems = user?.items?.special
val ownedItems = ArrayList<String>()
if (specialItems != null) {
ownedItems.add("inventory_present")
if (specialItems.snowball > 0) {
ownedItems.add("snowball")
}
.subscribe(
{ items ->
adapter?.items = items
},
RxErrorHandler.handleEmptyError()
)
)
if (specialItems.shinySeed > 0) {
ownedItems.add("shinySeed")
}
if (specialItems.seafoam > 0) {
ownedItems.add("seafoam")
}
if (specialItems.spookySparkles > 0) {
ownedItems.add("spookySparkles")
}
}
if (ownedItems.size == 0) {
ownedItems.add("")
}
compositeSubscription.add(
inventoryRepository.getItems(SpecialItem::class.java, ownedItems.toTypedArray())
.map { it.distinctBy { it.key } }
.doOnNext { items ->
adapter?.setSpecialItems(items)
val itemMap = mutableMapOf<String, Item>()
for (item in items) {
itemMap[item.key] = item
}
adapter?.items = itemMap
}
.subscribe()
)
}
}
compositeSubscription.add(inventoryRepository.getPets().subscribe({ adapter?.setExistingPets(it) }, RxErrorHandler.handleEmptyError()))
@ -251,6 +306,51 @@ class ItemRecyclerFragment : BaseFragment<FragmentItemsBinding>(), SwipeRefreshL
MainNavigationController.navigate(R.id.marketFragment)
}
private fun onSpecialItemSelected(specialItem: SpecialItem) {
selectedSpecialItem = specialItem
val intent = Intent(activity, SkillMemberActivity::class.java)
memberSelectionResult.launch(intent)
}
private val memberSelectionResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
if (it.resultCode == Activity.RESULT_OK) {
useSpecialItem(selectedSpecialItem, it.data?.getStringExtra("member_id"))
}
}
private fun useSpecialItem(specialItem: SpecialItem?, memberID: String? = null) {
if (specialItem == null || memberID == null) {
return
}
val observable: Flowable<SkillResponse> = userRepository.useSkill(specialItem.key, specialItem.target, memberID)
compositeSubscription.add(
observable.subscribe(
{ skillResponse -> this.displaySkillResult(specialItem) },
RxErrorHandler.handleEmptyError()
)
)
}
private fun displaySkillResult(specialItem: SpecialItem?) {
if (!isAdded) return
val activity = activity as? MainActivity
activity?.let {
HabiticaSnackbar.showSnackbar(
it.snackbarContainer,
context?.getString(R.string.used_skill_without_mana, specialItem?.text),
HabiticaSnackbar.SnackbarDisplayType.BLUE
)
}
compositeSubscription.add(
userRepository.retrieveUser(false).subscribe({ }, RxErrorHandler.handleEmptyError())
)
}
companion object {
private const val ITEM_TYPE_KEY = "CLASS_TYPE_KEY"

View file

@ -11,14 +11,7 @@ import com.habitrpg.android.habitica.models.ContentGear
import com.habitrpg.android.habitica.models.ContentResult
import com.habitrpg.android.habitica.models.FAQArticle
import com.habitrpg.android.habitica.models.Skill
import com.habitrpg.android.habitica.models.inventory.Customization
import com.habitrpg.android.habitica.models.inventory.Egg
import com.habitrpg.android.habitica.models.inventory.Equipment
import com.habitrpg.android.habitica.models.inventory.Food
import com.habitrpg.android.habitica.models.inventory.HatchingPotion
import com.habitrpg.android.habitica.models.inventory.Mount
import com.habitrpg.android.habitica.models.inventory.Pet
import com.habitrpg.android.habitica.models.inventory.QuestContent
import com.habitrpg.android.habitica.models.inventory.*
import io.realm.RealmList
import java.lang.reflect.Type
@ -101,6 +94,20 @@ class ContentDeserializer : JsonDeserializer<ContentResult> {
result.spells.add(skill)
}
}
if (obj.has("special")) {//ToDo add special
for ((classname, value) in obj.getAsJsonObject("special").entrySet()) {
val skillItem = value.asJsonObject
val special = SpecialItem()
special.key = skillItem.get("key").asString
special.text = skillItem.get("text").asString
special.notes = skillItem.get("notes").asString
special.target = skillItem.get("target").asString
special.value = skillItem.get("value").asInt
result.special.add(special)
}
}
result.appearances = context.deserialize(obj.get("appearances"), object : TypeToken<RealmList<Customization>>() {}.type)
result.backgrounds = context.deserialize(obj.get("backgrounds"), object : TypeToken<RealmList<Customization>>() {}.type)
val noBackground = Customization()