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

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
- }