diff --git a/Habitica/build.gradle b/Habitica/build.gradle index 1e388513d..9dc5e73df 100644 --- a/Habitica/build.gradle +++ b/Habitica/build.gradle @@ -163,7 +163,7 @@ android { 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 2485 - versionName "2.7.1" + versionName "2.8" } viewBinding { diff --git a/Habitica/res/layout/pet_detail_item.xml b/Habitica/res/layout/pet_detail_item.xml index 99591a480..4b949e17a 100644 --- a/Habitica/res/layout/pet_detail_item.xml +++ b/Habitica/res/layout/pet_detail_item.xml @@ -22,6 +22,8 @@ android:progressTint="@color/green_100" android:progressBackgroundTint="@color/gray_600" android:layout_marginTop="4dp" + android:layout_marginStart="9dp" + android:layout_marginEnd="9dp" android:max="50" /> 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 + You still need a %s Egg to hatch this pet + You still need a %s Potion to hatch this pet + You need a %s and %s Potion to hatch this pet + You still need a %s Egg to hatch this pet again + You still need a %s Potion to hatch this pet again + You need a %s and %s Potion to hatch this pet again + Combine your %s Egg and %s Potion to hatch this pet! Hatch Pet Unhatched Pet + Hatch Pet again Magic Potions Magic Potion Use Saddle + Hatch your Pet + Hatch diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/InventoryRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/InventoryRepository.kt index 38fc6aa0b..9563810cc 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/InventoryRepository.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/InventoryRepository.kt @@ -33,8 +33,8 @@ interface InventoryRepository : BaseRepository { fun getOwnedEquipment(type: String): Flowable> fun getEquipmentType(type: String, set: String): Flowable> - fun getOwnedItems(itemType: String): Flowable> - fun getOwnedItems(): Flowable> + fun getOwnedItems(itemType: String, includeZero: Boolean = false): Flowable> + fun getOwnedItems(includeZero: Boolean = false): Flowable> fun getEquipment(key: String): Flowable diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/InventoryRepositoryImpl.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/InventoryRepositoryImpl.kt index 121d987b1..f51c50c29 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/InventoryRepositoryImpl.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/InventoryRepositoryImpl.kt @@ -50,12 +50,12 @@ class InventoryRepositoryImpl(localRepository: InventoryLocalRepository, apiClie return localRepository.getEquipmentType(type, set) } - override fun getOwnedItems(itemType: String): Flowable> { - return localRepository.getOwnedItems(itemType, userID) + override fun getOwnedItems(itemType: String, includeZero: Boolean): Flowable> { + return localRepository.getOwnedItems(itemType, userID, includeZero) } - override fun getOwnedItems(): Flowable> { - return localRepository.getOwnedItems(userID) + override fun getOwnedItems(includeZero: Boolean): Flowable> { + return localRepository.getOwnedItems(userID, includeZero) } override fun getItems(itemClass: Class, keys: Array, user: User?): Flowable> { @@ -111,7 +111,7 @@ class InventoryRepositoryImpl(localRepository: InventoryLocalRepository, apiClie } override fun sellItem(user: User?, type: String, key: String): Flowable { - return localRepository.getOwnedItem(userID, type, key) + return localRepository.getOwnedItem(userID, type, key, true) .flatMap { item -> sellItem(user, item) } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/InventoryLocalRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/InventoryLocalRepository.kt index 08331e26e..fb49d0342 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/InventoryLocalRepository.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/InventoryLocalRepository.kt @@ -31,8 +31,8 @@ interface InventoryLocalRepository : ContentLocalRepository { fun getOwnedEquipment(type: String): Flowable> fun getItems(itemClass: Class, keys: Array, user: User?): Flowable> - fun getOwnedItems(itemType: String, userID: String): Flowable> - fun getOwnedItems(userID: String): Flowable> + fun getOwnedItems(itemType: String, userID: String, includeZero: Boolean): Flowable> + fun getOwnedItems(userID: String, includeZero: Boolean): Flowable> fun getEquipmentType(type: String, set: String): Flowable> fun getEquipment(key: String): Flowable @@ -45,7 +45,7 @@ interface InventoryLocalRepository : ContentLocalRepository { fun changeOwnedCount(item: OwnedItem, amountToAdd: Int?) fun getItem(type: String, key: String): Flowable - fun getOwnedItem(userID: String, type: String, key: String): Flowable + fun getOwnedItem(userID: String, type: String, key: String, includeZero: Boolean): Flowable fun decrementMysteryItemCount(user: User?) fun saveInAppRewards(onlineItems: List) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmInventoryLocalRepository.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmInventoryLocalRepository.kt index 2d5aeb0d6..56f292412 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmInventoryLocalRepository.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/local/implementation/RealmInventoryLocalRepository.kt @@ -79,10 +79,12 @@ class RealmInventoryLocalRepository(realm: Realm, private val context: Context) .filter { it.isLoaded } } - override fun getOwnedItems(itemType: String, userID: String): Flowable> { - return realm.where(OwnedItem::class.java) - .greaterThan("numberOwned", 0) - .equalTo("itemType", itemType) + override fun getOwnedItems(itemType: String, userID: String, includeZero: Boolean): Flowable> { + var query = realm.where(OwnedItem::class.java) + if (!includeZero) { + query = query.greaterThan("numberOwned", 0) + } + return query.equalTo("itemType", itemType) .equalTo("userID", userID) .sort("key") .findAll() @@ -95,10 +97,12 @@ class RealmInventoryLocalRepository(realm: Realm, private val context: Context) .filter { it.isLoaded } } - override fun getOwnedItems(userID: String): Flowable> { - return realm.where(OwnedItem::class.java) - .greaterThan("numberOwned", 0) - .equalTo("userID", userID) + override fun getOwnedItems(userID: String, includeZero: Boolean): Flowable> { + var query = realm.where(OwnedItem::class.java) + if (!includeZero) { + query = query.greaterThan("numberOwned", 0) + } + return query.equalTo("userID", userID) .findAll() .asFlowable() .map { @@ -185,7 +189,7 @@ class RealmInventoryLocalRepository(realm: Realm, private val context: Context) } override fun changeOwnedCount(type: String, key: String, userID: String, amountToAdd: Int) { - getOwnedItem(userID, type, key).firstElement().subscribe( Consumer { changeOwnedCount(it, amountToAdd)}, RxErrorHandler.handleEmptyError()) + getOwnedItem(userID, type, key, true).firstElement().subscribe( Consumer { changeOwnedCount(it, amountToAdd)}, RxErrorHandler.handleEmptyError()) } override fun changeOwnedCount(item: OwnedItem, amountToAdd: Int?) { @@ -194,13 +198,15 @@ class RealmInventoryLocalRepository(realm: Realm, private val context: Context) } } - override fun getOwnedItem(userID: String, type: String, key: String): Flowable { - return realm.where(OwnedItem::class.java) + override fun getOwnedItem(userID: String, type: String, key: String, includeZero: Boolean): Flowable { + var query = realm.where(OwnedItem::class.java) .equalTo("itemType", type) .equalTo("key", key) .equalTo("userID", userID) - .greaterThan("numberOwned", 0) - .findFirstAsync() + if (!includeZero) { + query = query.greaterThan("numberOwned", 0) + } + return query.findFirstAsync() .asFlowable() .filter { realmObject -> realmObject.isLoaded } } 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 db4aa7abb..bb7e121db 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 @@ -114,11 +114,11 @@ class PetDetailRecyclerAdapter(data: OrderedRealmCollection?, autoUpdate: B private val hasEgg: Boolean get() { - return ownedItems?.get(animal?.animal + "-eggs") != null + return ownedItems?.get(animal?.animal + "-eggs")?.numberOwned ?: 0 > 0 } private val hasPotion: Boolean get() { - return ownedItems?.get(animal?.color + "-hatchingPotions") != null + return ownedItems?.get(animal?.color + "-hatchingPotions")?.numberOwned ?: 0 > 0 } private val canHatch: Boolean @@ -223,7 +223,14 @@ class PetDetailRecyclerAdapter(data: OrderedRealmCollection?, autoUpdate: B val dialog = PetSuggestHatchDialog(context) animal?.let { val ingredients = animalIngredientsRetriever?.invoke(it) - dialog.configure(it, ingredients?.first, ingredients?.second, canHatch) + dialog.configure(it, + ingredients?.first, + ingredients?.second, + hasEgg, + hasPotion, + ownedItems?.get(animal?.animal + "-eggs") != null, + ownedItems?.get(animal?.color + "-hatchingPotions") != null, + ownedMounts?.containsKey(it.key) == true) } dialog.show() } 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 2633da27c..e1944828b 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 @@ -129,7 +129,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.getOwnedItems(true).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/views/dialogs/PetSuggestHatchDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/dialogs/PetSuggestHatchDialog.kt index f8641c21e..31bb00483 100644 --- 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 @@ -3,20 +3,27 @@ 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 android.widget.FrameLayout +import android.widget.LinearLayout +import android.widget.TextView +import androidx.core.content.ContextCompat 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.extensions.dpToPx 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.models.inventory.Item import com.habitrpg.android.habitica.ui.activities.MainActivity import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils +import com.habitrpg.android.habitica.ui.views.CurrencyView +import io.reactivex.Flowable import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.functions.Consumer + class PetSuggestHatchDialog(context: Context) : HabiticaAlertDialog(context) { @@ -28,35 +35,101 @@ class PetSuggestHatchDialog(context: Context) : HabiticaAlertDialog(context) { setAdditionalContentView(binding.root) } - fun configure(pet: Animal, egg: Egg?, potion: HatchingPotion?, canHatch: Boolean) { + fun configure(pet: Animal, egg: Egg?, potion: HatchingPotion?, hasEgg: Boolean, hasPotion: Boolean, hasUnlockedEgg: Boolean, hasUnlockedPotion: Boolean, hasMount: Boolean) { DataBindingUtils.loadImage(binding.eggView, "Pet_Egg_${pet.animal}") DataBindingUtils.loadImage(binding.hatchingPotionView, "Pet_HatchingPotion_${pet.color}") binding.petTitleView.text = pet.text + binding.eggView.alpha = if (hasEgg) 1.0f else 0.5f + binding.hatchingPotionView.alpha = if (hasPotion) 1.0f else 0.5f - if (canHatch) { + val eggName = egg?.text ?: pet.animal.capitalize() + val potionName = potion?.text ?: pet.color.capitalize() + + if (hasEgg && hasPotion) { 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) { _, _ -> + eggName, + potionName) + addButton(R.string.hatch, true, false) { _, _ -> val thisPotion = potion ?: return@addButton val thisEgg = egg ?: return@addButton (getActivity() as? MainActivity)?.hatchPet(thisPotion, thisEgg) } - setTitle(R.string.hatch_pet_title) + if (hasMount) { + setTitle(R.string.hatch_your_pet) + } else { + setTitle(R.string.hatch_pet_title) + } + addButton(R.string.close, false) } else { - binding.descriptionView.text = context.getString(R.string.suggest_pet_hatch, - egg?.text ?: pet.animal.capitalize(), - potion?.text ?: pet.color.capitalize()) + if (hasMount) { + if (!hasEgg && !hasPotion) { + binding.descriptionView.text = context.getString(R.string.suggest_pet_hatch_again_missing_both, eggName, potionName) + } else if (!hasEgg) { + binding.descriptionView.text = context.getString(R.string.suggest_pet_hatch_again_missing_egg, eggName) + } else { + binding.descriptionView.text = context.getString(R.string.suggest_pet_hatch_again_missing_potion, potionName) + } + } else { + if (!hasEgg && !hasPotion) { + binding.descriptionView.text = context.getString(R.string.suggest_pet_hatch_missing_both, eggName, potionName) + } else if (!hasEgg) { + binding.descriptionView.text = context.getString(R.string.suggest_pet_hatch_missing_egg, eggName) + } else { + binding.descriptionView.text = context.getString(R.string.suggest_pet_hatch_missing_potion, potionName) + } + } + + var hatchPrice = 0 + if (!hasEgg) { + hatchPrice = getItemPrice(pet, egg, hasUnlockedEgg) + } + + if (!hasPotion) { + hatchPrice = getItemPrice(pet, potion, hasUnlockedPotion) + + } + + addButton(R.string.close, true) + + if (hatchPrice > 0) { + val linearLayout = LinearLayout(context) + val label = TextView(context) + label.setText(R.string.hatch) + label.setTextColor(ContextCompat.getColor(context, R.color.colorPrimary)) + linearLayout.addView(label) + val layoutParams: LinearLayout.LayoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, + LinearLayout.LayoutParams.WRAP_CONTENT) + layoutParams.setMargins(0, 0, 4.dpToPx(context), 0) + label.layoutParams = layoutParams + val priceView = CurrencyView(context, "gems", true) + priceView.value = hatchPrice.toDouble() + linearLayout.addView(priceView) + addButton(linearLayout, true) { _, _ -> + val activity = (getActivity() as? MainActivity) ?: return@addButton + val thisPotion = potion ?: return@addButton + val thisEgg = egg ?: return@addButton + var observable: Flowable = Flowable.just("") + if (!hasEgg) { + observable = observable.flatMap { activity.inventoryRepository.purchaseItem("eggs", thisEgg.key, 1) } + } + if (!hasPotion) { + observable = observable.flatMap { activity.inventoryRepository.purchaseItem("hatchingPotions", thisPotion.key, 1) } + } + observable.subscribe(Consumer { + (getActivity() as? MainActivity)?.hatchPet(thisPotion, thisEgg) + }, RxErrorHandler.handleEmptyError()) + } + } + 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()) + val drawable = BitmapDrawable(resources, if (hasMount) it else it.extractAlpha()) Observable.just(drawable) .observeOn(AndroidSchedulers.mainThread()) .subscribe(Consumer { @@ -64,4 +137,11 @@ class PetSuggestHatchDialog(context: Context) : HabiticaAlertDialog(context) { }, RxErrorHandler.handleEmptyError()) } } + + private fun getItemPrice(pet: Animal, item: Item?, hasUnlocked: Boolean): Int { + if (pet.type == "drop" || (pet.type == "quest" && hasUnlocked)) { + return item?.value ?: 0 + } + return 0 + } }