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: Add simple paywall and use in tester app #1223

Merged

Conversation

tonidero
Copy link
Contributor

@tonidero tonidero commented Sep 6, 2023

Description

This PR adds a simple paywall to the revenuecatui library and uses it to display the paywall in paywall tester. Still pretty barebones but it's a start :P

Screen_recording_20230906_145136.mp4

@tonidero tonidero added refactor A code change that neither fixes a bug nor adds a feature test Adding missing tests or correcting existing tests labels Sep 6, 2023
private val offeringId = savedStateHandle.get<String?>(PaywallScreenViewModel.OFFERING_ID_KEY)

init {
updateOffering()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to refetch the offering, since after navigating to this screen, we only have the offeringId.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are also loading in the PaywallViewModel right? Do we need to do it in both places?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is in the paywall tester app, the other is in the library itself. We could offer an API so users can pass an offering id, and not an offering... But that seems worse, since they might send other strings, so I would prefer not to if possible.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it! Passing an offering and getting the current if null makes sense!

import com.revenuecat.purchases.Offering

@Composable
internal fun InternalPaywallView(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved the UI to an "internal" view, so we can separate the actual UI from the API.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have something similar since the public one will have to do loading and processing of the config. The internal one is simpler if it depends on the actual final requirements.

import androidx.lifecycle.ViewModelProvider
import com.revenuecat.purchases.Offering

class PaywallViewModelFactory(private val offering: Offering?) : ViewModelProvider.NewInstanceFactory() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To pass parameters to the view model, a factory like this is required... One of the problems of architecture component's viewModel.

Log.e("PaywallTester", "Error purchasing package: $error")
},
onSuccess = { purchase, _ ->
Log.i("PaywallTester", "Purchased package: $purchase")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should at least display some sort of UI, but in this PR, I'm just logging. Will follow-up with some alerts in the next PR.

@tonidero tonidero marked this pull request as ready for review September 6, 2023 12:56
@tonidero tonidero requested a review from a team September 6, 2023 12:56
@codecov
Copy link

codecov bot commented Sep 6, 2023

Codecov Report

❗ No coverage uploaded for pull request base (paywalls@208385a). Click here to learn what that means.
Patch has no changes to coverable lines.

❗ Current head cda6832 differs from pull request most recent head bba0dc1. Consider uploading reports for the commit bba0dc1 to get more accurate results

Additional details and impacted files
@@             Coverage Diff             @@
##             paywalls    #1223   +/-   ##
===========================================
  Coverage            ?   85.25%           
===========================================
  Files               ?      186           
  Lines               ?     6319           
  Branches            ?      911           
===========================================
  Hits                ?     5387           
  Misses              ?      586           
  Partials            ?      346           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@@ -54,6 +64,7 @@ dependencies {
implementation project(path: ':purchases')
implementation project(path: ':feature:amazon')
implementation project(path: ':ui:debugview')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

Text(text = "Error: ${state.errorMessage}")
}
is PaywallScreenState.Loaded -> {
PaywallView(PaywallViewOptions.Builder().setOffering(state.offering).build())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice


import com.revenuecat.purchases.Offering

sealed class PaywallScreenState {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love it. I wonder if you'll need to move it to the UI framework to handle these 3 states there instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a state in the library as well, but that's internal. This is needed because we need to refetch the Offering since we only get the offering_id in this screen.

}

private fun updateOffering() {
Purchases.sharedInstance.getOfferingsWith(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to use the coroutines? 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup! I wasn't thinking about it but we totally could! Will do that in a followup PR

import com.revenuecat.purchases.Offering

@Composable
internal fun InternalPaywallView(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have something similar since the public one will have to do loading and processing of the config. The internal one is simpler if it depends on the actual final requirements.

Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not perfect at this, but I'd recommend starting to extract some of these magic numbers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, this is too early in the UI 😅, since this whole UI is probably going away. But yeah, we should extract these.

}

override fun purchasePackage(activity: Activity, packageToPurchase: Package) {
Purchases.sharedInstance.purchaseWith(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to use coroutines here too?
It will make it easier to update the internal state to avoid multiple concurrent purchases (to disable the buttons on the UI).
See PurchaseHandler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup as mentioned above, will do that in a followup PR

@tonidero tonidero changed the title Add simple paywall and use in tester app Paywalls: Add simple paywall and use in tester app Sep 6, 2023
Base automatically changed from toniricodiez/pwl-221-create-paywall-tester-sample-app-2 to paywalls September 6, 2023 17:04
@tonidero tonidero force-pushed the toniricodiez/pwl-221-create-paywall-tester-sample-app-3 branch from cda6832 to bba0dc1 Compare September 6, 2023 17:04
@tonidero tonidero merged commit 0377b53 into paywalls Sep 6, 2023
3 of 5 checks passed
@tonidero tonidero deleted the toniricodiez/pwl-221-create-paywall-tester-sample-app-3 branch September 6, 2023 17:12
tonidero added a commit that referenced this pull request Oct 31, 2023
### Description
This PR adds a simple paywall to the revenuecatui library and uses it to
display the paywall in paywall tester. Still pretty barebones but it's a
start :P


https://github.com/RevenueCat/purchases-android/assets/808417/b4a4b85c-68dc-4cc0-9019-2baefb50e2e3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
refactor A code change that neither fixes a bug nor adds a feature RevenueCatUI test Adding missing tests or correcting existing tests
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants