react-native-purchases-ui 7.15.0-rc.1 → 7.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,6 +17,6 @@ Pod::Spec.new do |spec|
17
17
  spec.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }
18
18
 
19
19
  spec.dependency "React-Core"
20
- spec.dependency "PurchasesHybridCommon", '8.10.0-beta.8'
20
+ spec.dependency "PurchasesHybridCommon", '8.11.1'
21
21
  spec.swift_version = '5.7'
22
22
  end
@@ -59,7 +59,7 @@ android {
59
59
  minSdkVersion getExtOrIntegerDefault("minSdkVersion")
60
60
  targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
61
61
  versionCode 1
62
- versionName '7.15.0-rc.1'
62
+ versionName '7.16.0'
63
63
  }
64
64
 
65
65
  buildTypes {
@@ -91,8 +91,7 @@ dependencies {
91
91
  //noinspection GradleDynamicVersion
92
92
  implementation "com.facebook.react:react-native:+"
93
93
  implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
94
- implementation 'com.revenuecat.purchases:purchases-hybrid-common-ui:8.10.0-beta.8'
94
+ implementation 'com.revenuecat.purchases:purchases-hybrid-common-ui:8.11.1'
95
95
  implementation 'androidx.compose.ui:ui-android:1.5.4'
96
96
  implementation "androidx.appcompat:appcompat:1.6.1"
97
97
  }
98
-
@@ -0,0 +1,64 @@
1
+ package com.revenuecat.purchases.react.ui
2
+
3
+ import android.annotation.SuppressLint
4
+ import androidx.core.view.children
5
+ import com.facebook.react.uimanager.SimpleViewManager
6
+ import com.facebook.react.uimanager.ThemedReactContext
7
+ import com.facebook.react.uimanager.UIManagerModule
8
+ import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI
9
+ import com.revenuecat.purchases.ui.revenuecatui.views.PaywallFooterView
10
+
11
+ @OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
12
+ internal class PaywallFooterViewManager : SimpleViewManager<PaywallFooterView>() {
13
+ override fun getName(): String {
14
+ return "RCPaywallFooterView"
15
+ }
16
+
17
+ @SuppressLint("UnsafeOptInUsageError")
18
+ override fun createViewInstance(themedReactContext: ThemedReactContext): PaywallFooterView {
19
+ val paywallFooterView: PaywallFooterView = object : PaywallFooterView(themedReactContext) {
20
+
21
+ // This is required so the change from Loading to Loaded resizes the view
22
+ // https://github.com/facebook/react-native/issues/17968#issuecomment-1672111483
23
+ override fun requestLayout() {
24
+ super.requestLayout()
25
+ post(measureAndLayout)
26
+ }
27
+
28
+ private val measureAndLayout = Runnable {
29
+ measure(
30
+ MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
31
+ MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
32
+ )
33
+ layout(left, top, right, bottom)
34
+ }
35
+
36
+ // This is needed so it measures correctly the size of the children and react native can
37
+ // size the Javascript view correctly. Not doing this will render the view with height 0
38
+ // and will require the devs to set a fixed height to the view, which is not ideal
39
+ // https://medium.com/traveloka-engineering/react-native-at-traveloka-native-ui-components-c6b66f789f35
40
+ public override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
41
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
42
+ var maxWidth = 0
43
+ var maxHeight = 0
44
+ children.forEach {
45
+ it.measure(widthMeasureSpec, MeasureSpec.UNSPECIFIED)
46
+ maxWidth = maxWidth.coerceAtLeast(it.measuredWidth)
47
+ maxHeight = maxHeight.coerceAtLeast(it.measuredHeight)
48
+ }
49
+ val finalWidth = maxWidth.coerceAtLeast(suggestedMinimumWidth)
50
+ val finalHeight = maxHeight.coerceAtLeast(suggestedMinimumHeight)
51
+ setMeasuredDimension(finalWidth, finalHeight)
52
+ (context as? ThemedReactContext)?.let { themedReactContext ->
53
+ themedReactContext.runOnNativeModulesQueueThread {
54
+ themedReactContext.getNativeModule(UIManagerModule::class.java)
55
+ ?.updateNodeSize(id, finalWidth, finalHeight)
56
+ }
57
+ }
58
+ }
59
+ }
60
+
61
+ return paywallFooterView
62
+ }
63
+
64
+ }
@@ -0,0 +1,25 @@
1
+ package com.revenuecat.purchases.react.ui
2
+
3
+ import com.facebook.react.uimanager.SimpleViewManager
4
+ import com.facebook.react.uimanager.ThemedReactContext
5
+ import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI
6
+ import com.revenuecat.purchases.ui.revenuecatui.views.PaywallView
7
+
8
+ @OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
9
+ internal class PaywallViewManager : SimpleViewManager<PaywallView>() {
10
+ companion object {
11
+ const val REACT_CLASS = "Paywall"
12
+ }
13
+
14
+ override fun getName(): String {
15
+ return REACT_CLASS
16
+ }
17
+
18
+ override fun createViewInstance(themedReactContext: ThemedReactContext): PaywallView {
19
+ return PaywallView(themedReactContext)
20
+ }
21
+
22
+ override fun createShadowNodeInstance(): PaywallViewShadowNode {
23
+ return PaywallViewShadowNode()
24
+ }
25
+ }
@@ -0,0 +1,29 @@
1
+ package com.revenuecat.purchases.react.ui
2
+
3
+ import android.view.View
4
+ import com.facebook.react.uimanager.LayoutShadowNode
5
+ import com.facebook.yoga.YogaMeasureFunction
6
+ import com.facebook.yoga.YogaMeasureMode
7
+ import com.facebook.yoga.YogaMeasureOutput
8
+ import com.facebook.yoga.YogaNode
9
+
10
+ internal class PaywallViewShadowNode: LayoutShadowNode(), YogaMeasureFunction {
11
+ init {
12
+ setMeasureFunction(this)
13
+ }
14
+
15
+ override fun measure(
16
+ yogaNode: YogaNode,
17
+ width: Float,
18
+ yogaMeasureMode: YogaMeasureMode,
19
+ height: Float,
20
+ yogaMeasureMode1: YogaMeasureMode
21
+ ): Long {
22
+ // This is needed so the footer doesn't require a fixed height
23
+ // https://nicholasmarais1158.github.io/2017/07/React-Native-Custom-Measuring
24
+ val measuredWidth = View.MeasureSpec.getSize(width.toInt()).toFloat()
25
+ val measuredHeight = View.MeasureSpec.getSize(height.toInt()).toFloat()
26
+
27
+ return YogaMeasureOutput.make(measuredWidth, measuredHeight)
28
+ }
29
+ }
@@ -1,9 +1,13 @@
1
1
  package com.revenuecat.purchases.react.ui
