Skip to content

Commit

Permalink
Paywalls: Call PaywallDialog dismiss handler after successful resto…
Browse files Browse the repository at this point in the history
…re if needed (#1610)

### Description
When using `PaywallDialog` composable, if the user restored and matched
the `requiredEntitlementIdentifier` or condition to display the paywall
given by the developer, we were not dismissing the paywall
automatically.

This fixes that, and auto-dismisses the paywall after a successful
restore if it matches the given condition by the developer.
  • Loading branch information
tonidero authored Feb 14, 2024
1 parent aa9f9b8 commit 663112b
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.lifecycle.viewmodel.compose.viewModel
import com.revenuecat.purchases.CustomerInfo
import com.revenuecat.purchases.ui.revenuecatui.UIConstant.defaultAnimation
import com.revenuecat.purchases.ui.revenuecatui.composables.CloseButton
import com.revenuecat.purchases.ui.revenuecatui.data.PaywallState
Expand Down Expand Up @@ -160,6 +161,7 @@ private fun TemplatePaywall(state: PaywallState.Loaded, viewModel: PaywallViewMo
@Composable
internal fun getPaywallViewModel(
options: PaywallOptions,
shouldDisplayBlock: ((CustomerInfo) -> Boolean)? = null,
): PaywallViewModel {
val applicationContext = LocalContext.current.applicationContext
val viewModel = viewModel<PaywallViewModelImpl>(
Expand All @@ -168,6 +170,7 @@ internal fun getPaywallViewModel(
options,
MaterialTheme.colorScheme,
isSystemInDarkTheme(),
shouldDisplayBlock = shouldDisplayBlock,
preview = isInPreviewMode(),
),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ fun PaywallDialog(
}
val paywallOptions = paywallDialogOptions.toPaywallOptions(dismissRequest)

val viewModel = getPaywallViewModel(options = paywallOptions)
val viewModel = getPaywallViewModel(
options = paywallOptions,
shouldDisplayBlock = paywallDialogOptions.shouldDisplayBlock,
)

Dialog(
onDismissRequest = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,14 @@ internal interface PaywallViewModel {
}

@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class, ExperimentalPreviewRevenueCatPurchasesAPI::class)
@Suppress("TooManyFunctions")
@Suppress("TooManyFunctions", "LongParameterList")
internal class PaywallViewModelImpl(
override val resourceProvider: ResourceProvider,
private val purchases: PurchasesType = PurchasesImpl(),
private var options: PaywallOptions,
colorScheme: ColorScheme,
private var isDarkMode: Boolean,
private val shouldDisplayBlock: ((CustomerInfo) -> Boolean)?,
preview: Boolean = false,
) : ViewModel(), PaywallViewModel {
private val variableDataProvider = VariableDataProvider(resourceProvider, preview)
Expand Down Expand Up @@ -167,9 +168,18 @@ internal class PaywallViewModelImpl(
viewModelScope.launch {
try {
listener?.onRestoreStarted()

val customerInfo = purchases.awaitRestore()

Logger.i("Restore purchases successful: $customerInfo")
listener?.onRestoreCompleted(customerInfo)

shouldDisplayBlock?.let {
if (!it(customerInfo)) {
Logger.d("Dismissing paywall after restore since display condition has not been met")
options.dismissRequest()
}
}
} catch (e: PurchasesException) {
Logger.e("Error restoring purchases: $e")
listener?.onRestoreError(e.error)
Expand Down Expand Up @@ -201,6 +211,7 @@ internal class PaywallViewModelImpl(
PurchaseParams.Builder(activity, packageToPurchase),
)
listener?.onPurchaseCompleted(purchaseResult.customerInfo, purchaseResult.storeTransaction)
Logger.d("Dismissing paywall after purchase")
options.dismissRequest()
} catch (e: PurchasesException) {
if (e.code == PurchasesErrorCode.PurchaseCancelledError) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.revenuecat.purchases.ui.revenuecatui.data
import androidx.compose.material3.ColorScheme
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.revenuecat.purchases.CustomerInfo
import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI
import com.revenuecat.purchases.ui.revenuecatui.PaywallOptions
import com.revenuecat.purchases.ui.revenuecatui.helpers.ResourceProvider
Expand All @@ -13,6 +14,7 @@ internal class PaywallViewModelFactory(
private val options: PaywallOptions,
private val colorScheme: ColorScheme,
private val isDarkMode: Boolean,
private val shouldDisplayBlock: ((CustomerInfo) -> Boolean)?,
private val preview: Boolean = false,
) : ViewModelProvider.NewInstanceFactory() {
@Suppress("UNCHECKED_CAST")
Expand All @@ -23,6 +25,7 @@ internal class PaywallViewModelFactory(
colorScheme = colorScheme,
isDarkMode = isDarkMode,
preview = preview,
shouldDisplayBlock = shouldDisplayBlock,
) as T
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ class PaywallViewModelTest {
options,
TestData.Constants.currentColorScheme,
isDarkMode = false,
shouldDisplayBlock = null,
)
coVerify(exactly = 1) { purchases.awaitOfferings() }
model.updateOptions(options)
Expand All @@ -148,6 +149,7 @@ class PaywallViewModelTest {
options1,
TestData.Constants.currentColorScheme,
isDarkMode = false,
shouldDisplayBlock = null,
)
coVerify(exactly = 1) { purchases.awaitOfferings() }
model.updateOptions(options1)
Expand Down Expand Up @@ -357,6 +359,37 @@ class PaywallViewModelTest {
assertThat(dismissInvoked).isFalse
}

@Test
fun `restorePurchases calls onDismiss if shouldDisplayBlock condition false`() {
val model = create {
false
}

coEvery {
purchases.awaitRestore()
} returns customerInfo

model.restorePurchases()

assertThat(dismissInvoked).isTrue()
}

@Test
fun `restorePurchases does not call onDismiss if shouldDisplayBlock condition true`() {
val model = create {
true
}

coEvery {
purchases.awaitRestore()
} returns customerInfo

model.restorePurchases()

assertThat(dismissInvoked).isFalse()
}


@Test
fun `restorePurchases fails`() {
val model = create()
Expand Down Expand Up @@ -536,6 +569,7 @@ class PaywallViewModelTest {
offering: Offering? = null,
activeSubscriptions: Set<String> = setOf(),
nonSubscriptionTransactionProductIdentifiers: Set<String> = setOf(),
shouldDisplayBlock: ((CustomerInfo) -> Boolean)? = null,
): PaywallViewModelImpl {
mockActiveSubscriptions(activeSubscriptions)
mockNonSubscriptionTransactions(nonSubscriptionTransactionProductIdentifiers)
Expand All @@ -549,6 +583,7 @@ class PaywallViewModelTest {
.build(),
TestData.Constants.currentColorScheme,
isDarkMode = false,
shouldDisplayBlock = shouldDisplayBlock,
)
}

Expand Down

0 comments on commit 663112b

Please sign in to comment.