Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Paywalls: improve handling of lifetime/custom packages #1363

Merged
merged 3 commits into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,15 @@ internal fun LoadingPaywall(mode: PaywallMode) {
)

val state = offering.toPaywallState(
VariableDataProvider(
variableDataProvider = VariableDataProvider(
applicationContext,
isInPreviewMode(),
),
setOf(),
mode,
paywallData,
LoadingPaywallConstants.template,
activelySubscribedProductIdentifiers = setOf(),
nonSubscriptionProductIdentifiers = setOf(),
mode = mode,
validatedPaywallData = paywallData,
template = LoadingPaywallConstants.template,
)

when (state) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,11 +214,14 @@ internal class PaywallViewModelImpl(
Logger.w(PaywallValidationErrorStrings.DISPLAYING_DEFAULT)
}
return offering.toPaywallState(
variableDataProvider,
customerInfo.activeSubscriptions,
mode,
displayablePaywall,
template,
variableDataProvider = variableDataProvider,
activelySubscribedProductIdentifiers = customerInfo.activeSubscriptions,
nonSubscriptionProductIdentifiers = customerInfo.nonSubscriptionTransactions
.map { it.productIdentifier }
.toSet(),
mode = mode,
validatedPaywallData = displayablePaywall,
template = template,
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.revenuecat.purchases.ui.revenuecatui.data.processed

import com.revenuecat.purchases.Package
import com.revenuecat.purchases.PackageType
import com.revenuecat.purchases.paywalls.PaywallData
import com.revenuecat.purchases.ui.revenuecatui.errors.PackageConfigurationError
import com.revenuecat.purchases.ui.revenuecatui.helpers.Logger
Expand All @@ -12,6 +13,7 @@ internal object PackageConfigurationFactory {
variableDataProvider: VariableDataProvider,
availablePackages: List<Package>,
activelySubscribedProductIdentifiers: Set<String>,
nonSubscriptionProductIdentifiers: Set<String>,
packageIdsInConfig: List<String>,
default: String?,
localization: PaywallData.LocalizedConfiguration,
Expand All @@ -32,10 +34,25 @@ internal object PackageConfigurationFactory {
return Result.failure(PackageConfigurationError("No packages found for ids $packageIdsInConfig"))
}
val packageInfos = filteredRCPackages.map {
val currentlySubscribed = when (it.packageType) {
PackageType.ANNUAL,
PackageType.SIX_MONTH,
PackageType.THREE_MONTH,
PackageType.TWO_MONTH,
PackageType.MONTHLY,
PackageType.WEEKLY,
-> activelySubscribedProductIdentifiers.contains(it.product.id)

PackageType.LIFETIME, PackageType.CUSTOM,
-> nonSubscriptionProductIdentifiers.contains(it.product.id)

PackageType.UNKNOWN -> false
}

TemplateConfiguration.PackageInfo(
rcPackage = it,
localization = ProcessedLocalizedConfiguration.create(variableDataProvider, localization, it, locale),
currentlySubscribed = activelySubscribedProductIdentifiers.contains(it.product.id),
currentlySubscribed = currentlySubscribed,
discountRelativeToMostExpensivePerMonth = null, // TODO-PAYWALLS: Support discount UI
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ internal object TemplateConfigurationFactory {
paywallData: PaywallData,
availablePackages: List<Package>,
activelySubscribedProductIdentifiers: Set<String>,
nonSubscriptionProductIdentifiers: Set<String>,
template: PaywallTemplate,
): Result<TemplateConfiguration> {
val (locale, localizedConfiguration) = paywallData.localizedConfiguration
Expand All @@ -27,6 +28,7 @@ internal object TemplateConfigurationFactory {
variableDataProvider = variableDataProvider,
availablePackages = availablePackages,
activelySubscribedProductIdentifiers = activelySubscribedProductIdentifiers,
nonSubscriptionProductIdentifiers = nonSubscriptionProductIdentifiers,
packageIdsInConfig = paywallData.config.packageIds,
default = paywallData.config.defaultPackage,
localization = localizedConfiguration,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ internal object TestData {
Packages.weekly,
Packages.monthly,
Packages.annual,
Packages.lifetime,
),
metadata = mapOf(),
paywall = template2,
Expand Down Expand Up @@ -272,11 +273,12 @@ internal class MockViewModel(

private val _state = MutableStateFlow(
offering.toPaywallState(
VariableDataProvider(MockApplicationContext()),
setOf(),
mode,
offering.paywall!!,
PaywallTemplate.fromId(offering.paywall!!.templateName)!!,
variableDataProvider = VariableDataProvider(MockApplicationContext()),
activelySubscribedProductIdentifiers = setOf(),
nonSubscriptionProductIdentifiers = setOf(),
mode = mode,
validatedPaywallData = offering.paywall!!,
template = PaywallTemplate.fromId(offering.paywall!!.templateName)!!,
),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ internal val TestData.template2: PaywallData
packageIds = listOf(
PackageType.ANNUAL.identifier!!,
PackageType.MONTHLY.identifier!!,
PackageType.LIFETIME.identifier!!,
),
defaultPackage = PackageType.MONTHLY.identifier!!,
images = TestData.Constants.images,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,11 @@ private fun PaywallData.validate(): Result<PaywallTemplate> {
return Result.success(template)
}

@Suppress("ReturnCount", "TooGenericExceptionCaught")
@Suppress("ReturnCount", "TooGenericExceptionCaught", "LongParameterList")
internal fun Offering.toPaywallState(
variableDataProvider: VariableDataProvider,
activelySubscribedProductIdentifiers: Set<String>,
nonSubscriptionProductIdentifiers: Set<String>,
mode: PaywallMode,
validatedPaywallData: PaywallData,
template: PaywallTemplate,
Expand All @@ -81,6 +82,7 @@ internal fun Offering.toPaywallState(
paywallData = validatedPaywallData,
availablePackages = availablePackages,
activelySubscribedProductIdentifiers = activelySubscribedProductIdentifiers,
nonSubscriptionProductIdentifiers = nonSubscriptionProductIdentifiers,
template,
)
val templateConfiguration = createTemplateConfigurationResult.getOrElse {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.revenuecat.purchases.Offerings
import com.revenuecat.purchases.Package
import com.revenuecat.purchases.PurchaseResult
import com.revenuecat.purchases.models.StoreTransaction
import com.revenuecat.purchases.models.Transaction
import com.revenuecat.purchases.paywalls.PaywallData
import com.revenuecat.purchases.ui.revenuecatui.PaywallListener
import com.revenuecat.purchases.ui.revenuecatui.PaywallMode
Expand All @@ -35,6 +36,8 @@ import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.util.Date
import java.util.UUID

@RunWith(AndroidJUnit4::class)
class PaywallViewModelTest {
Expand Down Expand Up @@ -111,7 +114,10 @@ class PaywallViewModelTest {

@Test
fun `Should load default offering`() {
val model = create(activeSubscriptions = arrayOf(TestData.Packages.monthly.product.id))
val model = create(
activeSubscriptions = setOf(TestData.Packages.monthly.product.id),
nonSubscriptionTransactionProductIdentifiers = setOf(TestData.Packages.lifetime.product.id),
)

coVerify { purchases.awaitOfferings() }

Expand All @@ -128,6 +134,8 @@ class PaywallViewModelTest {
.isTrue
assertThat(state.templateConfiguration.packages.packageIsCurrentlySubscribed(TestData.Packages.annual))
.isFalse
assertThat(state.templateConfiguration.packages.packageIsCurrentlySubscribed(TestData.Packages.lifetime))
.isTrue
}

@Test
Expand Down Expand Up @@ -226,9 +234,11 @@ class PaywallViewModelTest {

private fun create(
offering: Offering? = null,
vararg activeSubscriptions: String,
activeSubscriptions: Set<String> = setOf(),
nonSubscriptionTransactionProductIdentifiers: Set<String> = setOf(),
): PaywallViewModelImpl {
mockActiveSubscriptions(*activeSubscriptions)
mockActiveSubscriptions(activeSubscriptions)
mockNonSubscriptionTransactions(nonSubscriptionTransactionProductIdentifiers)

return PaywallViewModelImpl(
MockApplicationContext(),
Expand All @@ -241,8 +251,21 @@ class PaywallViewModelTest {
)
}

private fun mockActiveSubscriptions(vararg subscriptions: String) {
every { customerInfo.activeSubscriptions } returns setOf(*subscriptions)
private fun mockActiveSubscriptions(subscriptions: Set<String>) {
every { customerInfo.activeSubscriptions } returns subscriptions
}

private fun mockNonSubscriptionTransactions(productIdentifiers: Set<String>) {
every { customerInfo.nonSubscriptionTransactions } returns productIdentifiers
.map {
Transaction(
UUID.randomUUID().toString(),
UUID.randomUUID().toString(),
it,
it,
Date()
)
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,22 @@ internal class TemplateConfigurationFactoryTest {
fun setUp() {
variableDataProvider = VariableDataProvider(MockApplicationContext())
val result = TemplateConfigurationFactory.create(
variableDataProvider,
paywallMode,
TestData.template2,
listOf(TestData.Packages.weekly, TestData.Packages.monthly, TestData.Packages.annual),
setOf(
TestData.Packages.monthly.product.id
variableDataProvider = variableDataProvider,
mode = paywallMode,
paywallData = TestData.template2,
availablePackages = listOf(
TestData.Packages.weekly,
TestData.Packages.monthly,
TestData.Packages.annual,
TestData.Packages.lifetime,
),
PaywallTemplate.TEMPLATE_2,
activelySubscribedProductIdentifiers = setOf(
TestData.Packages.monthly.product.id,
),
nonSubscriptionProductIdentifiers = setOf(
TestData.Packages.lifetime.product.id
),
template = PaywallTemplate.TEMPLATE_2,
)
template2Configuration = result.getOrNull()!!
}
Expand Down Expand Up @@ -63,13 +71,15 @@ internal class TemplateConfigurationFactoryTest {

val annualPackage = getPackageInfo(TestData.Packages.annual, currentlySubscribed = false)
val monthlyPackage = getPackageInfo(TestData.Packages.monthly, currentlySubscribed = true)
val lifetime = getPackageInfo(TestData.Packages.lifetime, currentlySubscribed = true)

val expectedConfiguration = TemplateConfiguration.PackageConfiguration.Multiple(
first = annualPackage,
default = monthlyPackage,
all = listOf(
annualPackage,
monthlyPackage,
lifetime
),
)

Expand Down Expand Up @@ -97,24 +107,28 @@ internal class TemplateConfigurationFactoryTest {
PackageType.ANNUAL -> "Annual"
PackageType.MONTHLY -> "Monthly"
PackageType.WEEKLY -> "Weekly"
PackageType.LIFETIME -> "Lifetime"
else -> error("Unknown package type ${rcPackage.packageType}")
}
val callToAction = when(rcPackage.packageType) {
PackageType.ANNUAL -> "Subscribe for $67.99/yr"
PackageType.MONTHLY -> "Subscribe for $7.99/mth"
PackageType.WEEKLY -> "Subscribe for $1.99/wk"
PackageType.LIFETIME -> "Subscribe for $1,000"
else -> error("Unknown package type ${rcPackage.packageType}")
}
val offerDetails = when(rcPackage.packageType) {
PackageType.ANNUAL -> "$67.99/yr ($5.67/mth)"
PackageType.MONTHLY -> "$7.99/mth"
PackageType.WEEKLY -> "$1.99/wk ($7.96/mth)"
PackageType.LIFETIME -> "$1,000"
else -> error("Unknown package type ${rcPackage.packageType}")
}
val offerDetailsWithIntroOffer = when(rcPackage.packageType) {
PackageType.ANNUAL -> "$67.99/yr ($5.67/mth) after 1 month trial"
PackageType.MONTHLY -> "$7.99/mth after trial"
PackageType.WEEKLY -> "$1.99/wk ($7.96/mth) after trial"
PackageType.LIFETIME -> "$1,000 after trial"
else -> error("Unknown package type ${rcPackage.packageType}")
}
val processedLocalization = ProcessedLocalizedConfiguration(
Expand Down
3 changes: 2 additions & 1 deletion ui/revenuecatui/src/test/resources/default_template.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@
},
"packages" : [
"$rc_annual",
"$rc_monthly"
"$rc_monthly",
"$rc_lifetime"
],
"privacy_url" : null,
"tos_url" : null
Expand Down