2
2
 
3
+ import android.util.Log
3
4
  import androidx.fragment.app.FragmentActivity
5
+ import com.facebook.react.bridge.Promise
4
6
  import com.facebook.react.bridge.ReactApplicationContext
5
7
  import com.facebook.react.bridge.ReactContextBaseJavaModule
6
8
  import com.facebook.react.bridge.ReactMethod
9
+ import com.facebook.react.bridge.ReadableMap
10
+ import com.revenuecat.purchases.hybridcommon.ui.PaywallResultListener
7
11
  import com.revenuecat.purchases.hybridcommon.ui.presentPaywallFromFragment
8
12
 
9
13
  internal class RNPaywallsModule(reactContext: ReactApplicationContext) :
@@ -16,7 +20,10 @@ internal class RNPaywallsModule(reactContext: ReactApplicationContext) :
16
20
  get() {
17
21
  return when (val currentActivity = currentActivity) {
18
22
  is FragmentActivity -> currentActivity
19
- else -> null
23
+ else -> {
24
+ Log.e(NAME, "RevenueCat paywalls require application to use a FragmentActivity")
25
+ null
26
+ }
20
27
  }
21
28
  }
22
29
 
@@ -25,20 +32,58 @@ internal class RNPaywallsModule(reactContext: ReactApplicationContext) :
25
32
  }
26
33
 
27
34
  @ReactMethod
28
- fun presentPaywall() {
29
- presentPaywall(null)
35
+ fun presentPaywall(
36
+ options: ReadableMap,
37
+ promise: Promise
38
+ ) {
39
+ val hashMap = options.toHashMap()
40
+ val offeringIdentifier = hashMap["offeringIdentifier"] as String?
41
+ val displayCloseButton = hashMap["displayCloseButton"] as Boolean?
42
+
43
+ presentPaywall(
44
+ null,
45
+ offeringIdentifier,
46
+ displayCloseButton,
47
+ promise
48
+ )
30
49
  }
31
50
 
32
51
  @ReactMethod
33
- fun presentPaywallIfNeeded(requiredEntitlementIdentifier: String?) {
34
- presentPaywall(requiredEntitlementIdentifier)
52
+ fun presentPaywallIfNeeded(
53
+ options: ReadableMap,
54
+ promise: Promise
55
+ ) {
56
+ val hashMap = options.toHashMap()
57
+ val requiredEntitlementIdentifier = hashMap["requiredEntitlementIdentifier"] as String?
58
+ val offeringIdentifier = hashMap["offeringIdentifier"] as String?
59
+ val displayCloseButton = hashMap["displayCloseButton"] as Boolean?
60
+
61
+ presentPaywall(
62
+ requiredEntitlementIdentifier,
63
+ offeringIdentifier,
64
+ displayCloseButton,
65
+ promise
66
+ )
35
67
  }
36
68
 
37
- private fun presentPaywall(requiredEntitlementIdentifier: String?) {
38
- val fragment = currentActivityFragment
39
- ?: // TODO: log
40
- return
69
+ private fun presentPaywall(
70
+ requiredEntitlementIdentifier: String?,
71
+ offeringIdentifier: String?,
72
+ displayCloseButton: Boolean?,
73
+ promise: Promise
74
+ ) {
75
+ val fragment = currentActivityFragment ?: return
41
76
 
42
- presentPaywallFromFragment(fragment, requiredEntitlementIdentifier)
77
+ // TODO wire offeringIdentifier
78
+ presentPaywallFromFragment(
79
+ fragment = fragment,
80
+ requiredEntitlementIdentifier = requiredEntitlementIdentifier,
81
+ shouldDisplayDismissButton = displayCloseButton,
82
+ paywallResultListener = object : PaywallResultListener {
83
+ override fun onPaywallResult(paywallResult: String) {
84
+ promise.resolve(paywallResult)
85
+ }
86
+ }
87
+ )
43
88
  }
44
89
  }
@@ -12,6 +12,6 @@ class RNPaywallsPackage : ReactPackage {
12
12
  }
13
13
 
14
14
  override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
15
- return listOf(RNPaywallManager())
15
+ return listOf(PaywallViewManager(), PaywallFooterViewManager())
16
16
  }
17
17
  }
@@ -10,7 +10,7 @@
10
10
 
11
11
  NS_ASSUME_NONNULL_BEGIN
12
12
 
13
- @interface RNPaywallManager : RCTViewManager
13
+ @interface PaywallViewManager : RCTViewManager
14
14
 
15
15
  @end
16
16
 
@@ -6,12 +6,12 @@
6
6
  // Copyright © 2023 Facebook. All rights reserved.
7
7
  //
8
8
 
9
- #import "RNPaywallManager.h"
9
+ #import "PaywallViewManager.h"
10
10
  @import PurchasesHybridCommon;
11
11
 
12
- @implementation RNPaywallManager
12
+ @implementation PaywallViewManager
13
13
 
14
- RCT_EXPORT_MODULE(RNPaywall)
14
+ RCT_EXPORT_MODULE(Paywall)
15
15
 
16
16
  - (UIView *)view
