diff --git a/Habitica/AndroidManifest.xml b/Habitica/AndroidManifest.xml index ad0c1e7db..60a1a8bc6 100644 --- a/Habitica/AndroidManifest.xml +++ b/Habitica/AndroidManifest.xml @@ -22,7 +22,7 @@ android:label="@string/app_name" android:theme="@style/MainAppTheme" android:fullBackupContent="@xml/backup_descriptor" - android:configChanges="orientation" + android:configChanges="orientation|smallestScreenSize|screenLayout" android:networkSecurityConfig="@xml/network_security_config"> + + + + + diff --git a/Habitica/res/layout-w600dp/activity_main.xml b/Habitica/res/layout-sw600dp/activity_main.xml similarity index 100% rename from Habitica/res/layout-w600dp/activity_main.xml rename to Habitica/res/layout-sw600dp/activity_main.xml diff --git a/Habitica/res/layout/fragment_subscription_content.xml b/Habitica/res/layout/fragment_subscription_content.xml index 7a89bd30b..f803a90fa 100644 --- a/Habitica/res/layout/fragment_subscription_content.xml +++ b/Habitica/res/layout/fragment_subscription_content.xml @@ -105,11 +105,6 @@ android:orientation="vertical" android:padding="24dp"> - - + + + android:textStyle="italic"/> diff --git a/Habitica/res/layout/subscription_details.xml b/Habitica/res/layout/subscription_details.xml index dbdd77410..650178657 100644 --- a/Habitica/res/layout/subscription_details.xml +++ b/Habitica/res/layout/subscription_details.xml @@ -9,25 +9,40 @@ tools:background="@color/content_background" android:paddingBottom="16dp"> + + + + app:strokeColor="@color/green_100" + app:strokeWidth="3dp"> + android:textColor="@color/green_500" /> @@ -59,6 +74,7 @@ Belongs to Challenge Has Reminder Has Tag - Subscribing supports our small team and help keeps Habitica running + Subscribing supports our small team and helps keep Habitica running Stay motivated with even more rewards when you subscribe Free Monthly Gems Monthly Mystic Hourglass @@ -407,6 +407,7 @@ Never miss an item with 1 Mystic Hourglass a month to use in the Time Travelers Shop! Subscribe now to get an exclusive set now and receive new items every month! Subscribe now to get this %s and receive new items every month! + Stay decked out in the latest exclusive gear. Subscribe now to get %1$s’s %2$s! Receive the Royal Purple Jackalope pet when you become a new subscriber. Avoid losing your progress with an instant heal when you run out of HP once a day! Get a Royal Purple Jackalope plus double the Eggs, Hatching Potions, and Food each day to grow your Pet collection! @@ -1550,6 +1551,8 @@ Gem Cap Get 12 Mystic Hourglasses immediately after your first 12 month subscription! 12 Mystic Hourglasses + Thanks for subscribing + Set 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 0ec6ade8f..ed00457f6 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 @@ -2,6 +2,7 @@ package com.habitrpg.android.habitica.data import com.habitrpg.android.habitica.models.inventory.Egg import com.habitrpg.android.habitica.models.inventory.Equipment +import com.habitrpg.android.habitica.models.inventory.EquipmentSet import com.habitrpg.android.habitica.models.inventory.Food import com.habitrpg.android.habitica.models.inventory.HatchingPotion import com.habitrpg.android.habitica.models.inventory.Item @@ -153,6 +154,7 @@ interface InventoryRepository : BaseRepository { fun getItems(itemClass: Class): Flow> fun getLatestMysteryItem(): Flow + fun getLatestMysteryItemAndSet(): Flow> fun getItem( type: String, 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 34997677e..e5891b493 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 @@ -8,6 +8,7 @@ import com.habitrpg.android.habitica.data.local.InventoryLocalRepository import com.habitrpg.android.habitica.helpers.AppConfigManager import com.habitrpg.android.habitica.models.inventory.Egg import com.habitrpg.android.habitica.models.inventory.Equipment +import com.habitrpg.android.habitica.models.inventory.EquipmentSet import com.habitrpg.android.habitica.models.inventory.Food import com.habitrpg.android.habitica.models.inventory.HatchingPotion import com.habitrpg.android.habitica.models.inventory.Item @@ -197,6 +198,10 @@ class InventoryRepositoryImpl( return localRepository.getLatestMysteryItem() } + override fun getLatestMysteryItemAndSet(): Flow> { + return localRepository.getLatestMysteryItemAndSet() + } + override fun getItem( type: String, key: String, 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 e14c162ee..ee2868044 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 @@ -1,6 +1,7 @@ package com.habitrpg.android.habitica.data.local import com.habitrpg.android.habitica.models.inventory.Equipment +import com.habitrpg.android.habitica.models.inventory.EquipmentSet import com.habitrpg.android.habitica.models.inventory.Item import com.habitrpg.android.habitica.models.inventory.Mount import com.habitrpg.android.habitica.models.inventory.Pet @@ -118,6 +119,7 @@ interface InventoryLocalRepository : ContentLocalRepository { ) fun getLatestMysteryItem(): Flow + fun getLatestMysteryItemAndSet(): Flow> fun soldItem( userID: String, 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 c5233cb0a..8a15cd5b3 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 @@ -3,6 +3,7 @@ package com.habitrpg.android.habitica.data.local.implementation import com.habitrpg.android.habitica.data.local.InventoryLocalRepository import com.habitrpg.android.habitica.models.inventory.Egg import com.habitrpg.android.habitica.models.inventory.Equipment +import com.habitrpg.android.habitica.models.inventory.EquipmentSet import com.habitrpg.android.habitica.models.inventory.Food import com.habitrpg.android.habitica.models.inventory.HatchingPotion import com.habitrpg.android.habitica.models.inventory.Item @@ -455,12 +456,33 @@ class RealmInventoryLocalRepository(realm: Realm) : .filter { it.isLoaded && it.size > 0 } .map { val format = SimpleDateFormat("yyyyMM", Locale.US) - it.first { - it.key?.contains(format.format(Date())) == true + it.first { equipment -> + equipment.key?.contains(format.format(Date())) == true } } } + private fun getLatestMysterySet(): Flow { + return realm.where(EquipmentSet::class.java) + .equalTo("pinType", "mystery_set") + .sort("key", Sort.DESCENDING) + .findAll() + .toFlow() + .filter { it.isLoaded } + .map { + val format = SimpleDateFormat("yyyyMM", Locale.US) + it.firstOrNull() { set -> + set.key.contains(format.format(Date())) + } + } + } + + override fun getLatestMysteryItemAndSet(): Flow> { + return getLatestMysteryItem().combine(getLatestMysterySet()) { item, set -> + Pair(item, set) + } + } + override fun soldItem( userID: String, updatedUser: User, diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/EquipmentSet.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/EquipmentSet.kt new file mode 100644 index 000000000..3cbd1a65b --- /dev/null +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/inventory/EquipmentSet.kt @@ -0,0 +1,11 @@ +package com.habitrpg.android.habitica.models.inventory + +import io.realm.RealmObject +import io.realm.annotations.PrimaryKey + +open class EquipmentSet: RealmObject() { + @PrimaryKey + var key: String = "" + var text: String = "" + var pinType: String = "" +} diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SubscriptionPlan.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SubscriptionPlan.kt index 7948fcf7b..80bae9fa2 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SubscriptionPlan.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/models/user/SubscriptionPlan.kt @@ -42,7 +42,7 @@ open class SubscriptionPlan : RealmObject(), BaseObject { val totalNumberOfGems: Int get() { return if (isActive) { - 25 + (consecutive?.gemCapExtra ?: 0) + 24 + (consecutive?.gemCapExtra ?: 0) } else { 0 } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GemPurchaseActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GemPurchaseActivity.kt index a661e7ce2..10d258c06 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GemPurchaseActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/GemPurchaseActivity.kt @@ -7,9 +7,11 @@ import androidx.appcompat.widget.Toolbar import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment import com.habitrpg.android.habitica.R +import com.habitrpg.android.habitica.extensions.updateStatusBarColor import com.habitrpg.android.habitica.ui.fragments.purchases.GemsPurchaseFragment import com.habitrpg.android.habitica.ui.fragments.purchases.SubscriptionFragment import com.habitrpg.android.habitica.ui.helpers.ToolbarColorHelper +import com.habitrpg.common.habitica.extensions.getThemeColor import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint @@ -25,7 +27,11 @@ class GemPurchaseActivity : PurchaseActivity() { showSubscription = !(intent.extras?.containsKey("openSubscription") == true && intent.extras?.getBoolean("openSubscription") == false) val toolbar = findViewById(R.id.toolbar) - setupToolbar(toolbar, Color.WHITE, ContextCompat.getColor(this, R.color.brand_300)) + if (showSubscription) { + setupToolbar(toolbar, Color.WHITE, ContextCompat.getColor(this, R.color.brand_300)) + } else { + setupToolbar(toolbar) + } supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayShowHomeEnabled(true) @@ -39,10 +45,10 @@ class GemPurchaseActivity : PurchaseActivity() { } } - override fun onStart() { - super.onStart() + override fun onResume() { + super.onResume() if (showSubscription) { - toolbar?.let { ToolbarColorHelper.colorizeToolbar(it, this,) } + window.updateStatusBarColor(ContextCompat.getColor(this, R.color.brand_300), false) } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/purchases/SubscriptionBottomSheetFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/purchases/SubscriptionBottomSheetFragment.kt index 87a53c0a8..544f537bd 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/purchases/SubscriptionBottomSheetFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/purchases/SubscriptionBottomSheetFragment.kt @@ -79,6 +79,12 @@ open class SubscriptionBottomSheetFragment : BottomSheetDialogFragment() { user?.let { setUser(it) } } } + + binding.content.subscriptionDetails.visibility = View.GONE + binding.content.subscribeBenefitsFooter.visibility = View.GONE + binding.content.giftSegmentSubscribed.root.visibility = View.GONE + binding.content.giftSegmentUnsubscribed.root.visibility = View.VISIBLE + binding.content.subscriptionDisclaimerView.visibility = View.VISIBLE } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/purchases/SubscriptionFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/purchases/SubscriptionFragment.kt index ebdcc568f..232a112a6 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/purchases/SubscriptionFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/purchases/SubscriptionFragment.kt @@ -172,10 +172,12 @@ class SubscriptionFragment : BaseFragment() { val subscriptions = purchaseHandler.getAllSubscriptionProducts() skus = subscriptions withContext(Dispatchers.Main) { + binding?.content?.loadingIndicator?.visibility = View.GONE if (subscriptions.isEmpty()) { - binding?.content?.loadingIndicator?.visibility = View.GONE - binding?.content?.noBillingSubscriptions?.visibility = View.VISIBLE - binding?.content?.visitHabiticaWebsiteButton?.visibility = View.VISIBLE + if (user?.isSubscribed != true) { + binding?.content?.noBillingSubscriptions?.visibility = View.VISIBLE + binding?.content?.visitHabiticaWebsiteButton?.visibility = View.VISIBLE + } return@withContext } binding?.content?.noBillingSubscriptions?.visibility = View.GONE @@ -187,7 +189,7 @@ class SubscriptionFragment : BaseFragment() { ?: "", ) } - subscriptions.minByOrNull { + subscriptions.maxByOrNull { it.subscriptionOfferDetails?.firstOrNull()?.pricingPhases?.pricingPhaseList?.firstOrNull()?.priceAmountMicros ?: 0 }?.let { selectSubscription(it) } @@ -273,6 +275,7 @@ class SubscriptionFragment : BaseFragment() { binding?.content?.giftSegmentUnsubscribed?.root?.visibility = View.GONE binding?.content?.giftSegmentSubscribed?.root?.visibility = View.VISIBLE binding?.content?.subscribeBenefitsTitle?.visibility = View.GONE + binding?.content?.subscriptionDisclaimerView?.visibility = View.GONE } else { binding?.content?.headerImageView?.setImageResource(R.drawable.subscribe_header_dark) if (!hasLoadedSubscriptionOptions) { @@ -280,9 +283,11 @@ class SubscriptionFragment : BaseFragment() { } binding?.content?.subscriptionDetails?.visibility = View.GONE binding?.content?.subscribeBenefitsTitle?.setText(R.string.subscribe_prompt) + binding?.content?.subscribeBenefitsTitle?.visibility = View.VISIBLE binding?.content?.subscribeBenefitsFooter?.visibility = View.GONE binding?.content?.giftSegmentSubscribed?.root?.visibility = View.GONE binding?.content?.giftSegmentUnsubscribed?.root?.visibility = View.VISIBLE + binding?.content?.subscriptionDisclaimerView?.visibility = View.VISIBLE binding?.content?.subscription12month?.showHourglassPromo(user?.purchased?.plan?.isEligableForHourglassPromo == true) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriberBenefitView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriberBenefitView.kt index 474a691b5..bedc6ace0 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriberBenefitView.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriberBenefitView.kt @@ -17,6 +17,9 @@ import dagger.hilt.android.EntryPointAccessors import dagger.hilt.components.SingletonComponent import kotlinx.coroutines.MainScope import kotlinx.coroutines.flow.firstOrNull +import java.text.SimpleDateFormat +import java.util.Date +import java.util.Locale import javax.inject.Inject class SubscriberBenefitView @@ -27,6 +30,8 @@ class SubscriberBenefitView ) : LinearLayout(context, attrs) { private val binding: SubscriptionBenefitsBinding = SubscriptionBenefitsBinding.inflate(context.layoutInflater, this) + val monthFormatter = SimpleDateFormat("MMMM", Locale.getDefault()) + @Inject lateinit var configManager: AppConfigManager @@ -49,7 +54,9 @@ class SubscriberBenefitView inventoryRepository = hiltEntryPoint.inventoryRepository() MainScope().launchCatching { - val item = inventoryRepository.getLatestMysteryItem().firstOrNull() + val pair = inventoryRepository.getLatestMysteryItemAndSet().firstOrNull() + val item = pair?.first + val set = pair?.second binding.subBenefitsMysteryItemIcon.loadImage( "shop_set_mystery_${ item?.key?.split( @@ -58,8 +65,10 @@ class SubscriberBenefitView }", ) binding.subBenefitsMysteryItemText.text = - context.getString(R.string.subscribe_listitem3_description_new, item?.text) + context.getString(R.string.subscribe_listitem3_description_alt, monthFormatter.format(Date()), set?.text ?: context.getString(R.string.set)) } + binding.subBenefitsMysteryItemText.text = + context.getString(R.string.subscribe_listitem3_description_alt, monthFormatter.format(Date()), context.getString(R.string.set)) binding.benefitArmoireWrapper.isVisible = configManager.enableArmoireSubs() binding.benefitFaintWrapper.isVisible = configManager.enableFaintSubs() diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriptionDetailsView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriptionDetailsView.kt index f57fc93e3..ec46b41d1 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriptionDetailsView.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/subscriptions/SubscriptionDetailsView.kt @@ -39,6 +39,7 @@ class SubscriptionDetailsView : LinearLayout { private fun setupView() { binding = SubscriptionDetailsBinding.inflate(context.layoutInflater, this, true) binding.changeSubscriptionButton.setOnClickListener { changeSubscriptionButtonTapped() } + binding.heartIcon.setImageBitmap(HabiticaIconsHelper.imageOfHeartLarge()) } fun setPlan(plan: SubscriptionPlan) { @@ -147,9 +148,9 @@ class SubscriptionDetailsView : LinearLayout { if (plan.isActive && (terminatedLocalDate == null || nextHourglassDate.isBefore(terminatedLocalDate))) { val format = if (now.year != nextHourglassDate.year) { - "dd MMM yyyy" + "MMM yyyy" } else { - "dd MMMM" + "MMMM" } val nextHourglassMonth = nextHourglassDate.format(DateTimeFormatter.ofPattern(format)) nextHourglassMonth?.let { binding.nextHourglassTextview.text = it }