From 1838595ac0d05850dfeaf1c090551f23ccb90a9a Mon Sep 17 00:00:00 2001 From: Cesar de la Vega Date: Fri, 6 Oct 2023 15:17:59 +0200 Subject: [PATCH 1/7] add support for multiple offers --- .../composables/IntroEligibilityStateView.kt | 40 ++++++++++++++----- .../composables/PurchaseButton.kt | 1 + .../extensions/PackageExtensions.kt | 12 ++++-- .../ui/revenuecatui/templates/Template1.kt | 1 + .../ui/revenuecatui/templates/Template2.kt | 1 + .../ui/revenuecatui/templates/Template3.kt | 1 + .../extensions/PackageExtensionsTest.kt | 32 +++++++++++---- 7 files changed, 66 insertions(+), 22 deletions(-) diff --git a/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/composables/IntroEligibilityStateView.kt b/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/composables/IntroEligibilityStateView.kt index b1a10cd86d..149fe355ae 100644 --- a/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/composables/IntroEligibilityStateView.kt +++ b/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/composables/IntroEligibilityStateView.kt @@ -16,19 +16,21 @@ import androidx.compose.ui.tooling.preview.Preview internal fun IntroEligibilityStateView( textWithNoIntroOffer: String?, textWithIntroOffer: String?, + textWithMultipleIntroOffers: String?, eligibility: IntroOfferEligibility, color: Color = Color.Unspecified, style: TextStyle = TextStyle.Default, fontWeight: FontWeight? = null, textAlign: TextAlign? = null, ) { - val text: String = if (textWithIntroOffer != null && eligibility == IntroOfferEligibility.ELIGIBLE) { - textWithIntroOffer - } else { - // Display text with intro offer as a backup to ensure layout does not change - // when switching states. - textWithNoIntroOffer ?: textWithIntroOffer ?: "" - } + val text: String = when (eligibility) { + IntroOfferEligibility.SINGLE_OFFER_ELIGIBLE -> textWithIntroOffer + IntroOfferEligibility.MULTIPLE_OFFER_ELIGIBLE -> textWithMultipleIntroOffers + else -> textWithNoIntroOffer + } // Display text with intro offer as a backup to ensure layout does not change when switching states. + ?: textWithNoIntroOffer + ?: textWithIntroOffer + ?: "" Text( text, @@ -41,7 +43,8 @@ internal fun IntroEligibilityStateView( internal enum class IntroOfferEligibility { INELIGIBLE, - ELIGIBLE, + SINGLE_OFFER_ELIGIBLE, + MULTIPLE_OFFER_ELIGIBLE, } @Preview(showBackground = true) @@ -50,7 +53,8 @@ private fun IntroEligibilityPreviewNoOffer() { IntroEligibilityStateView( textWithNoIntroOffer = "$3.99/mo", textWithIntroOffer = null, - eligibility = IntroOfferEligibility.ELIGIBLE, + textWithMultipleIntroOffers = null, + eligibility = IntroOfferEligibility.SINGLE_OFFER_ELIGIBLE, color = Color.Black, ) } @@ -61,6 +65,7 @@ private fun IntroEligibilityPreviewBothTextsIneligible() { IntroEligibilityStateView( textWithNoIntroOffer = "$3.99/mo", textWithIntroOffer = "7 day trial, then $3.99/mo", + textWithMultipleIntroOffers = "7 days for free, then $1.99 for your first month, and just $4.99/mo thereafter.", eligibility = IntroOfferEligibility.INELIGIBLE, color = Color.Black, ) @@ -68,11 +73,24 @@ private fun IntroEligibilityPreviewBothTextsIneligible() { @Preview(showBackground = true) @Composable -private fun IntroEligibilityPreviewBothTextsEligible() { +private fun IntroEligibilityPreviewBothTextsEligibleSingleOffer() { IntroEligibilityStateView( textWithNoIntroOffer = "$3.99/mo", textWithIntroOffer = "7 day trial, then $3.99/mo", - eligibility = IntroOfferEligibility.ELIGIBLE, + textWithMultipleIntroOffers = "7 days for free, then $1.99 for your first month, and just $3.99/mo thereafter.", + eligibility = IntroOfferEligibility.SINGLE_OFFER_ELIGIBLE, + color = Color.Black, + ) +} + +@Preview(showBackground = true) +@Composable +private fun IntroEligibilityPreviewBothTextsEligibleMultipleOffers() { + IntroEligibilityStateView( + textWithNoIntroOffer = "$3.99/mo", + textWithIntroOffer = "7 day trial, then $3.99/mo", + textWithMultipleIntroOffers = "7 days for free, then $1.99 for your first month, and just $4.99/mo thereafter.", + eligibility = IntroOfferEligibility.MULTIPLE_OFFER_ELIGIBLE, color = Color.Black, ) } diff --git a/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/composables/PurchaseButton.kt b/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/composables/PurchaseButton.kt index 60effd3cd4..a854b10653 100644 --- a/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/composables/PurchaseButton.kt +++ b/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/composables/PurchaseButton.kt @@ -42,6 +42,7 @@ internal fun PurchaseButton( IntroEligibilityStateView( textWithNoIntroOffer = state.selectedLocalization.callToAction, textWithIntroOffer = state.selectedLocalization.callToActionWithIntroOffer, + textWithMultipleIntroOffers = state.selectedLocalization.offerDetailsWithMultipleIntroOffers, eligibility = state.selectedPackage.introEligibility, ) } diff --git a/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensions.kt b/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensions.kt index bddc6566ee..3fad749c41 100644 --- a/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensions.kt +++ b/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensions.kt @@ -13,10 +13,14 @@ val Package.isMonthly: Boolean get() = product.period?.let { it.unit == Period.Unit.MONTH && it.value == 1 } ?: false internal val Package.introEligibility: IntroOfferEligibility - get() = if (product.defaultOption?.isBasePlan == true) { - IntroOfferEligibility.INELIGIBLE - } else { - IntroOfferEligibility.ELIGIBLE + get() = with(product.defaultOption) { + if (this?.isBasePlan == true) { + IntroOfferEligibility.INELIGIBLE + } else if (this?.pricingPhases?.size == 2) { + IntroOfferEligibility.SINGLE_OFFER_ELIGIBLE + } else { + IntroOfferEligibility.MULTIPLE_OFFER_ELIGIBLE + } } internal val TemplateConfiguration.PackageInfo.introEligibility: IntroOfferEligibility diff --git a/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/templates/Template1.kt b/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/templates/Template1.kt index cdbc35e2e6..b27f8eff61 100644 --- a/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/templates/Template1.kt +++ b/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/templates/Template1.kt @@ -117,6 +117,7 @@ private fun ColumnScope.Template1MainContent(state: PaywallViewState.Loaded) { IntroEligibilityStateView( textWithNoIntroOffer = localizedConfig.offerDetails, textWithIntroOffer = localizedConfig.offerDetailsWithIntroOffer, + textWithMultipleIntroOffers = localizedConfig.offerDetailsWithMultipleIntroOffers, eligibility = state.selectedPackage.introEligibility, color = colors.text1, style = MaterialTheme.typography.bodyLarge, diff --git a/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/templates/Template2.kt b/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/templates/Template2.kt index 82f86b0fd8..f6480e18dc 100644 --- a/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/templates/Template2.kt +++ b/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/templates/Template2.kt @@ -164,6 +164,7 @@ private fun SelectPackageButton( IntroEligibilityStateView( textWithNoIntroOffer = packageInfo.localization.offerDetails, textWithIntroOffer = packageInfo.localization.offerDetailsWithIntroOffer, + textWithMultipleIntroOffers = packageInfo.localization.offerDetailsWithMultipleIntroOffers, eligibility = packageInfo.introEligibility, ) } diff --git a/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/templates/Template3.kt b/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/templates/Template3.kt index b6897d1f74..534890c590 100644 --- a/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/templates/Template3.kt +++ b/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/templates/Template3.kt @@ -76,6 +76,7 @@ internal fun Template3( IntroEligibilityStateView( textWithNoIntroOffer = state.selectedLocalization.offerDetails, textWithIntroOffer = state.selectedLocalization.offerDetailsWithIntroOffer, + textWithMultipleIntroOffers = state.selectedLocalization.offerDetailsWithMultipleIntroOffers, eligibility = state.selectedPackage.introEligibility, color = state.templateConfiguration.getCurrentColors().text1, textAlign = TextAlign.Center, diff --git a/ui/revenuecatui/src/test/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensionsTest.kt b/ui/revenuecatui/src/test/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensionsTest.kt index 359d2d41c7..40dc5456aa 100644 --- a/ui/revenuecatui/src/test/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensionsTest.kt +++ b/ui/revenuecatui/src/test/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensionsTest.kt @@ -2,6 +2,8 @@ package com.revenuecat.purchases.ui.revenuecatui.extensions import androidx.test.ext.junit.runners.AndroidJUnit4 import com.revenuecat.purchases.Package +import com.revenuecat.purchases.models.PricingPhase +import com.revenuecat.purchases.models.PurchasingData import com.revenuecat.purchases.models.StoreProduct import com.revenuecat.purchases.models.SubscriptionOption import com.revenuecat.purchases.ui.revenuecatui.composables.IntroOfferEligibility @@ -15,24 +17,40 @@ import org.junit.runner.RunWith class PackageExtensionsTest { @Test - fun `introEligibility calculation is true if defaultOption is not base plan`() { - val rcPackage = createPackage(basePlan = false) + fun `introEligibility calculation is SINGLE_OFFER_ELIGIBLE if defaultOption only has a free trial`() { + val rcPackage = createPackage(numberOfOffers = 1) - assertThat(rcPackage.introEligibility).isEqualTo(IntroOfferEligibility.ELIGIBLE) + assertThat(rcPackage.introEligibility).isEqualTo(IntroOfferEligibility.SINGLE_OFFER_ELIGIBLE) + } + + @Test + fun `introEligibility calculation is MULTIPLE_OFFER_ELIGIBLE if defaultOption has trial and discounted price`() { + val rcPackage = createPackage(numberOfOffers = 2) + + assertThat(rcPackage.introEligibility).isEqualTo(IntroOfferEligibility.MULTIPLE_OFFER_ELIGIBLE) } @Test fun `introEligibility calculation is false if defaultOption is base plan`() { - val rcPackage = createPackage(basePlan = true) + val rcPackage = createPackage(numberOfOffers = 0) assertThat(rcPackage.introEligibility).isEqualTo(IntroOfferEligibility.INELIGIBLE) } - private fun createPackage(basePlan: Boolean): Package { + private fun createPackage(numberOfOffers: Int): Package { return mockk().apply { every { product } returns mockk().apply { - every { defaultOption } returns mockk().apply { - every { isBasePlan } returns basePlan + every { defaultOption } returns object : SubscriptionOption { + override val id: String + get() = "id" + override val pricingPhases: List + get() = List(numberOfOffers + 1) { mockk() } // Base plans have one pricing phase + override val tags: List + get() = listOf("tag_1") + override val presentedOfferingIdentifier: String? + get() = "offering_id" + override val purchasingData: PurchasingData + get() = mockk() } } } From a57140ff7a4d4c8d2fc7c96f081778b882707ad1 Mon Sep 17 00:00:00 2001 From: Cesar de la Vega Date: Fri, 6 Oct 2023 15:21:32 +0200 Subject: [PATCH 2/7] fix test name --- .../ui/revenuecatui/extensions/PackageExtensionsTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/revenuecatui/src/test/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensionsTest.kt b/ui/revenuecatui/src/test/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensionsTest.kt index 40dc5456aa..f4e9fe19e8 100644 --- a/ui/revenuecatui/src/test/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensionsTest.kt +++ b/ui/revenuecatui/src/test/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensionsTest.kt @@ -31,7 +31,7 @@ class PackageExtensionsTest { } @Test - fun `introEligibility calculation is false if defaultOption is base plan`() { + fun `introEligibility calculation is INELIGIBLE if defaultOption is base plan`() { val rcPackage = createPackage(numberOfOffers = 0) assertThat(rcPackage.introEligibility).isEqualTo(IntroOfferEligibility.INELIGIBLE) From a17ae4e4a2b49a33ab42c06e822e200166243243 Mon Sep 17 00:00:00 2001 From: Cesar de la Vega Date: Fri, 6 Oct 2023 15:24:55 +0200 Subject: [PATCH 3/7] refactor introEligibility calculator --- .../ui/revenuecatui/extensions/PackageExtensions.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensions.kt b/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensions.kt index 3fad749c41..8d1cdc09ab 100644 --- a/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensions.kt +++ b/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensions.kt @@ -13,15 +13,15 @@ val Package.isMonthly: Boolean get() = product.period?.let { it.unit == Period.Unit.MONTH && it.value == 1 } ?: false internal val Package.introEligibility: IntroOfferEligibility - get() = with(product.defaultOption) { - if (this?.isBasePlan == true) { + get() = product.defaultOption?.let { defaultOption -> + if (defaultOption.isBasePlan) { IntroOfferEligibility.INELIGIBLE - } else if (this?.pricingPhases?.size == 2) { + } else if (defaultOption.pricingPhases.size == 2) { // Base plan + one offer IntroOfferEligibility.SINGLE_OFFER_ELIGIBLE } else { IntroOfferEligibility.MULTIPLE_OFFER_ELIGIBLE } - } + } ?: IntroOfferEligibility.INELIGIBLE internal val TemplateConfiguration.PackageInfo.introEligibility: IntroOfferEligibility get() = this.rcPackage.introEligibility From a82f0228c5ce4baab75e36eb983176ba3a88db22 Mon Sep 17 00:00:00 2001 From: Cesar de la Vega Date: Fri, 6 Oct 2023 15:36:53 +0200 Subject: [PATCH 4/7] refactor to use freePhase and introPhase --- .../ui/revenuecatui/extensions/PackageExtensions.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensions.kt b/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensions.kt index 8d1cdc09ab..b2e0ccb679 100644 --- a/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensions.kt +++ b/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensions.kt @@ -14,12 +14,12 @@ val Package.isMonthly: Boolean internal val Package.introEligibility: IntroOfferEligibility get() = product.defaultOption?.let { defaultOption -> - if (defaultOption.isBasePlan) { - IntroOfferEligibility.INELIGIBLE - } else if (defaultOption.pricingPhases.size == 2) { // Base plan + one offer - IntroOfferEligibility.SINGLE_OFFER_ELIGIBLE - } else { - IntroOfferEligibility.MULTIPLE_OFFER_ELIGIBLE + when { + defaultOption.isBasePlan -> IntroOfferEligibility.INELIGIBLE + (defaultOption.freePhase != null && defaultOption.introPhase == null) || + (defaultOption.freePhase == null && defaultOption.introPhase != null) -> + IntroOfferEligibility.SINGLE_OFFER_ELIGIBLE + else -> IntroOfferEligibility.MULTIPLE_OFFER_ELIGIBLE } } ?: IntroOfferEligibility.INELIGIBLE From 7470e5dad1cfaa161ec1fb71a7f3fedb12a64ec7 Mon Sep 17 00:00:00 2001 From: Cesar de la Vega Date: Mon, 9 Oct 2023 12:19:52 +0200 Subject: [PATCH 5/7] rename to MULTIPLE_OFFERS_ELIGIBLE --- .../revenuecatui/composables/IntroEligibilityStateView.kt | 6 +++--- .../ui/revenuecatui/extensions/PackageExtensions.kt | 2 +- .../ui/revenuecatui/extensions/PackageExtensionsTest.kt | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/composables/IntroEligibilityStateView.kt b/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/composables/IntroEligibilityStateView.kt index 149fe355ae..167ac5392c 100644 --- a/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/composables/IntroEligibilityStateView.kt +++ b/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/composables/IntroEligibilityStateView.kt @@ -25,7 +25,7 @@ internal fun IntroEligibilityStateView( ) { val text: String = when (eligibility) { IntroOfferEligibility.SINGLE_OFFER_ELIGIBLE -> textWithIntroOffer - IntroOfferEligibility.MULTIPLE_OFFER_ELIGIBLE -> textWithMultipleIntroOffers + IntroOfferEligibility.MULTIPLE_OFFERS_ELIGIBLE -> textWithMultipleIntroOffers else -> textWithNoIntroOffer } // Display text with intro offer as a backup to ensure layout does not change when switching states. ?: textWithNoIntroOffer @@ -44,7 +44,7 @@ internal fun IntroEligibilityStateView( internal enum class IntroOfferEligibility { INELIGIBLE, SINGLE_OFFER_ELIGIBLE, - MULTIPLE_OFFER_ELIGIBLE, + MULTIPLE_OFFERS_ELIGIBLE, } @Preview(showBackground = true) @@ -90,7 +90,7 @@ private fun IntroEligibilityPreviewBothTextsEligibleMultipleOffers() { textWithNoIntroOffer = "$3.99/mo", textWithIntroOffer = "7 day trial, then $3.99/mo", textWithMultipleIntroOffers = "7 days for free, then $1.99 for your first month, and just $4.99/mo thereafter.", - eligibility = IntroOfferEligibility.MULTIPLE_OFFER_ELIGIBLE, + eligibility = IntroOfferEligibility.MULTIPLE_OFFERS_ELIGIBLE, color = Color.Black, ) } diff --git a/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensions.kt b/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensions.kt index b2e0ccb679..6f19f8beba 100644 --- a/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensions.kt +++ b/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensions.kt @@ -19,7 +19,7 @@ internal val Package.introEligibility: IntroOfferEligibility (defaultOption.freePhase != null && defaultOption.introPhase == null) || (defaultOption.freePhase == null && defaultOption.introPhase != null) -> IntroOfferEligibility.SINGLE_OFFER_ELIGIBLE - else -> IntroOfferEligibility.MULTIPLE_OFFER_ELIGIBLE + else -> IntroOfferEligibility.MULTIPLE_OFFERS_ELIGIBLE } } ?: IntroOfferEligibility.INELIGIBLE diff --git a/ui/revenuecatui/src/test/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensionsTest.kt b/ui/revenuecatui/src/test/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensionsTest.kt index f4e9fe19e8..e3bf131045 100644 --- a/ui/revenuecatui/src/test/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensionsTest.kt +++ b/ui/revenuecatui/src/test/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensionsTest.kt @@ -24,10 +24,10 @@ class PackageExtensionsTest { } @Test - fun `introEligibility calculation is MULTIPLE_OFFER_ELIGIBLE if defaultOption has trial and discounted price`() { + fun `introEligibility calculation is MULTIPLE_OFFERS_ELIGIBLE if defaultOption has trial and discounted price`() { val rcPackage = createPackage(numberOfOffers = 2) - assertThat(rcPackage.introEligibility).isEqualTo(IntroOfferEligibility.MULTIPLE_OFFER_ELIGIBLE) + assertThat(rcPackage.introEligibility).isEqualTo(IntroOfferEligibility.MULTIPLE_OFFERS_ELIGIBLE) } @Test From e8b29e0c39c59333783ad44f74634de0f652d043 Mon Sep 17 00:00:00 2001 From: Cesar de la Vega Date: Mon, 9 Oct 2023 12:28:03 +0200 Subject: [PATCH 6/7] callToActionWithMultipleIntroOffers --- .../purchases/ui/revenuecatui/composables/PurchaseButton.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/composables/PurchaseButton.kt b/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/composables/PurchaseButton.kt index a854b10653..d26abeff36 100644 --- a/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/composables/PurchaseButton.kt +++ b/ui/revenuecatui/src/main/kotlin/com/revenuecat/purchases/ui/revenuecatui/composables/PurchaseButton.kt @@ -42,7 +42,7 @@ internal fun PurchaseButton( IntroEligibilityStateView( textWithNoIntroOffer = state.selectedLocalization.callToAction, textWithIntroOffer = state.selectedLocalization.callToActionWithIntroOffer, - textWithMultipleIntroOffers = state.selectedLocalization.offerDetailsWithMultipleIntroOffers, + textWithMultipleIntroOffers = state.selectedLocalization.callToActionWithMultipleIntroOffers, eligibility = state.selectedPackage.introEligibility, ) } From eda3c35ffd172ca594bf60986ae39867df80ae9b Mon Sep 17 00:00:00 2001 From: Cesar de la Vega Date: Mon, 9 Oct 2023 12:48:07 +0200 Subject: [PATCH 7/7] fix tests --- .../extensions/PackageExtensionsTest.kt | 65 +++++++++++++++++-- 1 file changed, 59 insertions(+), 6 deletions(-) diff --git a/ui/revenuecatui/src/test/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensionsTest.kt b/ui/revenuecatui/src/test/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensionsTest.kt index e3bf131045..0ea1b8e4aa 100644 --- a/ui/revenuecatui/src/test/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensionsTest.kt +++ b/ui/revenuecatui/src/test/kotlin/com/revenuecat/purchases/ui/revenuecatui/extensions/PackageExtensionsTest.kt @@ -2,8 +2,11 @@ package com.revenuecat.purchases.ui.revenuecatui.extensions import androidx.test.ext.junit.runners.AndroidJUnit4 import com.revenuecat.purchases.Package +import com.revenuecat.purchases.models.Period +import com.revenuecat.purchases.models.Price import com.revenuecat.purchases.models.PricingPhase import com.revenuecat.purchases.models.PurchasingData +import com.revenuecat.purchases.models.RecurrenceMode import com.revenuecat.purchases.models.StoreProduct import com.revenuecat.purchases.models.SubscriptionOption import com.revenuecat.purchases.ui.revenuecatui.composables.IntroOfferEligibility @@ -18,33 +21,34 @@ class PackageExtensionsTest { @Test fun `introEligibility calculation is SINGLE_OFFER_ELIGIBLE if defaultOption only has a free trial`() { - val rcPackage = createPackage(numberOfOffers = 1) + val rcPackage = createPackage(freeTrial = true) assertThat(rcPackage.introEligibility).isEqualTo(IntroOfferEligibility.SINGLE_OFFER_ELIGIBLE) } @Test fun `introEligibility calculation is MULTIPLE_OFFERS_ELIGIBLE if defaultOption has trial and discounted price`() { - val rcPackage = createPackage(numberOfOffers = 2) + val rcPackage = createPackage(freeTrial = true, introOffer = true) assertThat(rcPackage.introEligibility).isEqualTo(IntroOfferEligibility.MULTIPLE_OFFERS_ELIGIBLE) } @Test fun `introEligibility calculation is INELIGIBLE if defaultOption is base plan`() { - val rcPackage = createPackage(numberOfOffers = 0) + val rcPackage = createPackage() assertThat(rcPackage.introEligibility).isEqualTo(IntroOfferEligibility.INELIGIBLE) } - private fun createPackage(numberOfOffers: Int): Package { + private fun createPackage(freeTrial: Boolean = false, introOffer: Boolean = false): Package { return mockk().apply { every { product } returns mockk().apply { every { defaultOption } returns object : SubscriptionOption { override val id: String get() = "id" - override val pricingPhases: List - get() = List(numberOfOffers + 1) { mockk() } // Base plans have one pricing phase + + override val pricingPhases: List = getPricingPhases(freeTrial, introOffer) + override val tags: List get() = listOf("tag_1") override val presentedOfferingIdentifier: String? @@ -56,3 +60,52 @@ class PackageExtensionsTest { } } } + +private fun getPricingPhases(freeTrial: Boolean, introOffer: Boolean): List { + val defaultPricing = PricingPhase( + billingPeriod = Period.create("P1M"), + recurrenceMode = RecurrenceMode.INFINITE_RECURRING, + billingCycleCount = null, + price = Price( + formatted = "$2.99", + amountMicros = 2990000L, + currencyCode = "USD" + ) + ) + + val freeTrialPricing = if (freeTrial) { + listOf( + PricingPhase( + billingPeriod = Period.create("P1M"), + recurrenceMode = RecurrenceMode.NON_RECURRING, + billingCycleCount = null, + price = Price( + formatted = "FREE", + amountMicros = 0, + currencyCode = "USD" + ) + ) + ) + } else { + emptyList() + } + + val introOfferPricing = if (introOffer) { + listOf( + PricingPhase( + billingPeriod = Period.create("P1M"), + recurrenceMode = RecurrenceMode.FINITE_RECURRING, + billingCycleCount = 2, + price = Price( + formatted = "$1.99", + amountMicros = 1990000L, + currencyCode = "USD" + ) + ) + ) + } else { + emptyList() + } + + return listOf(defaultPricing) + freeTrialPricing + introOfferPricing +}