diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/billing/manager/PremiumStateManager.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/billing/manager/PremiumStateManager.kt index ab8f2441e4..e74e8bb073 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/billing/manager/PremiumStateManager.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/billing/manager/PremiumStateManager.kt @@ -3,10 +3,7 @@ package com.x8bit.bitwarden.data.billing.manager import kotlinx.coroutines.flow.StateFlow /** - * Manages the consolidated eligibility state for the Premium upgrade banner. - * - * Combines multiple upstream signals (Premium status, billing support, feature flag, - * banner dismissal, account age, and vault item count) into a single observable flow. + * Manages Premium upgrade state for the active user. */ interface PremiumStateManager { @@ -16,6 +13,11 @@ interface PremiumStateManager { */ val isPremiumUpgradeBannerEligibleFlow: StateFlow + /** + * Returns `true` when the in-app upgrade flow is available, or `false` otherwise. + */ + fun isInAppUpgradeAvailable(): Boolean + /** * Marks the Premium upgrade banner as dismissed for the current user. */ diff --git a/app/src/main/kotlin/com/x8bit/bitwarden/data/billing/manager/PremiumStateManagerImpl.kt b/app/src/main/kotlin/com/x8bit/bitwarden/data/billing/manager/PremiumStateManagerImpl.kt index 8ac90250c0..14254c0792 100644 --- a/app/src/main/kotlin/com/x8bit/bitwarden/data/billing/manager/PremiumStateManagerImpl.kt +++ b/app/src/main/kotlin/com/x8bit/bitwarden/data/billing/manager/PremiumStateManagerImpl.kt @@ -27,17 +27,15 @@ import java.time.Instant /** * Default implementation of [PremiumStateManager]. - * - * Combines five upstream flows into a single eligibility signal using [combine]. */ @Suppress("LongParameterList") class PremiumStateManagerImpl( private val authDiskSource: AuthDiskSource, authRepository: AuthRepository, - billingRepository: BillingRepository, + private val billingRepository: BillingRepository, private val settingsDiskSource: SettingsDiskSource, vaultRepository: VaultRepository, - featureFlagManager: FeatureFlagManager, + private val featureFlagManager: FeatureFlagManager, private val clock: Clock, dispatcherManager: DispatcherManager, ) : PremiumStateManager { @@ -90,6 +88,10 @@ class PremiumStateManagerImpl( initialValue = false, ) + override fun isInAppUpgradeAvailable(): Boolean = + billingRepository.isInAppBillingSupportedFlow.value && + featureFlagManager.getFeatureFlag(FlagKey.MobilePremiumUpgrade) + override fun dismissPremiumUpgradeBanner() { val activeUserId = authDiskSource.userState?.activeUserId ?: return settingsDiskSource.storePremiumUpgradeBannerDismissed( diff --git a/app/src/test/kotlin/com/x8bit/bitwarden/data/billing/manager/PremiumStateManagerImplTest.kt b/app/src/test/kotlin/com/x8bit/bitwarden/data/billing/manager/PremiumStateManagerImplTest.kt index 3d0df96381..e7f85e4c8f 100644 --- a/app/src/test/kotlin/com/x8bit/bitwarden/data/billing/manager/PremiumStateManagerImplTest.kt +++ b/app/src/test/kotlin/com/x8bit/bitwarden/data/billing/manager/PremiumStateManagerImplTest.kt @@ -66,6 +66,9 @@ class PremiumStateManagerImplTest { every { getFeatureFlagFlow(FlagKey.MobilePremiumUpgrade) } returns mutableMobilePremiumUpgradeFlagFlow + every { + getFeatureFlag(FlagKey.MobilePremiumUpgrade) + } answers { mutableMobilePremiumUpgradeFlagFlow.value } } private val dispatcherManager = FakeDispatcherManager() @@ -330,6 +333,34 @@ class PremiumStateManagerImplTest { } } + @Test + fun `isInAppUpgradeAvailable should return true when billing supported and flag enabled`() { + val manager = createManager() + assertTrue(manager.isInAppUpgradeAvailable()) + } + + @Test + fun `isInAppUpgradeAvailable should return false when billing not supported`() { + mutableIsInAppBillingSupportedFlow.value = false + val manager = createManager() + assertFalse(manager.isInAppUpgradeAvailable()) + } + + @Test + fun `isInAppUpgradeAvailable should return false when feature flag disabled`() { + mutableMobilePremiumUpgradeFlagFlow.value = false + val manager = createManager() + assertFalse(manager.isInAppUpgradeAvailable()) + } + + @Test + fun `isInAppUpgradeAvailable should return false when both conditions are false`() { + mutableIsInAppBillingSupportedFlow.value = false + mutableMobilePremiumUpgradeFlagFlow.value = false + val manager = createManager() + assertFalse(manager.isInAppUpgradeAvailable()) + } + @Test fun `dismissPremiumUpgradeBanner should store dismissed state for active user`() { val manager = createManager()