diff --git a/Habitica/res/layout/shop_armoire_gear.xml b/Habitica/res/layout/shop_armoire_gear.xml
new file mode 100644
index 000000000..f72adffa0
--- /dev/null
+++ b/Habitica/res/layout/shop_armoire_gear.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml
index bae8dfe37..0c27c68f6 100644
--- a/Habitica/res/values/strings.xml
+++ b/Habitica/res/values/strings.xml
@@ -1378,6 +1378,8 @@
Leave Party Finder
This equipment is class-locked
Change class to %s
+ You own all %s gear
+ New gear is released during the seasonal Galas. Until then, theres %d pieces of gear in the Enchanted Armoire to find!
- You
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 16263bfb4..4afd8f3ef 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
@@ -22,9 +22,11 @@ import kotlinx.coroutines.flow.Flow
interface InventoryRepository : BaseRepository {
- fun getArmoireRemainingCount(): Long
+ fun getArmoireRemainingCount(): Flow
fun getInAppRewards(): Flow>
+ fun getInAppReward(key: String): Flow
+
fun getOwnedEquipment(): Flow>
fun getMounts(): Flow>
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 55fe6b4f8..ae27eefa1 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
@@ -39,7 +39,7 @@ class InventoryRepositoryImpl(
return localRepository.getEquipment(searchedKeys)
}
- override fun getArmoireRemainingCount(): Long {
+ override fun getArmoireRemainingCount(): Flow {
return localRepository.getArmoireRemainingCount()
}
@@ -47,6 +47,10 @@ class InventoryRepositoryImpl(
return localRepository.getInAppRewards()
}
+ override fun getInAppReward(key : String) : Flow {
+ return localRepository.getInAppReward(key)
+ }
+
override suspend fun retrieveInAppRewards(): List? {
val rewards = apiClient.retrieveInAppRewards()
if (rewards != null) {
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 6e5b7230e..91d76ffe4 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
@@ -15,7 +15,7 @@ import kotlinx.coroutines.flow.Flow
interface InventoryLocalRepository : ContentLocalRepository {
- fun getArmoireRemainingCount(): Long
+ fun getArmoireRemainingCount(): Flow
fun getOwnedEquipment(): Flow>
fun getMounts(): Flow>
@@ -27,6 +27,8 @@ interface InventoryLocalRepository : ContentLocalRepository {
fun getOwnedPets(userID: String): Flow>
fun getInAppRewards(): Flow>
+ fun getInAppReward(key: String): Flow
+
fun getQuestContent(key: String): Flow
fun getQuestContent(keys: List): Flow>
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 f1cc2859d..58c3c2812 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
@@ -57,7 +57,7 @@ class RealmInventoryLocalRepository(realm: Realm) :
.filter { it.isLoaded }
}
- override fun getArmoireRemainingCount(): Long {
+ override fun getArmoireRemainingCount(): Flow {
return realm.where(Equipment::class.java)
.equalTo("klass", "armoire")
.beginGroup()
@@ -65,7 +65,9 @@ class RealmInventoryLocalRepository(realm: Realm) :
.or()
.isNull("owned")
.endGroup()
- .count()
+ .findAll()
+ .toFlow()
+ .map { it.count() }
}
override fun getOwnedEquipment(type: String): Flow> {
@@ -318,6 +320,16 @@ class RealmInventoryLocalRepository(realm: Realm) :
.filter { it.isLoaded }
}
+ override fun getInAppReward(key: String): Flow {
+ return realm.where(ShopItem::class.java)
+ .equalTo("key", key)
+ .findAll()
+ .toFlow()
+ .filter { it.isLoaded }
+ .map { it.firstOrNull() }
+ .filterNotNull()
+ }
+
override fun saveInAppRewards(onlineItems: List) {
val localItems = realm.where(ShopItem::class.java).findAll().createSnapshot()
executeTransaction {
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ArmoireActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ArmoireActivity.kt
index 57706b907..edce32582 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ArmoireActivity.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ArmoireActivity.kt
@@ -27,6 +27,7 @@ import com.habitrpg.common.habitica.helpers.launchCatching
import com.plattysoft.leonids.ParticleSystem
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.launch
import java.util.Locale
import javax.inject.Inject
@@ -66,9 +67,11 @@ class ArmoireActivity : BaseActivity() {
if (gold == null) {
gold = user?.stats?.gp
}
- val remaining = inventoryRepository.getArmoireRemainingCount()
- binding.equipmentCountView.text = getString(R.string.equipment_remaining, remaining)
- binding.noEquipmentView.visibility = if (remaining > 0) View.GONE else View.VISIBLE
+ lifecycleScope.launchCatching {
+ val remaining = inventoryRepository.getArmoireRemainingCount().firstOrNull() ?: 0
+ binding.equipmentCountView.text = getString(R.string.equipment_remaining, remaining)
+ binding.noEquipmentView.visibility = if (remaining > 0) View.GONE else View.VISIBLE
+ }
}
if (appConfigManager.enableArmoireAds()) {
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/DeathActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/DeathActivity.kt
index 598772dda..7552d08cf 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/DeathActivity.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/DeathActivity.kt
@@ -35,7 +35,7 @@ class DeathActivity : BaseActivity() {
@Inject
lateinit var userViewModel: MainUserViewModel
- override fun getLayoutResId(): Int = R.layout.activity_armoire
+ override fun getLayoutResId(): Int = R.layout.activity_death
override fun getContentView(layoutResId: Int?): View {
binding = ActivityDeathBinding.inflate(layoutInflater)
@@ -66,7 +66,7 @@ class DeathActivity : BaseActivity() {
binding.adButton.visibility = View.INVISIBLE
}
}
- binding.adButton.updateForAdType(AdType.ARMOIRE, lifecycleScope)
+ binding.adButton.updateForAdType(AdType.FAINT, lifecycleScope)
binding.adButton.setOnClickListener {
binding.adButton.state = AdButton.State.LOADING
handler.show()
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ShopRecyclerAdapter.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ShopRecyclerAdapter.kt
index 2ac7cab06..5d61e83ea 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ShopRecyclerAdapter.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/inventory/ShopRecyclerAdapter.kt
@@ -6,7 +6,9 @@ import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.habitrpg.android.habitica.R
+import com.habitrpg.android.habitica.databinding.ShopArmoireGearBinding
import com.habitrpg.android.habitica.databinding.ShopHeaderBinding
import com.habitrpg.android.habitica.extensions.inflate
import com.habitrpg.android.habitica.helpers.MainNavigationController
@@ -19,15 +21,18 @@ import com.habitrpg.android.habitica.ui.viewHolders.SectionViewHolder
import com.habitrpg.android.habitica.ui.viewHolders.ShopItemViewHolder
import com.habitrpg.android.habitica.ui.views.getTranslatedClassName
import com.habitrpg.common.habitica.extensions.fromHtml
+import com.habitrpg.common.habitica.extensions.loadImage
-class ShopRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter() {
+class ShopRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter() {
+ var armoireCount : Int = 0
var onNeedsRefresh: (() -> Unit)? = null
var onShowPurchaseDialog: ((ShopItem, Boolean) -> Unit)? = null
private val items: MutableList = ArrayList()
private var shopIdentifier: String? = null
private var ownedItems: Map = HashMap()
+ var armoireItem: ShopItem? = null
var changeClassEvents: ((String) -> Unit)? = null
@@ -88,11 +93,18 @@ class ShopRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter ShopHeaderViewHolder(parent)
1 -> SectionViewHolder(parent.inflate(R.layout.shop_section_header))
2 -> EmptyStateViewHolder(parent.inflate(emptyViewResource))
+ 3 -> {
+ val viewHolder = ArmoireGearViewHolder(parent.inflate(R.layout.shop_armoire_gear))
+ viewHolder.itemView.setOnClickListener {
+ armoireItem?.let { it1 -> onShowPurchaseDialog?.invoke(it1, true) }
+ }
+ viewHolder
+ }
else -> {
val view = parent.inflate(R.layout.row_shopitem)
val viewHolder = ShopItemViewHolder(view)
@@ -105,28 +117,27 @@ class ShopRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter (obj as? Shop)?.let { (holder as? ShopHeaderViewHolder)?.bind(it, shopSpriteSuffix) }
- ShopCategory::class.java -> {
- val category = obj as? ShopCategory
+ when (obj) {
+ is Shop -> (holder as? ShopHeaderViewHolder)?.bind(obj, shopSpriteSuffix)
+ is ShopCategory -> {
val sectionHolder = holder as? SectionViewHolder ?: return
- sectionHolder.bind(category?.text ?: "")
- if (gearCategories.contains(category)) {
+ sectionHolder.bind(obj.text)
+ if (gearCategories.contains(obj)) {
context?.let { context ->
val adapter = HabiticaClassArrayAdapter(context, R.layout.class_spinner_dropdown_item, gearCategories.map { it.identifier })
sectionHolder.spinnerAdapter = adapter
- sectionHolder.selectedItem = gearCategories.indexOf(category)
+ sectionHolder.selectedItem = gearCategories.indexOf(obj)
sectionHolder.spinnerSelectionChanged = {
if (selectedGearCategory != gearCategories[holder.selectedItem].identifier) {
selectedGearCategory = gearCategories[holder.selectedItem].identifier
}
}
- if (user?.stats?.habitClass != category?.identifier && category?.identifier != "none") {
+ if (user?.stats?.habitClass != obj.identifier && obj.identifier != "none") {
if (user?.hasClass == true) {
sectionHolder.switchClassButton?.setOnClickListener {
changeClassEvents?.invoke(selectedGearCategory)
@@ -146,14 +157,14 @@ class ShopRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter {
- val item = obj as? ShopItem ?: return
+ is ShopItem -> {
val itemHolder = holder as? ShopItemViewHolder ?: return
- val numberOwned = ownedItems[item.key + "-" + item.purchaseType]?.numberOwned ?: 0
- itemHolder.bind(item, item.canAfford(user, 1), numberOwned)
- itemHolder.isPinned = pinnedItemKeys.contains(item.key)
+ val numberOwned = ownedItems[obj.key + "-" + obj.purchaseType]?.numberOwned ?: 0
+ itemHolder.bind(obj, obj.canAfford(user, 1), numberOwned)
+ itemHolder.isPinned = pinnedItemKeys.contains(obj.key)
}
- String::class.java -> (holder as? EmptyStateViewHolder)?.text = obj as? String
+ is String -> (holder as? EmptyStateViewHolder)?.text = obj
+ is Pair<*, *> -> (holder as? ArmoireGearViewHolder)?.bind(obj.first as? String ?: "", obj.second as? Int ?: 0)
}
}
}
@@ -167,14 +178,15 @@ class ShopRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter {
- val category = getSelectedShopCategory()
- category?.text = context?.getString(R.string.class_equipment) ?: ""
- category
+ selectedGearCategory?.text = context?.getString(R.string.class_equipment) ?: ""
+ selectedGearCategory
}
- (getSelectedShopCategory()?.items?.size ?: 0) <= position - 2 -> return context?.getString(R.string.equipment_empty)
- else -> getSelectedShopCategory()?.items?.get(position - 2)
+ (selectedGearCategory?.items?.size ?: 0) <= position - 2 -> return Pair(
+ context?.resources?.let { getTranslatedClassName(it, selectedGearCategory?.identifier) } ?: selectedGearCategory?.identifier, armoireCount)
+ else -> selectedGearCategory?.items?.get(position - 2)
}
} else {
val itemPosition = position - getGearItemCount()
@@ -185,10 +197,11 @@ class ShopRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter 0
- ShopCategory::class.java -> 1
- ShopItem::class.java -> 3
+ override fun getItemViewType(position: Int): Int = when (getItem(position)) {
+ is Shop -> 0
+ is ShopCategory -> 1
+ is Pair<*, *> -> 3
+ is ShopItem -> 4
else -> 2
}
@@ -233,7 +246,7 @@ class ShopRecyclerAdapter : androidx.recyclerview.widget.RecyclerView.Adapter()
adapter?.changeClassEvents = {
showClassChangeDialog(it)
}
+
+ lifecycleScope.launchCatching {
+ inventoryRepository.getInAppReward("armoire").collect {
+ adapter?.armoireItem = it
+ }
+ }
+ lifecycleScope.launchCatching {
+ inventoryRepository.getArmoireRemainingCount().collect {
+ adapter?.armoireCount = it
+ }
+ }
}
if (binding?.recyclerView?.layoutManager == null) {
layoutManager = GridLayoutManager(context, 2)
layoutManager?.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
- return if ((adapter?.getItemViewType(position) ?: 0) < 3) {
+ return if ((adapter?.getItemViewType(position) ?: 0) < 4) {
layoutManager?.spanCount ?: 1
} else {
1
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/MainActivityViewModel.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/MainActivityViewModel.kt
index e1d2cedf3..91802037c 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/MainActivityViewModel.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewmodels/MainActivityViewModel.kt
@@ -113,6 +113,7 @@ class MainActivityViewModel @Inject constructor(
pushNotificationManager.addPushDeviceUsingStoredToken()
}
}
+ inventoryRepository.retrieveInAppRewards()
contentRepository.retrieveContent()
}
viewModelScope.launchCatching {
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt
index ac613f40e..f2f8ea9a1 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/shops/PurchaseDialog.kt
@@ -255,6 +255,10 @@ class PurchaseDialog(context: Context, private val userRepository : UserReposito
lifecycleScope.launchCatching {
userRepository.getUser().filterNotNull().collect { setUser(it) }
}
+
+ if (item.key == "armoire") {
+ pinButton.visibility = View.GONE
+ }
}
private fun setUser(user: User) {