diff --git a/Habitica/res/layout/dialog_pet_suggest_hatch.xml b/Habitica/res/layout/dialog_pet_suggest_hatch.xml
new file mode 100644
index 000000000..57ebae355
--- /dev/null
+++ b/Habitica/res/layout/dialog_pet_suggest_hatch.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml
index f9d45dcce..7e60c15a6 100644
--- a/Habitica/res/values/strings.xml
+++ b/Habitica/res/values/strings.xml
@@ -1027,8 +1027,8 @@
%d%% Complete
Create a Task
Complete a Task
- Hatch a Pet
- Feed a Pet
+ Hatch a new pet
+ Feed a pet
Purchase Equipment
Add a task for something you would like to accomplish this week
Check off any of your tasks to earn rewards
@@ -1058,4 +1058,10 @@
You already have everything you need for all %s pets. Are you sure you want to purchase %d %ss?
Equip
View Onboarding Tasks
+ You\'ll need a %s Egg and %s Potion to hatch this pet
+ You can use a %s Egg and a %s Potion to hatch this pet
+ Hatch Pet
+ Unhatched Pet
+ Magic Potions
+ Magic Potion
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/Animal-Extensions.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/Animal-Extensions.kt
index f8cb2c6bc..102b47cc1 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/Animal-Extensions.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/extensions/Animal-Extensions.kt
@@ -14,6 +14,7 @@ fun Animal.getTranslatedType(c: Context?): String {
"quest" -> c?.getString(R.string.quest).toString()
"wacky" -> c?.getString(R.string.wacky).toString()
"special" -> c?.getString(R.string.special).toString()
+ "premium" -> c?.getString(R.string.magic_potion).toString()
else -> {
type
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/PetDetailRecyclerAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/PetDetailRecyclerAdapter.kt
index b917f88c7..b66dd1c0b 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/PetDetailRecyclerAdapter.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/PetDetailRecyclerAdapter.kt
@@ -10,16 +10,19 @@ import android.widget.TextView
import com.facebook.drawee.view.SimpleDraweeView
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.events.commands.FeedCommand
+import com.habitrpg.android.habitica.extensions.addCloseButton
import com.habitrpg.android.habitica.extensions.inflate
import com.habitrpg.android.habitica.helpers.RxErrorHandler
-import com.habitrpg.android.habitica.models.inventory.Mount
-import com.habitrpg.android.habitica.models.inventory.Pet
+import com.habitrpg.android.habitica.models.inventory.*
+import com.habitrpg.android.habitica.models.user.OwnedItem
import com.habitrpg.android.habitica.models.user.OwnedMount
import com.habitrpg.android.habitica.models.user.OwnedPet
import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils
import com.habitrpg.android.habitica.ui.helpers.bindView
import com.habitrpg.android.habitica.ui.menu.BottomSheetMenu
import com.habitrpg.android.habitica.ui.menu.BottomSheetMenuItem
+import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog
+import com.habitrpg.android.habitica.ui.views.dialogs.PetSuggestHatchDialog
import io.reactivex.BackpressureStrategy
import io.reactivex.Flowable
import io.reactivex.Observable
@@ -38,12 +41,15 @@ class PetDetailRecyclerAdapter(data: OrderedRealmCollection?, autoUpdate: B
private var existingMounts: RealmResults? = null
private var ownedPets: Map? = null
private var ownedMounts: Map? = null
+ private var ownedItems: Map? = null
private val equipEvents = PublishSubject.create()
fun getEquipFlowable(): Flowable {
return equipEvents.toFlowable(BackpressureStrategy.DROP)
}
+ var animalIngredientsRetriever: ((Animal) -> Pair)? = null
+
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PetViewHolder {
return PetViewHolder(parent.inflate(R.layout.pet_detail_item))
}
@@ -68,6 +74,12 @@ class PetDetailRecyclerAdapter(data: OrderedRealmCollection?, autoUpdate: B
this.ownedPets = ownedPets
notifyDataSetChanged()
}
+
+ fun setOwnedItems(ownedItems: Map) {
+ this.ownedItems = ownedItems
+ notifyDataSetChanged()
+ }
+
inner class PetViewHolder(itemView: View) : androidx.recyclerview.widget.RecyclerView.ViewHolder(itemView), View.OnClickListener {
var animal: Pet? = null
var ownedPet: OwnedPet? = null
@@ -88,6 +100,11 @@ class PetDetailRecyclerAdapter(data: OrderedRealmCollection?, autoUpdate: B
return false
}
+ private val canHatch: Boolean
+ get() {
+ return ownedItems?.get(animal?.animal + "-eggs") != null && ownedItems?.get(animal?.color + "-hatchingPotions") != null
+ }
+
init {
itemView.setOnClickListener(this)
}
@@ -126,6 +143,7 @@ class PetDetailRecyclerAdapter(data: OrderedRealmCollection?, autoUpdate: B
override fun onClick(v: View) {
if (!this.isOwned) {
+ showRequirementsDialog()
return
}
val context = context ?: return
@@ -148,5 +166,15 @@ class PetDetailRecyclerAdapter(data: OrderedRealmCollection?, autoUpdate: B
}
menu.show()
}
+
+ private fun showRequirementsDialog() {
+ val context = context ?: return
+ val dialog = PetSuggestHatchDialog(context)
+ animal?.let {
+ val ingredients = animalIngredientsRetriever?.invoke(it)
+ dialog.configure(it, ingredients?.first, ingredients?.second, canHatch)
+ }
+ dialog.show()
+ }
}
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/StableRecyclerAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/StableRecyclerAdapter.kt
index 4245d0ed5..7d6bdcca0 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/StableRecyclerAdapter.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/StableRecyclerAdapter.kt
@@ -10,6 +10,7 @@ import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.GridLayoutManager
import com.facebook.drawee.view.SimpleDraweeView
import com.habitrpg.android.habitica.R
+import com.habitrpg.android.habitica.events.commands.FeedCommand
import com.habitrpg.android.habitica.extensions.inflate
import com.habitrpg.android.habitica.helpers.MainNavigationController
import com.habitrpg.android.habitica.helpers.RxErrorHandler
@@ -18,11 +19,17 @@ import com.habitrpg.android.habitica.ui.activities.MainActivity
import com.habitrpg.android.habitica.ui.fragments.inventory.stable.StableFragmentDirections
import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils
import com.habitrpg.android.habitica.ui.helpers.bindView
+import com.habitrpg.android.habitica.ui.menu.BottomSheetMenu
+import com.habitrpg.android.habitica.ui.menu.BottomSheetMenuItem
import com.habitrpg.android.habitica.ui.viewHolders.SectionViewHolder
import com.habitrpg.android.habitica.ui.views.NPCBannerView
+import io.reactivex.BackpressureStrategy
+import io.reactivex.Flowable
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.functions.Consumer
+import io.reactivex.subjects.PublishSubject
+import org.greenrobot.eventbus.EventBus
class StableRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter() {
@@ -30,6 +37,11 @@ class StableRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter<
var itemType: String? = null
var context: Context? = null
var activity: MainActivity? = null
+ private val equipEvents = PublishSubject.create()
+
+ fun getEquipFlowable(): Flowable {
+ return equipEvents.toFlowable(BackpressureStrategy.DROP)
+ }
private var itemList: List = ArrayList()
@@ -120,7 +132,8 @@ class StableRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter<
fun bind(item: Animal) {
this.animal = item
- titleView.text = if (item.type == "special") {
+ val isIndividualAnimal = item.type == "special" || animal?.type == "wacky"
+ titleView.text = if (isIndividualAnimal) {
item.text
} else {
item.animal
@@ -131,27 +144,33 @@ class StableRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter<
this.ownedTextView.alpha = 1.0f
val imageName = if (itemType == "pets") {
- "Pet_Egg_" + item.animal
+ if (isIndividualAnimal) {
+ "social_Pet-" + animal?.key
+ } else {
+ "Pet_Egg_" + item.animal
+ }
} else {
"Mount_Icon_" + item.key
}
context?.let {
-
- var owned = item.numberOwned
- var totalNum = item.totalNumber
-
+ val owned = item.numberOwned
+ val totalNum = item.totalNumber
this.ownedTextView.text = context?.getString(R.string.pet_ownership_fraction, owned, totalNum)
this.ownedTextView.background = context?.getDrawable(R.drawable.layout_rounded_bg_shopitem_price)
this.ownedTextView.setTextColor(ContextCompat.getColor(it, R.color.black) )
- ownedTextView.visibility = if (animal?.type == "special") View.GONE else View.VISIBLE
+ ownedTextView.visibility = if (isIndividualAnimal) View.GONE else View.VISIBLE
imageView.background = null
-
- DataBindingUtils.loadImage(imageName) {
- val drawable = BitmapDrawable(context?.resources, it)
+ val numberOwned = item.numberOwned == 0
+ DataBindingUtils.loadImage(imageName) {bitmap ->
+ val drawable = if (isIndividualAnimal) {
+ BitmapDrawable(context?.resources, if (numberOwned) bitmap.extractAlpha() else bitmap)
+ } else {
+ BitmapDrawable(context?.resources, bitmap)
+ }
Observable.just(drawable)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(Consumer {
@@ -175,6 +194,20 @@ class StableRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter<
override fun onClick(v: View) {
val animal = this.animal
if (animal != null) {
+ if (animal.type == "special" || animal.type == "wacky") {
+ if (animal.numberOwned == 0) return
+ val context = context ?: return
+ val menu = BottomSheetMenu(context)
+ menu.setTitle(animal.text)
+ menu.addMenuItem(BottomSheetMenuItem(itemView.resources.getString(R.string.equip)))
+ menu.setSelectionRunnable {
+ animal.let {
+ equipEvents.onNext(it.key)
+ }
+ }
+ menu.show()
+ return
+ }
val color = if (animal.type == "special") animal.color else null
if (animal.numberOwned > 0) {
if (itemType == "pets") {
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/PetDetailRecyclerFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/PetDetailRecyclerFragment.kt
index 55e96dc9c..f2d6fc3fd 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/PetDetailRecyclerFragment.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/PetDetailRecyclerFragment.kt
@@ -9,9 +9,12 @@ import com.habitrpg.android.habitica.components.UserComponent
import com.habitrpg.android.habitica.data.InventoryRepository
import com.habitrpg.android.habitica.events.commands.FeedCommand
import com.habitrpg.android.habitica.helpers.RxErrorHandler
+import com.habitrpg.android.habitica.models.inventory.Egg
+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.user.Items
+import com.habitrpg.android.habitica.models.user.OwnedItem
import com.habitrpg.android.habitica.models.user.OwnedMount
import com.habitrpg.android.habitica.models.user.OwnedPet
import com.habitrpg.android.habitica.ui.adapter.inventory.PetDetailRecyclerAdapter
@@ -83,6 +86,11 @@ class PetDetailRecyclerFragment : BaseMainFragment() {
compositeSubscription.add(adapter.getEquipFlowable()
.flatMap { key -> inventoryRepository.equip(user, "pet", key) }
.subscribe(Consumer { }, RxErrorHandler.handleEmptyError()))
+ adapter.animalIngredientsRetriever = {
+ val egg = inventoryRepository.getItems(Egg::class.java, arrayOf(it.animal), null).firstElement().blockingGet().firstOrNull()
+ val potion = inventoryRepository.getItems(HatchingPotion::class.java, arrayOf(it.color), null).firstElement().blockingGet().firstOrNull()
+ Pair(egg as? Egg, potion as? HatchingPotion)
+ }
view.post { setGridSpanCount(view.width) }
}
@@ -122,6 +130,7 @@ class PetDetailRecyclerFragment : BaseMainFragment() {
return@map mountMap
}
.subscribe(Consumer { adapter.setOwnedMounts(it) }, RxErrorHandler.handleEmptyError()))
+ compositeSubscription.add(inventoryRepository.getOwnedItems().subscribe(Consumer { adapter.setOwnedItems(it) }, RxErrorHandler.handleEmptyError()))
compositeSubscription.add(inventoryRepository.getPets(animalType, animalGroup, animalColor).firstElement().subscribe(Consumer> { adapter.updateData(it) }, RxErrorHandler.handleEmptyError()))
compositeSubscription.add(inventoryRepository.getMounts(animalType, animalGroup, animalColor).subscribe(Consumer> { adapter.setExistingMounts(it) }, RxErrorHandler.handleEmptyError()))
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableRecyclerFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableRecyclerFragment.kt
index b82bf9c92..147a49006 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableRecyclerFragment.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/inventory/stable/StableRecyclerFragment.kt
@@ -12,10 +12,7 @@ import com.habitrpg.android.habitica.extensions.getTranslatedType
import com.habitrpg.android.habitica.extensions.inflate
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.inventory.Animal
-import com.habitrpg.android.habitica.models.user.OwnedMount
-import com.habitrpg.android.habitica.models.user.OwnedObject
-import com.habitrpg.android.habitica.models.user.OwnedPet
-import com.habitrpg.android.habitica.models.user.User
+import com.habitrpg.android.habitica.models.user.*
import com.habitrpg.android.habitica.ui.activities.MainActivity
import com.habitrpg.android.habitica.ui.adapter.inventory.StableRecyclerAdapter
import com.habitrpg.android.habitica.ui.fragments.BaseFragment
@@ -91,6 +88,12 @@ class StableRecyclerFragment : BaseFragment() {
adapter?.context = context
recyclerView?.adapter = adapter
recyclerView?.itemAnimator = SafeDefaultItemAnimator()
+
+ adapter?.let {
+ compositeSubscription.add(it.getEquipFlowable()
+ .flatMap { key -> inventoryRepository.equip(user, if (itemType == "pets") "pet" else "mount", key) }
+ .subscribe(Consumer { }, RxErrorHandler.handleEmptyError()))
+ }
}
this.loadItems()
@@ -146,7 +149,7 @@ class StableRecyclerFragment : BaseFragment() {
var lastAnimal: Animal = unsortedAnimals[0] ?: return items
var lastSectionTitle = ""
for (animal in unsortedAnimals) {
- val identifier = if (animal.animal.isNotEmpty() && animal.type != "special") animal.animal else animal.key
+ val identifier = if (animal.animal.isNotEmpty() && (animal.type != "special" && animal.type != "wacky")) animal.animal else animal.key
val lastIdentifier = if (lastAnimal.animal.isNotEmpty()) lastAnimal.animal else lastAnimal.key
if (identifier != lastIdentifier || animal === unsortedAnimals[unsortedAnimals.size - 1]) {
if (!((lastAnimal.type == "premium" || lastAnimal.type == "special") && lastAnimal.numberOwned == 0)) {
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/PetSuggestHatchDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/PetSuggestHatchDialog.kt
new file mode 100644
index 000000000..f8641c21e
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/PetSuggestHatchDialog.kt
@@ -0,0 +1,67 @@
+package com.habitrpg.android.habitica.ui.views.dialogs
+
+import android.content.Context
+import android.graphics.drawable.BitmapDrawable
+import android.view.LayoutInflater
+import com.facebook.drawee.view.SimpleDraweeView
+import com.habitrpg.android.habitica.R
+import com.habitrpg.android.habitica.databinding.DialogPetSuggestHatchBinding
+import com.habitrpg.android.habitica.helpers.MainNavigationController
+import com.habitrpg.android.habitica.helpers.RxErrorHandler
+import com.habitrpg.android.habitica.models.inventory.Animal
+import com.habitrpg.android.habitica.models.inventory.Egg
+import com.habitrpg.android.habitica.models.inventory.HatchingPotion
+import com.habitrpg.android.habitica.ui.activities.MainActivity
+import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils
+import io.reactivex.Observable
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.functions.Consumer
+
+class PetSuggestHatchDialog(context: Context) : HabiticaAlertDialog(context) {
+
+
+ private lateinit var binding: DialogPetSuggestHatchBinding
+
+ init {
+ val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as? LayoutInflater
+ inflater?.let { binding = DialogPetSuggestHatchBinding.inflate(it) }
+ setAdditionalContentView(binding.root)
+ }
+
+ fun configure(pet: Animal, egg: Egg?, potion: HatchingPotion?, canHatch: Boolean) {
+ DataBindingUtils.loadImage(binding.eggView, "Pet_Egg_${pet.animal}")
+ DataBindingUtils.loadImage(binding.hatchingPotionView, "Pet_HatchingPotion_${pet.color}")
+ binding.petTitleView.text = pet.text
+
+
+ if (canHatch) {
+ binding.descriptionView.text = context.getString(R.string.can_hatch_pet,
+ egg?.text ?: pet.animal.capitalize(),
+ potion?.text ?: pet.color.capitalize())
+ addButton(R.string.hatch_pet, true, false) { _, _ ->
+ val thisPotion = potion ?: return@addButton
+ val thisEgg = egg ?: return@addButton
+ (getActivity() as? MainActivity)?.hatchPet(thisPotion, thisEgg)
+ }
+ setTitle(R.string.hatch_pet_title)
+ } else {
+ binding.descriptionView.text = context.getString(R.string.suggest_pet_hatch,
+ egg?.text ?: pet.animal.capitalize(),
+ potion?.text ?: pet.color.capitalize())
+ setTitle(R.string.unhatched_pet)
+ }
+
+ addButton(R.string.close, !canHatch)
+
+ val imageName = "social_Pet-${pet.animal}-${pet.color}"
+ DataBindingUtils.loadImage(imageName) {
+ val resources = context.resources ?: return@loadImage
+ val drawable = BitmapDrawable(resources, it.extractAlpha())
+ Observable.just(drawable)
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(Consumer {
+ binding.petView.background = drawable
+ }, RxErrorHandler.handleEmptyError())
+ }
+ }
+}