Skip to content

Commit

Permalink
Paywalls: Add experimental annotation to all public APIs in RevenueCa…
Browse files Browse the repository at this point in the history
…t UI (#1400)

### Description
This adds a new `ExperimentalPreviewRevenueCatUIPurchasesAPI` annotation
for `RevenueCatUI` experimental APIs, and marks all current public APIs
in this library as experimental. We plan to move from using a beta
version of the package to using these experimental APIs until we're
ready for stable release.

---------

Co-authored-by: NachoSoto <[email protected]>
  • Loading branch information
tonidero and NachoSoto authored Oct 27, 2023
1 parent 2436263 commit 65ada91
Show file tree
Hide file tree
Showing 39 changed files with 106 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import androidx.compose.material3.Surface
import androidx.compose.ui.Modifier
import com.revenuecat.paywallstester.ui.theme.PaywallTesterAndroidTheme
import com.revenuecat.purchases.Offering
import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI
import com.revenuecat.purchases.ui.revenuecatui.activity.PaywallActivityLauncher
import com.revenuecat.purchases.ui.revenuecatui.activity.PaywallResult
import com.revenuecat.purchases.ui.revenuecatui.activity.PaywallResultHandler

@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
class MainActivity : ComponentActivity(), PaywallResultHandler {
private lateinit var paywallActivityLauncher: PaywallActivityLauncher

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import com.revenuecat.paywallstester.MainActivity
import com.revenuecat.purchases.Offering
import com.revenuecat.purchases.Offerings
import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI
import com.revenuecat.purchases.ui.revenuecatui.PaywallDialog
import com.revenuecat.purchases.ui.revenuecatui.PaywallDialogOptions
import kotlinx.coroutines.flow.MutableStateFlow
Expand Down Expand Up @@ -73,6 +74,7 @@ private fun LoadingOfferingsScreen() {
}
}

@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
@Composable
private fun OfferingsListScreen(
offeringsState: OfferingsState.Loaded,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ import com.revenuecat.paywallstester.SamplePaywallsLoader
import com.revenuecat.paywallstester.ui.screens.paywallfooter.SamplePaywall
import com.revenuecat.paywallstester.ui.theme.googleFont
import com.revenuecat.purchases.Offering
import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI
import com.revenuecat.purchases.ui.revenuecatui.PaywallDialog
import com.revenuecat.purchases.ui.revenuecatui.PaywallDialogOptions
import com.revenuecat.purchases.ui.revenuecatui.PaywallFooter
import com.revenuecat.purchases.ui.revenuecatui.PaywallOptions
import com.revenuecat.purchases.ui.revenuecatui.fonts.CustomFontProvider
import com.revenuecat.purchases.ui.revenuecatui.fonts.FontProvider

@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
@Composable
fun PaywallsScreen(
samplePaywallsLoader: SamplePaywallsLoader = SamplePaywallsLoader(),
Expand Down Expand Up @@ -94,6 +96,7 @@ fun PaywallsScreen(
}
}

@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
@Composable
private fun FullScreenDialog(currentState: DisplayPaywallState.FullScreen, onDismiss: () -> Unit) {
PaywallDialog(
Expand All @@ -105,6 +108,7 @@ private fun FullScreenDialog(currentState: DisplayPaywallState.FullScreen, onDis
)
}

@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
@Composable
private fun FooterDialog(currentState: DisplayPaywallState.Footer, onDismiss: () -> Unit) {
Dialog(
Expand All @@ -126,9 +130,11 @@ private fun FooterDialog(currentState: DisplayPaywallState.Footer, onDismiss: ()
}
}

@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
private sealed class DisplayPaywallState {
object None : DisplayPaywallState()
data class FullScreen(
data class FullScreen
constructor(
val offering: Offering? = null,
val fontProvider: FontProvider? = null,
) : DisplayPaywallState()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.lifecycle.viewmodel.compose.viewModel
import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI
import com.revenuecat.purchases.ui.revenuecatui.Paywall
import com.revenuecat.purchases.ui.revenuecatui.PaywallOptions

@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
@Composable
fun PaywallScreen(
viewModel: PaywallScreenViewModel = viewModel<PaywallScreenViewModelImpl>(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ import com.revenuecat.purchases.PurchasesError
import com.revenuecat.purchases.PurchasesException
import com.revenuecat.purchases.awaitOfferings
import com.revenuecat.purchases.models.StoreTransaction
import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI
import com.revenuecat.purchases.ui.revenuecatui.PaywallListener
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch

@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
interface PaywallScreenViewModel : PaywallListener {
companion object {
const val OFFERING_ID_KEY = "offering_id"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import com.revenuecat.paywallstester.ui.screens.paywall.PaywallScreenState
import com.revenuecat.paywallstester.ui.screens.paywall.PaywallScreenViewModel
import com.revenuecat.paywallstester.ui.screens.paywall.PaywallScreenViewModelImpl
import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI
import com.revenuecat.purchases.ui.revenuecatui.PaywallFooter
import com.revenuecat.purchases.ui.revenuecatui.PaywallOptions

@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
@Composable
fun PaywallFooterScreen(
viewModel: PaywallScreenViewModel = viewModel<PaywallScreenViewModelImpl>(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.revenuecat.purchases.ui.revenuecatui

/**
* This annotation marks the experimental preview of the RevenueCat UI Purchases API.
* This API is in a preview state and has a very high chance of being changed in the near future.
Once RevenueCat UI is stable, this annotation will be removed.
*
* Any usage of a declaration annotated with `@ExperimentalPreviewRevenueCatUIPurchasesAPI` must be
* accepted either by annotating that usage with the [OptIn] annotation,
* e.g. `@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)`, or by using the compiler argument
* `-Xopt-in=kotlin.time.ExperimentalPreviewRevenueCatUIPurchasesAPI`.
*/
@Retention(value = AnnotationRetention.BINARY)
@RequiresOptIn(level = RequiresOptIn.Level.ERROR)
@Target(
AnnotationTarget.CLASS,
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY,
)
annotation class ExperimentalPreviewRevenueCatUIPurchasesAPI
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import com.revenuecat.purchases.ui.revenuecatui.templates.Template2
import com.revenuecat.purchases.ui.revenuecatui.templates.Template3
import com.revenuecat.purchases.ui.revenuecatui.templates.Template4

@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
@Composable
internal fun InternalPaywall(
options: PaywallOptions,
Expand Down Expand Up @@ -105,6 +106,7 @@ private fun TemplatePaywall(state: PaywallState.Loaded, viewModel: PaywallViewMo
}
}

@ExperimentalPreviewRevenueCatUIPurchasesAPI
@Composable
private fun getPaywallViewModel(
options: PaywallOptions,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import androidx.compose.runtime.Composable
* Composable offering a full screen Paywall UI configured from the RevenueCat dashboard.
* @param options The options to configure the [Paywall] if needed.
*/
@ExperimentalPreviewRevenueCatUIPurchasesAPI
@Composable
fun Paywall(options: PaywallOptions) {
InternalPaywall(options)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import kotlinx.coroutines.launch
* This dialog will be shown as a full screen dialog in compact devices and a normal dialog otherwise.
* @param paywallDialogOptions The options to configure the PaywallDialog and what to do on dismissal.
*/
@ExperimentalPreviewRevenueCatUIPurchasesAPI
@Composable
fun PaywallDialog(
paywallDialogOptions: PaywallDialogOptions,
Expand All @@ -49,6 +50,7 @@ fun PaywallDialog(
}
}

@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
@Composable
private fun DialogScaffold(paywallOptions: PaywallOptions) {
Scaffold(modifier = Modifier.fillMaxSize()) { paddingValues ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.revenuecat.purchases.Offering
import com.revenuecat.purchases.ui.revenuecatui.fonts.FontProvider
import com.revenuecat.purchases.ui.revenuecatui.helpers.shouldDisplayBlockForEntitlementIdentifier

@ExperimentalPreviewRevenueCatUIPurchasesAPI
class PaywallDialogOptions(builder: Builder) {

val shouldDisplayBlock: ((CustomerInfo) -> Boolean)?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import androidx.compose.ui.tooling.preview.Preview
* add that padding to your own content. This padding corresponds to the height of the rounded corner area of
* the paywall.
*/
@ExperimentalPreviewRevenueCatUIPurchasesAPI
@Composable
fun PaywallFooter(
options: PaywallOptions,
Expand All @@ -49,6 +50,7 @@ fun PaywallFooter(
}

@Suppress("MagicNumber")
@ExperimentalPreviewRevenueCatUIPurchasesAPI
@Preview(showBackground = true)
@Composable
private fun PaywallFooterPreview() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.revenuecat.purchases.Package
import com.revenuecat.purchases.PurchasesError
import com.revenuecat.purchases.models.StoreTransaction

@ExperimentalPreviewRevenueCatUIPurchasesAPI
interface PaywallListener {
fun onPurchaseStarted(rcPackage: Package) {}
fun onPurchaseCompleted(customerInfo: CustomerInfo, storeTransaction: StoreTransaction) {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ internal sealed class OfferingSelection {
}
}

@ExperimentalPreviewRevenueCatUIPurchasesAPI
class PaywallOptions(builder: Builder) {

internal val offeringSelection: OfferingSelection
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import com.revenuecat.purchases.CustomerInfo
import com.revenuecat.purchases.PurchasesError
import com.revenuecat.purchases.PurchasesErrorCode
import com.revenuecat.purchases.models.StoreTransaction
import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI
import com.revenuecat.purchases.ui.revenuecatui.Paywall
import com.revenuecat.purchases.ui.revenuecatui.PaywallListener
import com.revenuecat.purchases.ui.revenuecatui.PaywallOptions
Expand All @@ -31,6 +32,7 @@ import com.revenuecat.purchases.ui.revenuecatui.fonts.TypographyType
* Wrapper activity around [Paywall] that allows using it when you are not using Jetpack Compose directly.
* It receives the [PaywallActivityArgs] as an extra and returns the [PaywallResult] as a result.
*/
@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
internal class PaywallActivity : ComponentActivity(), PaywallListener {
companion object {
const val ARGS_EXTRA = "paywall_args"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.revenuecat.purchases.ui.revenuecatui.activity

import android.os.Parcelable
import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI
import com.revenuecat.purchases.ui.revenuecatui.fonts.ParcelizableFontProvider
import com.revenuecat.purchases.ui.revenuecatui.fonts.PaywallFontFamily
import com.revenuecat.purchases.ui.revenuecatui.fonts.TypographyType
import kotlinx.parcelize.Parcelize

@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
@Parcelize
internal data class PaywallActivityArgs(
val offeringId: String? = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,22 @@ import androidx.activity.result.ActivityResultLauncher
import androidx.fragment.app.Fragment
import com.revenuecat.purchases.CustomerInfo
import com.revenuecat.purchases.Offering
import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI
import com.revenuecat.purchases.ui.revenuecatui.fonts.ParcelizableFontProvider
import com.revenuecat.purchases.ui.revenuecatui.helpers.shouldDisplayBlockForEntitlementIdentifier
import com.revenuecat.purchases.ui.revenuecatui.helpers.shouldDisplayPaywall

/**
* Implement this interface to receive the result of the paywall activity.
*/
@ExperimentalPreviewRevenueCatUIPurchasesAPI
interface PaywallResultHandler : ActivityResultCallback<PaywallResult>

/**
* Launches the paywall activity. You need to create this object during the activity's onCreate.
* Then launch the activity at your moment of choice
*/
@ExperimentalPreviewRevenueCatUIPurchasesAPI
class PaywallActivityLauncher {

private var activityResultLauncher: ActivityResultLauncher<PaywallActivityArgs>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import android.os.Build
import androidx.activity.result.contract.ActivityResultContract
import com.revenuecat.purchases.PurchasesError
import com.revenuecat.purchases.PurchasesErrorCode
import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI

/**
* Contract that specifies how to launch the paywall activity and how to parse its result, abstracting
* that logic from the caller.
*/
@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
internal class PaywallContract : ActivityResultContract<PaywallActivityArgs, PaywallResult>() {
override fun createIntent(context: Context, args: PaywallActivityArgs): Intent {
return Intent(context, PaywallActivity::class.java).apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package com.revenuecat.purchases.ui.revenuecatui.activity
import android.os.Parcelable
import com.revenuecat.purchases.CustomerInfo
import com.revenuecat.purchases.PurchasesError
import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI
import kotlinx.parcelize.Parcelize

/**
* Result of the paywall activity.
*/
@ExperimentalPreviewRevenueCatUIPurchasesAPI
sealed class PaywallResult : Parcelable {
/**
* The user cancelled the paywall without purchasing.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import com.revenuecat.purchases.Package
import com.revenuecat.purchases.PurchaseParams
import com.revenuecat.purchases.PurchasesError
import com.revenuecat.purchases.PurchasesException
import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI
import com.revenuecat.purchases.ui.revenuecatui.PaywallListener
import com.revenuecat.purchases.ui.revenuecatui.PaywallMode
import com.revenuecat.purchases.ui.revenuecatui.PaywallOptions
Expand Down Expand Up @@ -51,6 +52,7 @@ internal interface PaywallViewModel {
fun clearActionError()
}

@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
@Suppress("TooManyFunctions")
internal class PaywallViewModelImpl(
private val applicationContext: ApplicationContext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package com.revenuecat.purchases.ui.revenuecatui.data
import androidx.compose.material3.ColorScheme
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI
import com.revenuecat.purchases.ui.revenuecatui.PaywallOptions
import com.revenuecat.purchases.ui.revenuecatui.helpers.ApplicationContext

@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
internal class PaywallViewModelFactory(
private val applicationContext: ApplicationContext,
private val options: PaywallOptions,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package com.revenuecat.purchases.ui.revenuecatui.errors

class PackageConfigurationError(override val message: String) : Throwable(message)
internal class PackageConfigurationError(override val message: String) : Throwable(message)
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package com.revenuecat.purchases.ui.revenuecatui.errors
import com.revenuecat.purchases.Offering
import com.revenuecat.purchases.ui.revenuecatui.strings.PaywallValidationErrorStrings

sealed class PaywallValidationError : Throwable() {
internal sealed class PaywallValidationError : Throwable() {

fun associatedErrorString(offering: Offering): String {
return when (this) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import com.revenuecat.purchases.Offering
import com.revenuecat.purchases.Package
import com.revenuecat.purchases.paywalls.PaywallColor
import com.revenuecat.purchases.paywalls.PaywallData
import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI
import com.revenuecat.purchases.ui.revenuecatui.InternalPaywall
import com.revenuecat.purchases.ui.revenuecatui.PaywallOptions
import com.revenuecat.purchases.ui.revenuecatui.R
Expand Down Expand Up @@ -119,6 +120,7 @@ private fun getThemeColors(currentColorScheme: ColorScheme): PaywallData.Configu

private fun Color.asPaywallColor(): PaywallColor = PaywallColor(colorInt = this.toArgb())

@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
@Preview(showBackground = true, locale = "en-rUS")
@Preview(showBackground = true, locale = "es-rES")
@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ package com.revenuecat.purchases.ui.revenuecatui.extensions

import androidx.compose.material3.Typography
import androidx.compose.ui.text.TextStyle
import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI
import com.revenuecat.purchases.ui.revenuecatui.fonts.FontProvider
import com.revenuecat.purchases.ui.revenuecatui.fonts.TypographyType

@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
fun Typography.copyWithFontProvider(fontProvider: FontProvider): Typography {
with(this) {
return copy(
Expand All @@ -27,6 +29,7 @@ fun Typography.copyWithFontProvider(fontProvider: FontProvider): Typography {
}
}

@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
private fun TextStyle.modifyFontIfNeeded(typographyType: TypographyType, fontProvider: FontProvider): TextStyle {
val font = fontProvider.getFont(typographyType)
return if (font == null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package com.revenuecat.purchases.ui.revenuecatui.fonts

import androidx.compose.ui.text.font.FontFamily
import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI

/**
* Class that allows to provide a font family for all text styles.
* @param fontFamily the [FontFamily] to be used for all text styles.
*/
@ExperimentalPreviewRevenueCatUIPurchasesAPI
class CustomFontProvider(private val fontFamily: FontFamily) : FontProvider {
override fun getFont(type: TypographyType) = fontFamily
}
Loading

0 comments on commit 65ada91

Please sign in to comment.