react-native-purchases-ui 7.15.0-rc.1 → 7.15.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.10.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.15.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.10.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,12 @@
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.revenuecat.purchases.hybridcommon.ui.PaywallResultListener
7
10
  import com.revenuecat.purchases.hybridcommon.ui.presentPaywallFromFragment
8
11
 
9
12
  internal class RNPaywallsModule(reactContext: ReactApplicationContext) :
@@ -16,7 +19,10 @@ internal class RNPaywallsModule(reactContext: ReactApplicationContext) :
16
19
  get() {
17
20
  return when (val currentActivity = currentActivity) {
18
21
  is FragmentActivity -> currentActivity
19
- else -> null
22
+ else -> {
23
+ Log.e(NAME, "RevenueCat paywalls require application to use a FragmentActivity")
24
+ null
25
+ }
20
26
  }
21
27
  }
22
28
 
@@ -25,20 +31,26 @@ internal class RNPaywallsModule(reactContext: ReactApplicationContext) :
25
31
  }
26
32
 
27
33
  @ReactMethod
28
- fun presentPaywall() {
29
- presentPaywall(null)
34
+ fun presentPaywall(promise: Promise) {
35
+ presentPaywall(null, promise)
30
36
  }
31
37
 
32
38
  @ReactMethod
33
- fun presentPaywallIfNeeded(requiredEntitlementIdentifier: String?) {
34
- presentPaywall(requiredEntitlementIdentifier)
39
+ fun presentPaywallIfNeeded(requiredEntitlementIdentifier: String?, promise: Promise) {
40
+ presentPaywall(requiredEntitlementIdentifier, promise)
35
41
  }
36
42
 
37
- private fun presentPaywall(requiredEntitlementIdentifier: String?) {
38
- val fragment = currentActivityFragment
39
- ?: // TODO: log
40
- return
43
+ private fun presentPaywall(requiredEntitlementIdentifier: String?, promise: Promise) {
44
+ val fragment = currentActivityFragment ?: return
41
45
 
42
- presentPaywallFromFragment(fragment, requiredEntitlementIdentifier)
46
+ presentPaywallFromFragment(
47
+ fragment,
48
+ requiredEntitlementIdentifier,
49
+ paywallResultListener = object : PaywallResultListener {
50
+ override fun onPaywallResult(paywallResult: String) {
51
+ promise.resolve(paywallResult)
52
+ }
53
+ }
54
+ )
43
55
  }
44
56
  }
@@ -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,40 @@ RCT_EXPORT_MODULE();
58
58
 
59
59
  // MARK: -
60
60
 
61
- RCT_EXPORT_METHOD(presentPaywall) {
61
+ RCT_REMAP_METHOD(presentPaywall,
62
+ presentPaywallWithResolve:(RCTPromiseResolveBlock)resolve
63
+ reject:(RCTPromiseRejectBlock)reject) {
62
64
  if (@available(iOS 15.0, *)) {
63
- [self.paywalls presentPaywall];
65
+ [self.paywalls presentPaywallWithPaywallResultHandler:^(NSString *result) {
66
+ resolve(result);
67
+ }];
64
68
  } else {
65
- [self logPaywallsUnsupportedError];
69
+ [self rejectPaywallsUnsupportedError:reject];
66
70
  }
67
71
  }
68
72
 
69
- RCT_EXPORT_METHOD(presentPaywallIfNeeded:(NSString *)requiredEntitlementIdentifier) {
73
+ RCT_REMAP_METHOD(presentPaywallIfNeeded,
74
+ presentPaywallIfNeeded:(NSString *)requiredEntitlementIdentifier
75
+ withResolve:(RCTPromiseResolveBlock)resolve
76
+ reject:(RCTPromiseRejectBlock)reject) {
70
77
  if (@available(iOS 15.0, *)) {
71
- [self.paywalls presentPaywallIfNeededWithRequiredEntitlementIdentifier:requiredEntitlementIdentifier];
78
+ [self.paywalls presentPaywallIfNeededWithRequiredEntitlementIdentifier:requiredEntitlementIdentifier
79
+ paywallResultHandler:^(NSString *result) {
80
+ resolve(result);
81
+ }];
72
82
  } else {
73
- [self logPaywallsUnsupportedError];
83
+ [self rejectPaywallsUnsupportedError:reject];
74
84
  }
75
85
  }
76
86
 
77
- - (void)logPaywallsUnsupportedError {
87
+ - (void)rejectPaywallsUnsupportedError:(RCTPromiseRejectBlock)reject {
78
88
  NSLog(@"Error: attempted to present paywalls on unsupported iOS version.");
89
+ reject(@"PaywallsUnsupportedCode", @"Paywalls are not supported prior to iOS 15.", nil);
90
+ }
91
+
92
+ + (BOOL)requiresMainQueueSetup
93
+ {
94
+ return YES;
79
95
  }
80
96
 
81
97
  @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,86 @@
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({} = {}) {
39
+ return RNPaywalls.presentPaywall();
40
+ }
41
+ static presentPaywallIfNeeded({
42
+ requiredEntitlementIdentifier
43
+ }) {
44
+ return RNPaywalls.presentPaywallIfNeeded(requiredEntitlementIdentifier);
45
+ }
46
+ static Paywall = props => /*#__PURE__*/_react.default.createElement(InternalPaywall, _extends({}, props, {
47
+ style: [{
48
+ flex: 1
49
+ }, props.style]
50
+ }));
51
+ static PaywallFooterContainerView = ({
52
+ style,
53
+ children
54
+ }) => {
55
+ // We use 20 as the default paddingBottom because that's the corner radius in the Android native SDK.
56
+ // We also listen to safeAreaInsetsDidChange which is only sent from iOS and which is triggered when the
57
+ // safe area insets change. Not adding this extra padding on iOS will cause the content of the scrollview
58
+ // to be hidden behind the rounded corners of the paywall.
59
+ const [paddingBottom, setPaddingBottom] = (0, _react.useState)(20);
60
+ (0, _react.useEffect)(() => {
61
+ const handleSafeAreaInsetsChange = ({
62
+ bottom
63
+ }) => {
64
+ setPaddingBottom(20 + bottom);
65
+ };
66
+ const subscription = eventEmitter.addListener('safeAreaInsetsDidChange', handleSafeAreaInsetsChange);
67
+ return () => {
68
+ subscription.remove();
69
+ };
70
+ }, []);
71
+ return /*#__PURE__*/_react.default.createElement(_reactNative.View, {
72
+ style: [{
73
+ flex: 1
74
+ }, style]
75
+ }, /*#__PURE__*/_react.default.createElement(_reactNative.ScrollView, {
76
+ contentContainerStyle: {
77
+ flexGrow: 1,
78
+ paddingBottom
79
+ }
80
+ }, children), /*#__PURE__*/_react.default.createElement(InternalPaywallFooterView, {
81
+ style: {
82
+ marginTop: -20
83
+ }
84
+ }));
85
+ };
17
86
  }
87
+ exports.default = RevenueCatUI;
18
88
  //# 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","presentPaywallIfNeeded","requiredEntitlementIdentifier","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,74 @@
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({} = {}) {
26
+ return RNPaywalls.presentPaywall();
27
+ }
28
+ static presentPaywallIfNeeded({
29
+ requiredEntitlementIdentifier
30
+ }) {
31
+ return RNPaywalls.presentPaywallIfNeeded(requiredEntitlementIdentifier);
32
+ }
33
+ static Paywall = props => /*#__PURE__*/React.createElement(InternalPaywall, _extends({}, props, {
34
+ style: [{
35
+ flex: 1
36
+ }, props.style]
37
+ }));
38
+ static PaywallFooterContainerView = ({
39
+ style,
40
+ children
41
+ }) => {
42
+ // We use 20 as the default paddingBottom because that's the corner radius in the Android native SDK.
43
+ // We also listen to safeAreaInsetsDidChange which is only sent from iOS and which is triggered when the
44
+ // safe area insets change. Not adding this extra padding on iOS will cause the content of the scrollview
45
+ // to be hidden behind the rounded corners of the paywall.
46
+ const [paddingBottom, setPaddingBottom] = useState(20);
47
+ useEffect(() => {
48
+ const handleSafeAreaInsetsChange = ({
49
+ bottom
50
+ }) => {
51
+ setPaddingBottom(20 + bottom);
52
+ };
53
+ const subscription = eventEmitter.addListener('safeAreaInsetsDidChange', handleSafeAreaInsetsChange);
54
+ return () => {
55
+ subscription.remove();
56
+ };
57
+ }, []);
58
+ return /*#__PURE__*/React.createElement(View, {
59
+ style: [{
60
+ flex: 1
61
+ }, style]
62
+ }, /*#__PURE__*/React.createElement(ScrollView, {
63
+ contentContainerStyle: {
64
+ flexGrow: 1,
65
+ paddingBottom
66
+ }
67
+ }, children), /*#__PURE__*/React.createElement(InternalPaywallFooterView, {
68
+ style: {
69
+ marginTop: -20
70
+ }
71
+ }));
72
+ };
10
73
  }
11
74
  //# 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","presentPaywallIfNeeded","requiredEntitlementIdentifier","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;AAYH,eAAe,MAAMU,YAAY,CAAC;EAEhC;AACF;AACA;AACA;AACA;EACE,OAAcd,cAAc,GAAGA,cAAc;EAE7C,OAAce,cAAcA,CAAC,CAAuB,CAAC,GAAG,CAAC,CAAC,EAA2B;IACnF,OAAOP,UAAU,CAACO,cAAc,CAAC,CAAC;EACpC;EAEA,OAAcC,sBAAsBA,CAAC;IAACC;EAA2D,CAAC,EAA2B;IAC3H,OAAOT,UAAU,CAACQ,sBAAsB,CAACC,6BAA6B,CAAC;EACzE;EAEA,OAAcC,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;QAAEC;MAAyC,CAAC,KAAK;QACnFF,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,29 @@
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
+ export type PresentPaywallIfNeededParams = PresentPaywallParams & {
12
+ /**
13
+ * The paywall will only be presented if this entitlement is not active.
14
+ */
15
+ requiredEntitlementIdentifier: string;
16
+ };
17
+ export default class RevenueCatUI {
18
+ /**
19
+ * The result of presenting a paywall. This will be the last situation the user experienced before the paywall closed.
20
+ * @readonly
21
+ * @enum {string}
22
+ */
23
+ static PAYWALL_RESULT: typeof PAYWALL_RESULT;
24
+ static presentPaywall({}?: PresentPaywallParams): Promise<PAYWALL_RESULT>;
25
+ static presentPaywallIfNeeded({ requiredEntitlementIdentifier }: PresentPaywallIfNeededParams): Promise<PAYWALL_RESULT>;
26
+ static Paywall: React.FC<PaywallViewProps>;
27
+ static PaywallFooterContainerView: React.FC<PaywallViewProps>;
28
+ }
3
29
  //# 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;CACpC;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,EAAE,GAAE,oBAAyB,GAAG,OAAO,CAAC,cAAc,CAAC;WAItE,sBAAsB,CAAC,EAAC,6BAA6B,EAAC,EAAE,4BAA4B,GAAG,OAAO,CAAC,cAAc,CAAC;IAI5H,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.15.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.15.0"
113
116
  }
114
117
  }
package/src/index.tsx CHANGED
@@ -1,13 +1,112 @@
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
+
48
+ export type PresentPaywallIfNeededParams = PresentPaywallParams & {
49
+ /**
50
+ * The paywall will only be presented if this entitlement is not active.
51
+ */
52
+ requiredEntitlementIdentifier: string;
8
53
  }
9
54
 
10
- export function presentPaywallIfNeeded(requiredEntitlementIdentifier: String) {
11
- // TODO: check iOS/Android version
12
- RNPaywalls.presentPaywallIfNeeded(requiredEntitlementIdentifier);
55
+ export default class RevenueCatUI {
56
+
57
+ /**
58
+ * The result of presenting a paywall. This will be the last situation the user experienced before the paywall closed.
59
+ * @readonly
60
+ * @enum {string}
61
+ */
62
+ public static PAYWALL_RESULT = PAYWALL_RESULT;
63
+
64
+ public static presentPaywall({}: PresentPaywallParams = {}): Promise<PAYWALL_RESULT> {
65
+ return RNPaywalls.presentPaywall();
66
+ }
67
+
68
+ public static presentPaywallIfNeeded({requiredEntitlementIdentifier}: PresentPaywallIfNeededParams): Promise<PAYWALL_RESULT> {
69
+ return RNPaywalls.presentPaywallIfNeeded(requiredEntitlementIdentifier);
70
+ }
71
+
72
+ public static Paywall: React.FC<PaywallViewProps> = (props) => (
73
+ <InternalPaywall {...props} style={[{flex: 1}, props.style]}/>
74
+ );
75
+
76
+ public static PaywallFooterContainerView: React.FC<PaywallViewProps> = ({style, children}) => {
77
+ // We use 20 as the default paddingBottom because that's the corner radius in the Android native SDK.
78
+ // We also listen to safeAreaInsetsDidChange which is only sent from iOS and which is triggered when the
79
+ // safe area insets change. Not adding this extra padding on iOS will cause the content of the scrollview
80
+ // to be hidden behind the rounded corners of the paywall.
81
+ const [paddingBottom, setPaddingBottom] = useState(20);
82
+
83
+ useEffect(() => {
84
+ interface HandleSafeAreaInsetsChangeParams {
85
+ bottom: number;
86
+ }
87
+
88
+ const handleSafeAreaInsetsChange = ({ bottom }: HandleSafeAreaInsetsChangeParams) => {
89
+ setPaddingBottom(20 + bottom);
90
+ };
91
+
92
+ const subscription = eventEmitter.addListener(
93
+ 'safeAreaInsetsDidChange',
94
+ handleSafeAreaInsetsChange
95
+ );
96
+
97
+ return () => {
98
+ subscription.remove();
99
+ };
100
+ }, []);
101
+
102
+ return (
103
+ <View style={[{flex: 1}, style]}>
104
+ <ScrollView contentContainerStyle={{flexGrow: 1, paddingBottom}}>
105
+ {children}
106
+ </ScrollView>
107
+ {/*Adding negative margin to the footer view to make it overlap with the extra padding of the scroll*/}
108
+ <InternalPaywallFooterView style={{marginTop: -20}}/>
109
+ </View>
110
+ );
111
+ };
13
112
  }
@@ -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
- }