17
17
  {
@@ -0,0 +1,17 @@
1
+ //
2
+ // RCPaywallFooterViewManager.h
3
+ // Pods
4
+ //
5
+ // Created by Cesar de la Vega on 29/12/23.
6
+ // Copyright © 2023 Facebook. All rights reserved.
7
+ //
8
+
9
+ #import <React/RCTViewManager.h>
10
+
11
+ NS_ASSUME_NONNULL_BEGIN
12
+
13
+ @interface RCPaywallFooterViewManager : RCTViewManager
14
+
15
+ @end
16
+
17
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,147 @@
1
+ //
2
+ // RCPaywallFooterViewManager.m
3
+ // RNPaywalls
4
+ //
5
+ // Created by Cesar de la Vega on 29/12/23.
6
+ //
7
+
8
+ #import "RNPaywalls.h"
9
+ #import "RCPaywallFooterViewManager.h"
10
+
11
+ @import RevenueCatUI;
12
+ @import PurchasesHybridCommon;
13
+
14
+ #import "UIView+Extensions.h"
15
+
16
+ #import <React/RCTShadowView.h>
17
+ #import <React/RCTUIManager.h>
18
+ #import <React/RCTBridge.h>
19
+ #import <React/RCTRootViewDelegate.h>
20
+ #import <React/RCTEventEmitter.h>
21
+
22
+
23
+ NS_ASSUME_NONNULL_BEGIN
24
+
25
+ @interface FooterViewWrapper : UIView
26
+
27
+ - (instancetype)initWithFooterViewController:(UIViewController *)footerViewController
28
+ bridge:(RCTBridge *)bridge;
29
+
30
+ @end
31
+
32
+ NS_ASSUME_NONNULL_END
33
+
34
+ @interface FooterViewWrapper () <RCPaywallViewControllerDelegate>
35
+
36
+ @property (strong, nonatomic) UIViewController *footerViewController;
37
+ @property (strong, nonatomic) RCTBridge *bridge;
38
+
39
+ @property BOOL addedToHierarchy;
40
+
41
+ @end
42
+
43
+ @implementation FooterViewWrapper
44
+
45
+ - (instancetype)initWithFooterViewController:(UIViewController *)footerViewController bridge:(RCTBridge *)bridge {
46
+ if ((self = [super initWithFrame:footerViewController.view.bounds])) {
47
+ _bridge = bridge;
48
+ _footerViewController = footerViewController;
49
+ }
50
+
51
+ return self;
52
+ }
53
+
54
+ - (void)safeAreaInsetsDidChange {
55
+ [super safeAreaInsetsDidChange];
56
+
57
+ // Get the safe area insets, for example
58
+ UIEdgeInsets safeAreaInsets = self.safeAreaInsets;
59
+
60
+ // TODO: figure out a better way of sending event, since this is deprecated
61
+ // It's probably better to create a singleton from the module that this view manager can call and use to send events
62
+ #pragma clang diagnostic push
63
+ #pragma clang diagnostic ignored "-Wdeprecated-declarations"
64
+ [self.bridge.eventDispatcher sendAppEventWithName:safeAreaInsetsDidChangeEvent
65
+ body:@{@"top": @(safeAreaInsets.top),
66
+ @"left": @(safeAreaInsets.left),
67
+ @"bottom": @(safeAreaInsets.bottom),
68
+ @"right": @(safeAreaInsets.right)}];
69
+ #pragma clang diagnostic pop
70
+ }
71
+
72
+ - (void)paywallViewController:(RCPaywallViewController *)controller didChangeSizeTo:(CGSize)size API_AVAILABLE(ios(15.0)){
73
+ [_bridge.uiManager setSize:size forView:self];
74
+ }
75
+
76
+ - (void)layoutSubviews {
77
+ [super layoutSubviews];
78
+
79
+ // Need to wait for this view to be in the hierarchy to look for the parent UIVC.
80
+ // This is required to add a SwiftUI `UIHostingController` to the hierarchy in a way that allows
81
+ // UIKit to read properties from the environment, like traits and safe area.
82
+ if (!self.addedToHierarchy) {
83
+ UIViewController *parentController = self.parentViewController;
84
+ if (parentController) {
85
+ self.footerViewController.view.translatesAutoresizingMaskIntoConstraints = NO;
86
+ [parentController addChildViewController:self.footerViewController];
87
+ [self addSubview:self.footerViewController.view];
88
+ [self.footerViewController didMoveToParentViewController:parentController];
89
+
90
+ [NSLayoutConstraint activateConstraints:@[
91
+ [self.footerViewController.view.topAnchor constraintEqualToAnchor:self.topAnchor],
92
+ [self.footerViewController.view.bottomAnchor constraintEqualToAnchor:self.bottomAnchor],
93
+ [self.footerViewController.view.leftAnchor constraintEqualToAnchor:self.leftAnchor],
94
+ [self.footerViewController.view.rightAnchor constraintEqualToAnchor:self.rightAnchor]
95
+ ]];
96
+
97
+ self.addedToHierarchy = YES;
98
+ }
99
+ }
100
+ }
101
+
102
+ @end
103
+
104
+ @interface RCPaywallFooterViewManager ()
105
+
106
+ @property (nonatomic, strong) id proxyIfAvailable;
107
+
108
+ @end
109
+
110
+ @implementation RCPaywallFooterViewManager
111
+
112
+ RCT_EXPORT_MODULE(RCPaywallFooterView)
113
+
114
+ - (instancetype)init {
115
+ if ((self = [super init])) {
116
+ if (@available(iOS 15.0, *)) {
117
+ _proxyIfAvailable = [[PaywallProxy alloc] init];
118
+ }
119
+ }
120
+
121
+ return self;
122
+ }
123
+
124
+ - (PaywallProxy *)proxy API_AVAILABLE(ios(15.0)){
125
+ return (PaywallProxy *)self.proxyIfAvailable;
126
+ }
127
+
128
+ - (UIView *)view
129
+ {
130
+ if (@available(iOS 15.0, *)) {
131
+ UIViewController *footerViewController = [self.proxy createFooterPaywallView];
132
+ FooterViewWrapper *wrapper = [[FooterViewWrapper alloc] initWithFooterViewController:footerViewController
133
+ bridge:self.bridge];
134
+ self.proxy.delegate = wrapper;
135
+
136
+ return wrapper;
137
+ } else {
138
+ NSLog(@"Error: attempted to present paywalls on unsupported iOS version.");
139
+ return nil;
140
+ }
141
+ }
142
+
143
+ + (BOOL)requiresMainQueueSetup {
144
+ return YES;
145
+ }
146
+
147
+ @end
package/ios/RNPaywalls.h CHANGED
@@ -8,6 +8,8 @@
8
8
  @import PurchasesHybridCommon;
9
9
  @import RevenueCat;
10
10
 
11
+ static NSString *const safeAreaInsetsDidChangeEvent = @"safeAreaInsetsDidChange";
12
+
11
13
  @interface RNPaywalls : RCTEventEmitter <RCTBridgeModule>
12
14
 
13
15
  @end
package/ios/RNPaywalls.m CHANGED
@@ -45,7 +45,7 @@ RCT_EXPORT_MODULE();
45
45
  // MARK: -
46
46
 
47
47
  - (NSArray<NSString *> *)supportedEvents {
48
- return @[];
48
+ return @[safeAreaInsetsDidChangeEvent];
49
49
  }
50
50
 
51
51
  - (dispatch_queue_t)methodQueue {
@@ -58,24 +58,63 @@ RCT_EXPORT_MODULE();
58
58
 
59
59
  // MARK: -
60
60
 
61
- RCT_EXPORT_METHOD(presentPaywall) {
61
+ RCT_EXPORT_METHOD(presentPaywall:(NSDictionary *)options
62
+ withResolve:(RCTPromiseResolveBlock)resolve
63
+ reject:(RCTPromiseRejectBlock)reject) {
62
64
  if (@available(iOS 15.0, *)) {
63
- [self.paywalls presentPaywall];
65
+ // TODO wire offeringIdentifier
66
+ NSString *offeringIdentifier = options[@"offeringIdentifier"];
67
+ NSNumber *displayCloseButton = options[@"displayCloseButton"];
68
+
69
+ if (displayCloseButton == nil) {
70
+ [self.paywallProxy presentPaywallWithPaywallResultHandler:^(NSString *result) {
71
+ resolve(result);
72
+ }];
73
+ return;
74
+ }
75
+ [self.paywalls presentPaywallWithDisplayCloseButton:displayCloseButton.boolValue
76
+ paywallResultHandler:^(NSString *result) {
77
+ resolve(result);
78
+ }];
64
79
  } else {
65
- [self logPaywallsUnsupportedError];
80
+ [self rejectPaywallsUnsupportedError:reject];
66
81
  }
67
82
  }
68
83
 
69
- RCT_EXPORT_METHOD(presentPaywallIfNeeded:(NSString *)requiredEntitlementIdentifier) {
84
+ RCT_EXPORT_METHOD(presentPaywallIfNeeded:(NSDictionary *)options
85
+ withResolve:(RCTPromiseResolveBlock)resolve
86
+ reject:(RCTPromiseRejectBlock)reject) {
70
87
  if (@available(iOS 15.0, *)) {
71
- [self.paywalls presentPaywallIfNeededWithRequiredEntitlementIdentifier:requiredEntitlementIdentifier];
88
+ NSString *requiredEntitlementIdentifier = options[@"requiredEntitlementIdentifier"];
89
+ // TODO wire offeringIdentifier
90
+ NSString *offeringIdentifier = options[@"offeringIdentifier"];
91
+ NSNumber *displayCloseButton = options[@"displayCloseButton"];
92
+ if (displayCloseButton == nil) {
93
+ [self.paywalls presentPaywallIfNeededWithRequiredEntitlementIdentifier:requiredEntitlementIdentifier
94
+ paywallResultHandler:^(NSString *result) {
95
+ resolve(result);
96
+ }];
97
+ return;
98
+ }
99
+
100
+ [self.paywalls presentPaywallIfNeededWithRequiredEntitlementIdentifier:requiredEntitlementIdentifier
101
+ displayCloseButton:displayCloseButton.boolValue
102
+ paywallResultHandler:^(NSString *result) {
103
+ resolve(result);
104
+ }];
72
105
  } else {
73
- [self logPaywallsUnsupportedError];
106
+ [self rejectPaywallsUnsupportedError:reject];
74
107
  }
75
108
  }
76
109
 
77
- - (void)logPaywallsUnsupportedError {
110
+ - (void)rejectPaywallsUnsupportedError:(RCTPromiseRejectBlock)reject {
78
111
  NSLog(@"Error: attempted to present paywalls on unsupported iOS version.");
112
+ reject(@"PaywallsUnsupportedCode", @"Paywalls are not supported prior to iOS 15.", nil);
113
+ }
114
+
115
+ + (BOOL)requiresMainQueueSetup
116
+ {
117
+ return YES;
79
118
  }
80
119
 
81
120
  @end
@@ -0,0 +1,15 @@
1
+ //
2
+ // UIView+Extensions.h
3
+ // Pods
4
+ //
5
+ // Created by NachoSoto on 29/12/23.
6
+ // Copyright © 2023 Facebook. All rights reserved.
7
+ //
8
+
9
+ @import UIKit;
10
+
11
+ @interface UIView (ParentViewController)
12
+
13
+ - (UIViewController *)parentViewController;
14
+
15
+ @end
@@ -0,0 +1,23 @@
1
+ //
2
+ // UIView+Extensions.m
3
+ // RNPaywalls
4
+ //
5
+ // Created by Nacho Soto on 29/12/23.
6
+ //
7
+
8
+ #import "UIView+Extensions.h"
9
+
10
+ @implementation UIView (ParentViewController)
11
+
12
+ - (UIViewController *)parentViewController {
13
+ UIResponder *responder = self;
14
+ while (responder) {
15
+ responder = responder.nextResponder;
16
+ if ([responder isKindOfClass:[UIViewController class]]) {
17
+ return (UIViewController *)responder;
18
+ }
19
+ }
20
+ return nil;
21
+ }
22
+
23
+ @end
@@ -3,16 +3,84 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.presentPaywall = presentPaywall;
7
- exports.presentPaywallIfNeeded = presentPaywallIfNeeded;
6
+ Object.defineProperty(exports, "PAYWALL_RESULT", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _purchasesTypescriptInternal.PAYWALL_RESULT;
10
+ }
11
+ });
12
+ exports.default = void 0;
8
13
  var _reactNative = require("react-native");
14
+ var _purchasesTypescriptInternal = require("@revenuecat/purchases-typescript-internal");
15
+ var _react = _interopRequireWildcard(require("react"));
16
+ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
17
+ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
18
+ function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
19
+ const LINKING_ERROR = `The package 'react-native-purchases-view' doesn't seem to be linked. Make sure: \n\n` + _reactNative.Platform.select({
20
+ ios: "- You have run 'pod install'\n",
21
+ default: ''
22
+ }) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo Go\n';
9
23
  const RNPaywalls = _reactNative.NativeModules.RNPaywalls;
10
- function presentPaywall() {
11
- // TODO: check iOS/Android version
12
- RNPaywalls.presentPaywall();
13
- }
14
- function presentPaywallIfNeeded(requiredEntitlementIdentifier) {
15
- // TODO: check iOS/Android version
16
- RNPaywalls.presentPaywallIfNeeded(requiredEntitlementIdentifier);
24
+ const eventEmitter = new _reactNative.NativeEventEmitter(RNPaywalls);
25
+ const InternalPaywall = _reactNative.UIManager.getViewManagerConfig('Paywall') != null ? (0, _reactNative.requireNativeComponent)('Paywall') : () => {
26
+ throw new Error(LINKING_ERROR);
27
+ };
28
+ const InternalPaywallFooterView = _reactNative.UIManager.getViewManagerConfig('Paywall') != null ? (0, _reactNative.requireNativeComponent)('RCPaywallFooterView') : () => {
29
+ throw new Error(LINKING_ERROR);
30
+ };
31
+ class RevenueCatUI {
32
+ /**
33
+ * The result of presenting a paywall. This will be the last situation the user experienced before the paywall closed.
34
+ * @readonly
35
+ * @enum {string}
36
+ */
37
+ static PAYWALL_RESULT = _purchasesTypescriptInternal.PAYWALL_RESULT;
38
+ static presentPaywall(params = {}) {
39
+ return RNPaywalls.presentPaywall(params);
40
+ }
41
+ static presentPaywallIfNeeded(params) {
42
+ return RNPaywalls.presentPaywallIfNeeded(params);
43
+ }
44
+ static Paywall = props => /*#__PURE__*/_react.default.createElement(InternalPaywall, _extends({}, props, {
45
+ style: [{
46
+ flex: 1
47
+ }, props.style]
48
+ }));
49
+ static PaywallFooterContainerView = ({
50
+ style,
51
+ children
52
+ }) => {
53
+ // We use 20 as the default paddingBottom because that's the corner radius in the Android native SDK.
54
+ // We also listen to safeAreaInsetsDidChange which is only sent from iOS and which is triggered when the
55
+ // safe area insets change. Not adding this extra padding on iOS will cause the content of the scrollview
56
+ // to be hidden behind the rounded corners of the paywall.
57
+ const [paddingBottom, setPaddingBottom] = (0, _react.useState)(20);
58
+ (0, _react.useEffect)(() => {
59
+ const handleSafeAreaInsetsChange = ({
60
+ bottom
61
+ }) => {
62
+ setPaddingBottom(20 + bottom);
63
+ };
64
+ const subscription = eventEmitter.addListener('safeAreaInsetsDidChange', handleSafeAreaInsetsChange);
65
+ return () => {
66
+ subscription.remove();
67
+ };
68
+ }, []);
69
+ return /*#__PURE__*/_react.default.createElement(_reactNative.View, {
70
+ style: [{
71
+ flex: 1
72
+ }, style]
73
+ }, /*#__PURE__*/_react.default.createElement(_reactNative.ScrollView, {
74
+ contentContainerStyle: {
75
+ flexGrow: 1,
76
+ paddingBottom
77
+ }
78
+ }, children), /*#__PURE__*/_react.default.createElement(InternalPaywallFooterView, {
79
+ style: {
80
+ marginTop: -20
81
+ }
82
+ }));
83
+ };
17
84
  }
85
+ exports.default = RevenueCatUI;
18
86
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["_reactNative","require","RNPaywalls","NativeModules","presentPaywall","presentPaywallIfNeeded","requiredEntitlementIdentifier"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAEA,MAAMC,UAAU,GAAGC,0BAAa,CAACD,UAAU;AAEpC,SAASE,cAAcA,CAAA,EAAG;EAC/B;EACAF,UAAU,CAACE,cAAc,CAAC,CAAC;AAC7B;AAEO,SAASC,sBAAsBA,CAACC,6BAAqC,EAAE;EAC5E;EACAJ,UAAU,CAACG,sBAAsB,CAACC,6BAA6B,CAAC;AAClE"}
1
+ {"version":3,"names":["_reactNative","require","_purchasesTypescriptInternal","_react","_interopRequireWildcard","_getRequireWildcardCache","e","WeakMap","r","t","__esModule","default","has","get","n","__proto__","a","Object","defineProperty","getOwnPropertyDescriptor","u","prototype","hasOwnProperty","call","i","set","_extends","assign","bind","target","arguments","length","source","key","apply","LINKING_ERROR","Platform","select","ios","RNPaywalls","NativeModules","eventEmitter","NativeEventEmitter","InternalPaywall","UIManager","getViewManagerConfig","requireNativeComponent","Error","InternalPaywallFooterView","RevenueCatUI","PAYWALL_RESULT","presentPaywall","params","presentPaywallIfNeeded","Paywall","props","createElement","style","flex","PaywallFooterContainerView","children","paddingBottom","setPaddingBottom","useState","useEffect","handleSafeAreaInsetsChange","bottom","subscription","addListener","remove","View","ScrollView","contentContainerStyle","flexGrow","marginTop","exports"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"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"}
@@ -1,11 +1,72 @@
1
- import { NativeModules } from "react-native";
1
+ function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
2
+ import { NativeEventEmitter, NativeModules, Platform, requireNativeComponent, ScrollView, UIManager, View } from "react-native";
3
+ import { PAYWALL_RESULT } from "@revenuecat/purchases-typescript-internal";
4
+ import React, { useEffect, useState } from "react";
5
+ export { PAYWALL_RESULT } from "@revenuecat/purchases-typescript-internal";
6
+ const LINKING_ERROR = `The package 'react-native-purchases-view' doesn't seem to be linked. Make sure: \n\n` + Platform.select({
7
+ ios: "- You have run 'pod install'\n",
8
+ default: ''
9
+ }) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo Go\n';
2
10
  const RNPaywalls = NativeModules.RNPaywalls;
3
- export function presentPaywall() {
4
- // TODO: check iOS/Android version
5
- RNPaywalls.presentPaywall();
6
- }
7
- export function presentPaywallIfNeeded(requiredEntitlementIdentifier) {
8
- // TODO: check iOS/Android version
9
- RNPaywalls.presentPaywallIfNeeded(requiredEntitlementIdentifier);
11
+ const eventEmitter = new NativeEventEmitter(RNPaywalls);
12
+ const InternalPaywall = UIManager.getViewManagerConfig('Paywall') != null ? requireNativeComponent('Paywall') : () => {
13
+ throw new Error(LINKING_ERROR);
14
+ };
15
+ const InternalPaywallFooterView = UIManager.getViewManagerConfig('Paywall') != null ? requireNativeComponent('RCPaywallFooterView') : () => {
16
+ throw new Error(LINKING_ERROR);
17
+ };
18
+ export default class RevenueCatUI {
19
+ /**
20
+ * The result of presenting a paywall. This will be the last situation the user experienced before the paywall closed.
21
+ * @readonly
22
+ * @enum {string}
23
+ */
24
+ static PAYWALL_RESULT = PAYWALL_RESULT;
25
+ static presentPaywall(params = {}) {
26
+ return RNPaywalls.presentPaywall(params);
27
+ }
28
+ static presentPaywallIfNeeded(params) {
29
+ return RNPaywalls.presentPaywallIfNeeded(params);
30
+ }
31
+ static Paywall = props => /*#__PURE__*/React.createElement(InternalPaywall, _extends({}, props, {
32
+ style: [{
33
+ flex: 1
34
+ }, props.style]
35
+ }));
36
+ static PaywallFooterContainerView = ({
37
+ style,
38
+ children
39
+ }) => {
40
+ // We use 20 as the default paddingBottom because that's the corner radius in the Android native SDK.
41
+ // We also listen to safeAreaInsetsDidChange which is only sent from iOS and which is triggered when the
42
+ // safe area insets change. Not adding this extra padding on iOS will cause the content of the scrollview
43
+ // to be hidden behind the rounded corners of the paywall.
44
+ const [paddingBottom, setPaddingBottom] = useState(20);
45
+ useEffect(() => {
46
+ const handleSafeAreaInsetsChange = ({
47
+ bottom
48
+ }) => {
49
+ setPaddingBottom(20 + bottom);
50
+ };
51
+ const subscription = eventEmitter.addListener('safeAreaInsetsDidChange', handleSafeAreaInsetsChange);
52
+ return () => {
53
+ subscription.remove();
54
+ };
55
+ }, []);
56
+ return /*#__PURE__*/React.createElement(View, {
57
+ style: [{
58
+ flex: 1
59
+ }, style]
60
+ }, /*#__PURE__*/React.createElement(ScrollView, {
61
+ contentContainerStyle: {
62
+ flexGrow: 1,
63
+ paddingBottom
64
+ }
65
+ }, children), /*#__PURE__*/React.createElement(InternalPaywallFooterView, {
66
+ style: {
67
+ marginTop: -20
68
+ }
69
+ }));
70
+ };
10
71
  }
11
72
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["NativeModules","RNPaywalls","presentPaywall","presentPaywallIfNeeded","requiredEntitlementIdentifier"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"AAAA,SAASA,aAAa,QAAQ,cAAc;AAE5C,MAAMC,UAAU,GAAGD,aAAa,CAACC,UAAU;AAE3C,OAAO,SAASC,cAAcA,CAAA,EAAG;EAC/B;EACAD,UAAU,CAACC,cAAc,CAAC,CAAC;AAC7B;AAEA,OAAO,SAASC,sBAAsBA,CAACC,6BAAqC,EAAE;EAC5E;EACAH,UAAU,CAACE,sBAAsB,CAACC,6BAA6B,CAAC;AAClE"}
1
+ {"version":3,"names":["NativeEventEmitter","NativeModules","Platform","requireNativeComponent","ScrollView","UIManager","View","PAYWALL_RESULT","React","useEffect","useState","LINKING_ERROR","select","ios","default","RNPaywalls","eventEmitter","InternalPaywall","getViewManagerConfig","Error","InternalPaywallFooterView","RevenueCatUI","presentPaywall","params","presentPaywallIfNeeded","Paywall","props","createElement","_extends","style","flex","PaywallFooterContainerView","children","paddingBottom","setPaddingBottom","handleSafeAreaInsetsChange","bottom","subscription","addListener","remove","contentContainerStyle","flexGrow","marginTop"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";AAAA,SACEA,kBAAkB,EAClBC,aAAa,EACbC,QAAQ,EACRC,sBAAsB,EACtBC,UAAU,EAEVC,SAAS,EACTC,IAAI,QAEC,cAAc;AACrB,SAASC,cAAc,QAAQ,2CAA2C;AAC1E,OAAOC,KAAK,IAAoBC,SAAS,EAAEC,QAAQ,QAAQ,OAAO;AAElE,SAASH,cAAc,QAAQ,2CAA2C;AAE1E,MAAMI,aAAa,GAChB,sFAAqF,GACtFT,QAAQ,CAACU,MAAM,CAAC;EAACC,GAAG,EAAE,gCAAgC;EAAEC,OAAO,EAAE;AAAE,CAAC,CAAC,GACrE,sDAAsD,GACtD,+BAA+B;AAEjC,MAAMC,UAAU,GAAGd,aAAa,CAACc,UAAU;AAE3C,MAAMC,YAAY,GAAG,IAAIhB,kBAAkB,CAACe,UAAU,CAAC;AAOvD,MAAME,eAAe,GACnBZ,SAAS,CAACa,oBAAoB,CAAC,SAAS,CAAC,IAAI,IAAI,GAC7Cf,sBAAsB,CAAmB,SAAS,CAAC,GACnD,MAAM;EACN,MAAM,IAAIgB,KAAK,CAACR,aAAa,CAAC;AAChC,CAAC;AAEL,MAAMS,yBAAyB,GAAGf,SAAS,CAACa,oBAAoB,CAAC,SAAS,CAAC,IAAI,IAAI,GAC/Ef,sBAAsB,CAAmB,qBAAqB,CAAC,GAC/D,MAAM;EACN,MAAM,IAAIgB,KAAK,CAACR,aAAa,CAAC;AAChC,CAAC;AAgBH,eAAe,MAAMU,YAAY,CAAC;EAEhC;AACF;AACA;AACA;AACA;EACE,OAAcd,cAAc,GAAGA,cAAc;EAE7C,OAAce,cAAcA,CAACC,MAA4B,GAAG,CAAC,CAAC,EAA2B;IACvF,OAAOR,UAAU,CAACO,cAAc,CAACC,MAAM,CAAC;EAC1C;EAEA,OAAcC,sBAAsBA,CAACD,MAAoC,EAA2B;IAClG,OAAOR,UAAU,CAACS,sBAAsB,CAACD,MAAM,CAAC;EAClD;EAEA,OAAcE,OAAO,GAAgCC,KAAK,iBACxDlB,KAAA,CAAAmB,aAAA,CAACV,eAAe,EAAAW,QAAA,KAAKF,KAAK;IAAEG,KAAK,EAAE,CAAC;MAACC,IAAI,EAAE;IAAC,CAAC,EAAEJ,KAAK,CAACG,KAAK;EAAE,EAAC,CAC9D;EAED,OAAcE,0BAA0B,GAA+BA,CAAC;IAACF,KAAK;IAAEG;EAAQ,CAAC,KAAK;IAC5F;IACA;IACA;IACA;IACA,MAAM,CAACC,aAAa,EAAEC,gBAAgB,CAAC,GAAGxB,QAAQ,CAAC,EAAE,CAAC;IAEtDD,SAAS,CAAC,MAAM;MAKd,MAAM0B,0BAA0B,GAAGA,CAAC;QAACC;MAAwC,CAAC,KAAK;QACjFF,gBAAgB,CAAC,EAAE,GAAGE,MAAM,CAAC;MAC/B,CAAC;MAED,MAAMC,YAAY,GAAGrB,YAAY,CAACsB,WAAW,CAC3C,yBAAyB,EACzBH,0BACF,CAAC;MAED,OAAO,MAAM;QACXE,YAAY,CAACE,MAAM,CAAC,CAAC;MACvB,CAAC;IACH,CAAC,EAAE,EAAE,CAAC;IAEN,oBACE/B,KAAA,CAAAmB,aAAA,CAACrB,IAAI;MAACuB,KAAK,EAAE,CAAC;QAACC,IAAI,EAAE;MAAC,CAAC,EAAED,KAAK;IAAE,gBAC9BrB,KAAA,CAAAmB,aAAA,CAACvB,UAAU;MAACoC,qBAAqB,EAAE;QAACC,QAAQ,EAAE,CAAC;QAAER;MAAa;IAAE,GAC7DD,QACS,CAAC,eAEbxB,KAAA,CAAAmB,aAAA,CAACP,yBAAyB;MAACS,KAAK,EAAE;QAACa,SAAS,EAAE,CAAC;MAAE;IAAE,CAAC,CAChD,CAAC;EAEX,CAAC;AACH"}
@@ -1,3 +1,33 @@
1
- export declare function presentPaywall(): void;
2
- export declare function presentPaywallIfNeeded(requiredEntitlementIdentifier: String): void;
1
+ import { type StyleProp, type ViewStyle } from "react-native";
2
+ import { PAYWALL_RESULT } from "@revenuecat/purchases-typescript-internal";
3
+ import React, { type ReactNode } from "react";
4
+ export { PAYWALL_RESULT } from "@revenuecat/purchases-typescript-internal";
5
+ type PaywallViewProps = {
6
+ style?: StyleProp<ViewStyle>;
7
+ children?: ReactNode;
8
+ };
9
+ export interface PresentPaywallParams {
10
+ /**
11
+ * Whether to display the close button or not.
12
+ */
13
+ displayCloseButton?: boolean;
14
+ }
15
+ export type PresentPaywallIfNeededParams = PresentPaywallParams & {
16
+ /**
17
+ * The paywall will only be presented if this entitlement is not active.
18
+ */
19
+ requiredEntitlementIdentifier: string;
20
+ };
21
+ export default class RevenueCatUI {
22
+ /**
23
+ * The result of presenting a paywall. This will be the last situation the user experienced before the paywall closed.
24
+ * @readonly
25
+ * @enum {string}
26
+ */
27
+ static PAYWALL_RESULT: typeof PAYWALL_RESULT;
28
+ static presentPaywall(params?: PresentPaywallParams): Promise<PAYWALL_RESULT>;
29
+ static presentPaywallIfNeeded(params: PresentPaywallIfNeededParams): Promise<PAYWALL_RESULT>;
30
+ static Paywall: React.FC<PaywallViewProps>;
31
+ static PaywallFooterContainerView: React.FC<PaywallViewProps>;
32
+ }
3
33
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAIA,wBAAgB,cAAc,SAG7B;AAED,wBAAgB,sBAAsB,CAAC,6BAA6B,EAAE,MAAM,QAG3E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,SAAS,EAGd,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,cAAc,EAAE,MAAM,2CAA2C,CAAC;AAC3E,OAAO,KAAK,EAAE,EAAE,KAAK,SAAS,EAAuB,MAAM,OAAO,CAAC;AAEnE,OAAO,EAAE,cAAc,EAAE,MAAM,2CAA2C,CAAC;AAY3E,KAAK,gBAAgB,GAAG;IACtB,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB,CAAC;AAeF,MAAM,WAAW,oBAAoB;IACnC;;OAEG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,MAAM,MAAM,4BAA4B,GAAG,oBAAoB,GAAG;IAChE;;OAEG;IACH,6BAA6B,EAAE,MAAM,CAAC;CACvC,CAAA;AAED,MAAM,CAAC,OAAO,OAAO,YAAY;IAE/B;;;;OAIG;IACH,OAAc,cAAc,wBAAkB;WAEhC,cAAc,CAAC,MAAM,GAAE,oBAAyB,GAAG,OAAO,CAAC,cAAc,CAAC;WAI1E,sBAAsB,CAAC,MAAM,EAAE,4BAA4B,GAAG,OAAO,CAAC,cAAc,CAAC;IAInG,OAAc,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAE/C;IAEF,OAAc,0BAA0B,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAmClE;CACH"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "react-native-purchases-ui",
3
3
  "title": "React Native Purchases UI",
4
- "version": "7.15.0-rc.1",
4
+ "version": "7.16.0",
5
5
  "description": "React Native in-app purchases and subscriptions made easy. Supports iOS and Android.",
6
6
  "main": "lib/commonjs/index",
7
7
  "module": "lib/module/index",
@@ -51,8 +51,8 @@
51
51
  "readmeFilename": "README.md",
52
52
  "devDependencies": {
53
53
  "@types/jest": "^28.1.2",
54
- "@types/react": "~17.0.21",
55
- "@types/react-native": "0.70.0",
54
+ "@types/react": "~18.2.0",
55
+ "@types/react-dom": "~18.2.0",
56
56
  "jest": "^28.1.1",
57
57
  "jest-react-native": "^18.0.0",
58
58
  "pod-install": "^0.1.0",
@@ -67,7 +67,9 @@
67
67
  "typescript": "^5.0.2"
68
68
  },
69
69
  "resolutions": {
70
- "@types/react": "17.0.21"
70
+ "@types/react": "18.2.0",
71
+ "@types/react-native": "0.73.1",
72
+ "@types/react-dom": "18.2.0"
71
73
  },
72
74
  "peerDependencies": {
73
75
  "react": "*",
@@ -109,6 +111,7 @@
109
111
  ]
110
112
  },
111
113
  "dependencies": {
112
- "react-native-purchases": "7.15.0-rc.1"
114
+ "@revenuecat/purchases-typescript-internal": "8.10.1",
115
+ "react-native-purchases": "7.16.0"
113
116
  }
114
117
  }
package/src/index.tsx CHANGED
@@ -1,13 +1,116 @@
1
- import { NativeModules } from "react-native";
1
+ import {
2
+ NativeEventEmitter,
3
+ NativeModules,
4
+ Platform,
5
+ requireNativeComponent,
6
+ ScrollView,
7
+ type StyleProp,
8
+ UIManager,
9
+ View,
10
+ type ViewStyle,
11
+ } from "react-native";
12
+ import { PAYWALL_RESULT } from "@revenuecat/purchases-typescript-internal";
13
+ import React, { type ReactNode, useEffect, useState } from "react";
14
+
15
+ export { PAYWALL_RESULT } from "@revenuecat/purchases-typescript-internal";
16
+
17
+ const LINKING_ERROR =
18
+ `The package 'react-native-purchases-view' doesn't seem to be linked. Make sure: \n\n` +
19
+ Platform.select({ios: "- You have run 'pod install'\n", default: ''}) +
20
+ '- You rebuilt the app after installing the package\n' +
21
+ '- You are not using Expo Go\n';
2
22
 
3
23
  const RNPaywalls = NativeModules.RNPaywalls;
4
24
 
5
- export function presentPaywall() {
6
- // TODO: check iOS/Android version
7
- RNPaywalls.presentPaywall();
25
+ const eventEmitter = new NativeEventEmitter(RNPaywalls);
26
+
27
+ type PaywallViewProps = {
28
+ style?: StyleProp<ViewStyle>;
29
+ children?: ReactNode;
30
+ };
31
+
32
+ const InternalPaywall =
33
+ UIManager.getViewManagerConfig('Paywall') != null
34
+ ? requireNativeComponent<PaywallViewProps>('Paywall')
35
+ : () => {
36
+ throw new Error(LINKING_ERROR);
37
+ };
38
+
39
+ const InternalPaywallFooterView = UIManager.getViewManagerConfig('Paywall') != null
40
+ ? requireNativeComponent<PaywallViewProps>('RCPaywallFooterView')
41
+ : () => {
42
+ throw new Error(LINKING_ERROR);
43
+ };
44
+
45
+ export interface PresentPaywallParams {
46
+ /**
47
+ * Whether to display the close button or not.
48
+ */
49
+ displayCloseButton?: boolean;
50
+ }
51
+
52
+ export type PresentPaywallIfNeededParams = PresentPaywallParams & {
53
+ /**
54
+ * The paywall will only be presented if this entitlement is not active.
55
+ */
56
+ requiredEntitlementIdentifier: string;
8
57
  }
9
58
 
10
- export function presentPaywallIfNeeded(requiredEntitlementIdentifier: String) {
11
- // TODO: check iOS/Android version
12
- RNPaywalls.presentPaywallIfNeeded(requiredEntitlementIdentifier);
59
+ export default class RevenueCatUI {
60
+
61
+ /**
62
+ * The result of presenting a paywall. This will be the last situation the user experienced before the paywall closed.
63
+ * @readonly
64
+ * @enum {string}
65
+ */
66
+ public static PAYWALL_RESULT = PAYWALL_RESULT;
67
+
68
+ public static presentPaywall(params: PresentPaywallParams = {}): Promise<PAYWALL_RESULT> {
69
+ return RNPaywalls.presentPaywall(params);
70
+ }
71
+
72
+ public static presentPaywallIfNeeded(params: PresentPaywallIfNeededParams): Promise<PAYWALL_RESULT> {
73
+ return RNPaywalls.presentPaywallIfNeeded(params);
74
+ }
75
+
76
+ public static Paywall: React.FC<PaywallViewProps> = (props) => (
77
+ <InternalPaywall {...props} style={[{flex: 1}, props.style]}/>
78
+ );
79
+
80
+ public static PaywallFooterContainerView: React.FC<PaywallViewProps> = ({style, children}) => {
81
+ // We use 20 as the default paddingBottom because that's the corner radius in the Android native SDK.
82
+ // We also listen to safeAreaInsetsDidChange which is only sent from iOS and which is triggered when the
83
+ // safe area insets change. Not adding this extra padding on iOS will cause the content of the scrollview
84
+ // to be hidden behind the rounded corners of the paywall.
85
+ const [paddingBottom, setPaddingBottom] = useState(20);
86
+
87
+ useEffect(() => {
88
+ interface HandleSafeAreaInsetsChangeParams {
89
+ bottom: number;
90
+ }
91
+
92
+ const handleSafeAreaInsetsChange = ({bottom}: HandleSafeAreaInsetsChangeParams) => {
93
+ setPaddingBottom(20 + bottom);
94
+ };
95
+
96
+ const subscription = eventEmitter.addListener(
97
+ 'safeAreaInsetsDidChange',
98
+ handleSafeAreaInsetsChange
99
+ );
100
+
101
+ return () => {
102
+ subscription.remove();
103
+ };
104
+ }, []);
105
+
106
+ return (
107
+ <View style={[{flex: 1}, style]}>
108
+ <ScrollView contentContainerStyle={{flexGrow: 1, paddingBottom}}>
109
+ {children}
110
+ </ScrollView>
111
+ {/*Adding negative margin to the footer view to make it overlap with the extra padding of the scroll*/}
112
+ <InternalPaywallFooterView style={{marginTop: -20}}/>
113
+ </View>
114
+ );
115
+ };
13
116
  }
@@ -1,33 +0,0 @@
1
- package com.revenuecat.purchases.react.ui
2
-
3
- import android.app.PendingIntent.getActivity
4
- import android.content.Context
5
- import android.util.AttributeSet
6
- import android.widget.ImageView
7
- import androidx.compose.runtime.Composable
8
- import androidx.compose.runtime.getValue
9
- import androidx.compose.runtime.mutableStateOf
10
- import androidx.compose.runtime.setValue
11
- import androidx.compose.ui.platform.AbstractComposeView
12
- import com.facebook.react.ReactActivity
13
- import com.facebook.react.ReactActivityDelegate
14
- import com.facebook.react.uimanager.SimpleViewManager
15
- import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI
16
- import com.revenuecat.purchases.ui.revenuecatui.Paywall
17
- import com.revenuecat.purchases.ui.revenuecatui.PaywallOptions
18
-
19
- internal class Paywall @JvmOverloads constructor(
20
- context: Context,
21
- attrs: AttributeSet? = null,
22
- ) : AbstractComposeView(context, attrs) {
23
- @OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
24
- @Composable
25
- override fun Content() {
26
- Paywall(
27
- PaywallOptions.Builder(
28
- dismissRequest = {}
29
- )
30
- .build()
31
- )
32
- }
33
- }
@@ -1,18 +0,0 @@
1
- package com.revenuecat.purchases.react.ui
2
-
3
- import com.facebook.react.uimanager.SimpleViewManager
4
- import com.facebook.react.uimanager.ThemedReactContext
5
-
6
- internal class RNPaywallManager : SimpleViewManager<Paywall>() {
7
- companion object {
8
- const val REACT_CLASS = "RNPaywall"
9
- }
10
-
11
- override fun getName(): String {
12
- return REACT_CLASS
13
- }
14
-
15
- override fun createViewInstance(themedReactContext: ThemedReactContext): Paywall {
16
- return Paywall(themedReactContext)
17
- }
18
- }