react-native-purchases-ui 8.0.0-beta.1 → 8.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. package/RNPaywalls.podspec +2 -2
  2. package/android/build.gradle +2 -2
  3. package/android/src/main/java/com/revenuecat/purchases/react/ui/BasePaywallViewManager.kt +79 -58
  4. package/android/src/main/java/com/revenuecat/purchases/react/ui/FontAssetManager.kt +60 -16
  5. package/android/src/main/java/com/revenuecat/purchases/react/ui/{PaywallEvent.kt → PaywallEventName.kt} +6 -3
  6. package/android/src/main/java/com/revenuecat/purchases/react/ui/PaywallFooterViewManager.kt +20 -9
  7. package/android/src/main/java/com/revenuecat/purchases/react/ui/PaywallViewManager.kt +9 -3
  8. package/android/src/main/java/com/revenuecat/purchases/react/ui/RNPaywallsModule.kt +14 -2
  9. package/android/src/main/java/com/revenuecat/purchases/react/ui/ViewExtensions.kt +7 -0
  10. package/android/src/main/java/com/revenuecat/purchases/react/ui/events/OnDismissEvent.kt +13 -0
  11. package/android/src/main/java/com/revenuecat/purchases/react/ui/events/OnMeasureEvent.kt +17 -0
  12. package/android/src/main/java/com/revenuecat/purchases/react/ui/events/OnPurchaseCancelledEvent.kt +13 -0
  13. package/android/src/main/java/com/revenuecat/purchases/react/ui/events/OnPurchaseCompletedEvent.kt +18 -0
  14. package/android/src/main/java/com/revenuecat/purchases/react/ui/events/OnPurchaseErrorEvent.kt +14 -0
  15. package/android/src/main/java/com/revenuecat/purchases/react/ui/events/OnPurchaseStartedEvent.kt +16 -0
  16. package/android/src/main/java/com/revenuecat/purchases/react/ui/events/OnRestoreCompletedEvent.kt +14 -0
  17. package/android/src/main/java/com/revenuecat/purchases/react/ui/events/OnRestoreErrorEvent.kt +14 -0
  18. package/android/src/main/java/com/revenuecat/purchases/react/ui/events/OnRestoreStartedEvent.kt +13 -0
  19. package/android/src/main/java/com/revenuecat/purchases/react/ui/events/PaywallEvent.kt +34 -0
  20. package/ios/PaywallViewWrapper.m +24 -1
  21. package/ios/RNPaywalls.m +21 -18
  22. package/lib/commonjs/index.js +19 -9
  23. package/lib/commonjs/index.js.map +1 -1
  24. package/lib/module/index.js +18 -8
  25. package/lib/module/index.js.map +1 -1
  26. package/lib/typescript/src/index.d.ts +14 -2
  27. package/lib/typescript/src/index.d.ts.map +1 -1
  28. package/package.json +13 -12
  29. package/src/index.tsx +39 -7
@@ -10,13 +10,13 @@ Pod::Spec.new do |spec|
10
10
  spec.authors = package['author']
11
11
  spec.homepage = "https://github.com/RevenueCat/react-native-purchases"
12
12
  spec.license = package['license']
13
- spec.platform = :ios, "13.0"
13
+ spec.platform = :ios, "11.0"
14
14
 
15
15
  spec.source = { :git => "https://github.com/RevenueCat/react-native-purchases.git" }
16
16
  spec.source_files = "ios/**/*.{h,m,swift}"
17
17
  spec.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES' }
18
18
 
19
19
  spec.dependency "React-Core"
20
- spec.dependency "PurchasesHybridCommonUI", "10.0.0-beta.1"
20
+ spec.dependency "PurchasesHybridCommonUI", '13.0.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 '8.0.0-beta.1'
62
+ versionName '8.0.1'
63
63
  }
64
64
 
65
65
  buildTypes {
@@ -91,7 +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:9.8.0'
94
+ implementation 'com.revenuecat.purchases:purchases-hybrid-common-ui:13.0.1'
95
95
  implementation 'androidx.compose.ui:ui-android:1.5.4'
96
96
  implementation "androidx.appcompat:appcompat:1.6.1"
97
97
  }
@@ -1,14 +1,24 @@
1
1
  package com.revenuecat.purchases.react.ui
2
2
 
3
3
  import android.view.View
4
+ import com.facebook.react.bridge.ReactContext
4
5
  import com.facebook.react.bridge.ReadableMap
5
6
  import com.facebook.react.bridge.WritableNativeMap
6
7
  import com.facebook.react.common.MapBuilder
7
8
  import com.facebook.react.uimanager.SimpleViewManager
8
9
  import com.facebook.react.uimanager.ThemedReactContext
10
+ import com.facebook.react.uimanager.UIManagerHelper
9
11
  import com.facebook.react.uimanager.annotations.ReactProp
10
- import com.facebook.react.uimanager.events.RCTEventEmitter
12
+ import com.facebook.react.uimanager.events.Event
11
13
  import com.revenuecat.purchases.hybridcommon.ui.PaywallListenerWrapper
14
+ import com.revenuecat.purchases.react.ui.events.OnDismissEvent
15
+ import com.revenuecat.purchases.react.ui.events.OnPurchaseCancelledEvent
16
+ import com.revenuecat.purchases.react.ui.events.OnPurchaseCompletedEvent
17
+ import com.revenuecat.purchases.react.ui.events.OnPurchaseErrorEvent
18
+ import com.revenuecat.purchases.react.ui.events.OnPurchaseStartedEvent
19
+ import com.revenuecat.purchases.react.ui.events.OnRestoreCompletedEvent
20
+ import com.revenuecat.purchases.react.ui.events.OnRestoreErrorEvent
21
+ import com.revenuecat.purchases.react.ui.events.OnRestoreStartedEvent
12
22
  import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI
13
23
  import com.revenuecat.purchases.ui.revenuecatui.fonts.CustomFontProvider
14
24
 
@@ -23,16 +33,19 @@ internal abstract class BasePaywallViewManager<T : View> : SimpleViewManager<T>(
23
33
 
24
34
  abstract fun setOfferingId(view: T, identifier: String)
25
35
 
36
+ abstract fun setDisplayDismissButton(view: T, display: Boolean)
37
+
26
38
  override fun getExportedCustomDirectEventTypeConstants(): Map<String, Any>? {
27
39
  return MapBuilder.builder<String, Any>()
28
- .putEvent(PaywallEvent.ON_PURCHASE_STARTED)
29
- .putEvent(PaywallEvent.ON_PURCHASE_COMPLETED)
30
- .putEvent(PaywallEvent.ON_PURCHASE_ERROR)
31
- .putEvent(PaywallEvent.ON_PURCHASE_CANCELLED)
32
- .putEvent(PaywallEvent.ON_RESTORE_STARTED)
33
- .putEvent(PaywallEvent.ON_RESTORE_COMPLETED)
34
- .putEvent(PaywallEvent.ON_RESTORE_ERROR)
35
- .putEvent(PaywallEvent.ON_DISMISS)
40
+ .putEvent(PaywallEventName.ON_PURCHASE_STARTED)
41
+ .putEvent(PaywallEventName.ON_PURCHASE_COMPLETED)
42
+ .putEvent(PaywallEventName.ON_PURCHASE_ERROR)
43
+ .putEvent(PaywallEventName.ON_PURCHASE_CANCELLED)
44
+ .putEvent(PaywallEventName.ON_RESTORE_STARTED)
45
+ .putEvent(PaywallEventName.ON_RESTORE_COMPLETED)
46
+ .putEvent(PaywallEventName.ON_RESTORE_ERROR)
47
+ .putEvent(PaywallEventName.ON_DISMISS)
48
+ .putEvent(PaywallEventName.ON_MEASURE)
36
49
  .build()
37
50
  }
38
51
 
@@ -44,11 +57,13 @@ internal abstract class BasePaywallViewManager<T : View> : SimpleViewManager<T>(
44
57
  options?.let { props ->
45
58
  setOfferingIdProp(view, props)
46
59
  setFontFamilyProp(view, props)
60
+ setDisplayCloseButton(view, props)
47
61
  }
48
62
  }
49
63
 
50
64
  private fun setOfferingIdProp(view: T, props: ReadableMap?) {
51
- val offeringIdentifier = props?.getDynamic(OPTION_OFFERING)?.asMap()?.getString(OFFERING_IDENTIFIER)
65
+ val offeringIdentifier =
66
+ props?.getDynamic(OPTION_OFFERING)?.asMap()?.getString(OFFERING_IDENTIFIER)
52
67
  offeringIdentifier?.let {
53
68
  setOfferingId(view, it)
54
69
  }
@@ -60,71 +75,96 @@ internal abstract class BasePaywallViewManager<T : View> : SimpleViewManager<T>(
60
75
  FontAssetManager.getFontFamily(fontFamilyName = it, view.resources.assets)?.let {
61
76
  setFontFamily(view, CustomFontProvider(it))
62
77
  }
78
+ }
79
+ }
63
80
 
81
+ private fun setDisplayCloseButton(view: T, options: ReadableMap) {
82
+ options.takeIf { it.hasKey("displayCloseButton") }?.let {
83
+ setDisplayDismissButton(view, it.getBoolean("displayCloseButton"))
64
84
  }
65
85
  }
66
86
 
67
- // TODO: RCTEventEmitter is deprecated, and RCTModernEventEmitter should be used instead
68
- // but documentation is not clear on how to use it so keeping this for now
69
87
  internal fun createPaywallListenerWrapper(
70
88
  themedReactContext: ThemedReactContext,
71
89
  view: View
72
90
  ) = object : PaywallListenerWrapper() {
73
-
74
91
  override fun onPurchaseStarted(rcPackage: Map<String, Any?>) {
75
- val payload = mapOf(
76
- PaywallEventKey.PACKAGE to rcPackage,
92
+ val event = OnPurchaseStartedEvent(
93
+ surfaceId = view.surfaceId,
94
+ viewTag = view.id,
95
+ rcPackage
77
96
  )
78
- emitEvent(themedReactContext, view.id, PaywallEvent.ON_PURCHASE_STARTED, payload)
97
+ emitEvent(themedReactContext, view.id, event)
79
98
  }
80
99
 
81
100
  override fun onPurchaseCompleted(
82
101
  customerInfo: Map<String, Any?>,
83
102
  storeTransaction: Map<String, Any?>
84
103
  ) {
85
- val payload = mapOf(
86
- PaywallEventKey.CUSTOMER_INFO to customerInfo,
87
- PaywallEventKey.STORE_TRANSACTION to storeTransaction
104
+ val event = OnPurchaseCompletedEvent(
105
+ surfaceId = view.surfaceId,
106
+ viewTag = view.id,
107
+ customerInfo,
108
+ storeTransaction
88
109
  )
89
- emitEvent(themedReactContext, view.id, PaywallEvent.ON_PURCHASE_COMPLETED, payload)
110
+ emitEvent(themedReactContext, view.id, event)
90
111
  }
91
112
 
92
113
  override fun onPurchaseError(error: Map<String, Any?>) {
93
- val payload = mapOf(PaywallEventKey.ERROR to error)
94
- emitEvent(themedReactContext, view.id, PaywallEvent.ON_PURCHASE_ERROR, payload)
114
+ val event = OnPurchaseErrorEvent(
115
+ surfaceId = view.surfaceId,
116
+ viewTag = view.id,
117
+ error
118
+ )
119
+ emitEvent(themedReactContext, view.id, event)
95
120
  }
96
121
 
97
122
  override fun onPurchaseCancelled() {
98
- emitEvent(themedReactContext, view.id, PaywallEvent.ON_PURCHASE_CANCELLED)
123
+ val event = OnPurchaseCancelledEvent(
124
+ surfaceId = view.surfaceId,
125
+ viewTag = view.id,
126
+ )
127
+ emitEvent(themedReactContext, view.id, event)
99
128
  }
100
129
 
101
130
  override fun onRestoreStarted() {
102
- emitEvent(themedReactContext, view.id, PaywallEvent.ON_RESTORE_STARTED)
131
+ val event = OnRestoreStartedEvent(
132
+ surfaceId = view.surfaceId,
133
+ viewTag = view.id,
134
+ )
135
+ emitEvent(themedReactContext, view.id, event)
103
136
  }
104
137
 
105
138
  override fun onRestoreCompleted(customerInfo: Map<String, Any?>) {
106
- val payload = mapOf(PaywallEventKey.CUSTOMER_INFO to customerInfo)
107
- emitEvent(themedReactContext, view.id, PaywallEvent.ON_RESTORE_COMPLETED, payload)
139
+ val event = OnRestoreCompletedEvent(
140
+ surfaceId = view.surfaceId,
141
+ viewTag = view.id,
142
+ customerInfo,
143
+ )
144
+ emitEvent(themedReactContext, view.id, event)
108
145
  }
109
146
 
110
147
  override fun onRestoreError(error: Map<String, Any?>) {
111
- val payload = mapOf(PaywallEventKey.ERROR to error)
112
- emitEvent(themedReactContext, view.id, PaywallEvent.ON_RESTORE_ERROR, payload)
148
+ val event = OnRestoreErrorEvent(
149
+ surfaceId = view.surfaceId,
150
+ viewTag = view.id,
151
+ error,
152
+ )
153
+ emitEvent(themedReactContext, view.id, event)
113
154
  }
114
155
 
115
156
  }
116
157
 
117
158
  internal fun getDismissHandler(
118
159
  themedReactContext: ThemedReactContext,
119
- view: T
120
- ): (() -> Unit) {
121
- return {
122
- emitEvent(themedReactContext, view.id, PaywallEvent.ON_DISMISS)
123
- }
160
+ view: View,
161
+ ): (() -> Unit) = {
162
+ val event = OnDismissEvent(view.surfaceId, view.id)
163
+ emitEvent(themedReactContext, view.id, event)
124
164
  }
125
165
 
126
166
  private fun MapBuilder.Builder<String, Any>.putEvent(
127
- paywallEvent: PaywallEvent
167
+ paywallEvent: PaywallEventName
128
168
  ): MapBuilder.Builder<String, Any> {
129
169
  val registrationName = MapBuilder.of("registrationName", paywallEvent.eventName)
130
170
  return this.put(paywallEvent.eventName, registrationName)
@@ -137,31 +177,12 @@ internal abstract class BasePaywallViewManager<T : View> : SimpleViewManager<T>(
137
177
  )
138
178
  }
139
179
 
140
- private fun emitEvent(
141
- context: ThemedReactContext,
142
- viewId: Int,
143
- event: PaywallEvent,
144
- payload: Map<PaywallEventKey, Map<String, Any?>>,
145
- ) {
146
- val convertedPayload = WritableNativeMap().apply {
147
- payload.forEach { (key, value) ->
148
- putMap(key.key, RNPurchasesConverters.convertMapToWriteableMap(value))
149
- }
150
- }
151
- emitEvent(context, viewId, event, convertedPayload)
152
- }
153
-
154
- @Suppress("DEPRECATION")
155
- private fun emitEvent(
156
- context: ThemedReactContext,
180
+ protected fun emitEvent(
181
+ context: ReactContext,
157
182
  viewId: Int,
158
- event: PaywallEvent,
159
- payload: WritableNativeMap? = null
183
+ event: Event<*>,
160
184
  ) {
161
- context.getJSModule(RCTEventEmitter::class.java).receiveEvent(
162
- viewId,
163
- event.eventName,
164
- payload
165
- )
185
+ val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, viewId)
186
+ eventDispatcher?.dispatchEvent(event)
166
187
  }
167
188
  }
@@ -5,11 +5,16 @@ import androidx.compose.ui.text.font.Font
5
5
  import androidx.compose.ui.text.font.FontFamily
6
6
  import androidx.compose.ui.text.font.FontStyle
7
7
  import androidx.compose.ui.text.font.FontWeight
8
+ import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI
9
+ import com.revenuecat.purchases.ui.revenuecatui.fonts.PaywallFont
10
+ import com.revenuecat.purchases.ui.revenuecatui.fonts.PaywallFontFamily
8
11
 
9
12
 
13
+ @OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
10
14
  internal object FontAssetManager {
11
15
  @get:Synchronized
12
16
  private var fontFamilyCache = mapOf<String, FontFamily>()
17
+ private var paywallFontFamilyCache = mapOf<String, PaywallFontFamily>()
13
18
  private val FILE_EXTENSIONS = arrayOf(".ttf", ".otf")
14
19
 
15
20
  private const val FONT_PATH = "fonts/"
@@ -39,23 +44,16 @@ internal object FontAssetManager {
39
44
  if (cachedFontFamily != null) {
40
45
  return cachedFontFamily
41
46
  }
42
- val existingFontFileNames = assetManager.list(FONT_PATH)?.toList() ?: emptyList()
43
- val fontsInFamily = mutableListOf<Font>()
44
- FontStyleExtension.values().forEach { styleExtension ->
45
- FILE_EXTENSIONS.forEach { fileNameExtension ->
46
- val fileName = "$fontFamilyName${styleExtension.extension}$fileNameExtension"
47
- if (existingFontFileNames.contains(fileName)) {
48
- fontsInFamily.add(
49
- Font(
50
- path = FONT_PATH + fileName,
51
- assetManager = assetManager,
52
- weight = styleExtension.weight,
53
- style = styleExtension.style
54
- )
55
- )
56
- }
47
+
48
+ val fontsInFamily =
49
+ getFontsInFamily(fontFamilyName, assetManager) { fileName, styleExtension ->
50
+ Font(
51
+ path = FONT_PATH + fileName,
52
+ assetManager = assetManager,
53
+ weight = styleExtension.weight,
54
+ style = styleExtension.style
55
+ )
57
56
  }
58
- }
59
57
 
60
58
  return if (fontsInFamily.isNotEmpty()) {
61
59
  val fontFamily = FontFamily(fontsInFamily)
@@ -65,4 +63,50 @@ internal object FontAssetManager {
65
63
  null
66
64
  }
67
65
  }
66
+
67
+ @Synchronized
68
+ fun getPaywallFontFamily(
69
+ fontFamilyName: String,
70
+ assetManager: AssetManager
71
+ ): PaywallFontFamily? {
72
+ val cachedPaywallFontFamily = paywallFontFamilyCache[fontFamilyName]
73
+ if (cachedPaywallFontFamily != null) {
74
+ return cachedPaywallFontFamily
75
+ }
76
+
77
+ val paywallFontsInFamily =
78
+ getFontsInFamily(fontFamilyName, assetManager) { fileName, styleExtension ->
79
+ PaywallFont.AssetFont(
80
+ path = FONT_PATH + fileName,
81
+ fontWeight = styleExtension.weight,
82
+ fontStyle = styleExtension.style.value
83
+ )
84
+ }
85
+
86
+ return if (paywallFontsInFamily.isNotEmpty()) {
87
+ val fontFamily = PaywallFontFamily(paywallFontsInFamily)
88
+ paywallFontFamilyCache = paywallFontFamilyCache + (fontFamilyName to fontFamily)
89
+ fontFamily
90
+ } else {
91
+ null
92
+ }
93
+ }
94
+
95
+ private fun <T> getFontsInFamily(
96
+ fontFamilyName: String,
97
+ assetManager: AssetManager,
98
+ createFont: (String, FontStyleExtension) -> T
99
+ ): List<T> {
100
+ val existingFontFileNames = assetManager.list(FONT_PATH)?.toList() ?: emptyList()
101
+ val fontsInFamily = mutableListOf<T>()
102
+ FontStyleExtension.values().forEach { styleExtension ->
103
+ FILE_EXTENSIONS.forEach { fileNameExtension ->
104
+ val fileName = "$fontFamilyName${styleExtension.extension}$fileNameExtension"
105
+ if (existingFontFileNames.contains(fileName)) {
106
+ fontsInFamily.add(createFont(fileName, styleExtension))
107
+ }
108
+ }
109
+ }
110
+ return fontsInFamily
111
+ }
68
112
  }
@@ -1,6 +1,6 @@
1
1
  package com.revenuecat.purchases.react.ui
2
2
 
3
- internal enum class PaywallEvent(val eventName: String) {
3
+ internal enum class PaywallEventName(val eventName: String) {
4
4
  ON_PURCHASE_STARTED("onPurchaseStarted"),
5
5
  ON_PURCHASE_COMPLETED("onPurchaseCompleted"),
6
6
  ON_PURCHASE_ERROR("onPurchaseError"),
@@ -8,12 +8,15 @@ internal enum class PaywallEvent(val eventName: String) {
8
8
  ON_RESTORE_STARTED("onRestoreStarted"),
9
9
  ON_RESTORE_COMPLETED("onRestoreCompleted"),
10
10
  ON_RESTORE_ERROR("onRestoreError"),
11
- ON_DISMISS("onDismiss");
11
+ ON_DISMISS("onDismiss"),
12
+ ON_MEASURE("onMeasure");
12
13
  }
13
14
 
14
15
  internal enum class PaywallEventKey(val key: String) {
15
16
  PACKAGE("packageBeingPurchased"),
16
17
  CUSTOMER_INFO("customerInfo"),
17
18
  STORE_TRANSACTION("storeTransaction"),
18
- ERROR("error")
19
+ ERROR("error"),
20
+ MEASUREMENTS("measurements"),
21
+ HEIGHT("height"),
19
22
  }
@@ -2,7 +2,7 @@ package com.revenuecat.purchases.react.ui
2
2
 
3
3
  import androidx.core.view.children
4
4
  import com.facebook.react.uimanager.ThemedReactContext
5
- import com.facebook.react.uimanager.UIManagerModule
5
+ import com.revenuecat.purchases.react.ui.events.OnMeasureEvent
6
6
  import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI
7
7
  import com.revenuecat.purchases.ui.revenuecatui.fonts.CustomFontProvider
8
8
  import com.revenuecat.purchases.ui.revenuecatui.views.PaywallFooterView
@@ -48,16 +48,22 @@ internal class PaywallFooterViewManager : BasePaywallViewManager<PaywallFooterVi
48
48
  val finalWidth = maxWidth.coerceAtLeast(suggestedMinimumWidth)
49
49
  val finalHeight = maxHeight.coerceAtLeast(suggestedMinimumHeight)
50
50
  setMeasuredDimension(finalWidth, finalHeight)
51
- (context as? ThemedReactContext)?.let { themedReactContext ->
52
- themedReactContext.runOnNativeModulesQueueThread {
53
- themedReactContext.getNativeModule(UIManagerModule::class.java)
54
- ?.updateNodeSize(id, finalWidth, finalHeight)
55
- }
51
+
52
+ val density = context.resources.displayMetrics.density
53
+ val finalHeightInDp = finalHeight / density
54
+
55
+ val onMeasureEvent = OnMeasureEvent(
56
+ this.surfaceId,
57
+ this.id,
58
+ finalHeightInDp.toInt()
59
+ )
60
+ (context as? ThemedReactContext)?.reactApplicationContext?.let { reactApplicationContext ->
61
+ emitEvent(reactApplicationContext, this.id, onMeasureEvent)
56
62
  }
57
63
  }
58
- }.also {
59
- it.setPaywallListener(createPaywallListenerWrapper(themedReactContext, it))
60
- it.setDismissHandler(getDismissHandler(themedReactContext, it))
64
+ }.also { view ->
65
+ view.setPaywallListener(createPaywallListenerWrapper(themedReactContext, view))
66
+ view.setDismissHandler(getDismissHandler(themedReactContext, view))
61
67
  }
62
68
  }
63
69
 
@@ -68,4 +74,9 @@ internal class PaywallFooterViewManager : BasePaywallViewManager<PaywallFooterVi
68
74
  override fun setFontFamily(view: PaywallFooterView, customFontProvider: CustomFontProvider) {
69
75
  view.setFontProvider(customFontProvider)
70
76
  }
77
+
78
+ override fun setDisplayDismissButton(view: PaywallFooterView, display: Boolean) {
79
+ // No-op since PaywallFooterView doesn't have a dismiss button
80
+ }
81
+
71
82
  }
@@ -5,6 +5,7 @@ import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIP
5
5
  import com.revenuecat.purchases.ui.revenuecatui.fonts.CustomFontProvider
6
6
  import com.revenuecat.purchases.ui.revenuecatui.views.PaywallView
7
7
 
8
+
8
9
  @OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
9
10
  internal class PaywallViewManager : BasePaywallViewManager<PaywallView>() {
10
11
 
@@ -17,9 +18,9 @@ internal class PaywallViewManager : BasePaywallViewManager<PaywallView>() {
17
18
  }
18
19
 
19
20
  override fun createViewInstance(themedReactContext: ThemedReactContext): PaywallView {
20
- return PaywallView(themedReactContext).also {
21
- it.setPaywallListener(createPaywallListenerWrapper(themedReactContext, it))
22
- it.setDismissHandler(getDismissHandler(themedReactContext, it))
21
+ return PaywallView(themedReactContext).also { view ->
22
+ view.setPaywallListener(createPaywallListenerWrapper(themedReactContext, view))
23
+ view.setDismissHandler(getDismissHandler(themedReactContext, view))
23
24
  }
24
25
  }
25
26
 
@@ -34,4 +35,9 @@ internal class PaywallViewManager : BasePaywallViewManager<PaywallView>() {
34
35
  override fun setFontFamily(view: PaywallView, customFontProvider: CustomFontProvider) {
35
36
  view.setFontProvider(customFontProvider)
36
37
  }
38
+
39
+ override fun setDisplayDismissButton(view: PaywallView, display: Boolean) {
40
+ view.setDisplayDismissButton(display)
41
+ }
42
+
37
43
  }
@@ -10,6 +10,9 @@ import com.revenuecat.purchases.hybridcommon.ui.PaywallResultListener
10
10
  import com.revenuecat.purchases.hybridcommon.ui.PaywallSource
11
11
  import com.revenuecat.purchases.hybridcommon.ui.PresentPaywallOptions
12
12
  import com.revenuecat.purchases.hybridcommon.ui.presentPaywallFromFragment
13
+ import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI
14
+ import com.revenuecat.purchases.ui.revenuecatui.fonts.PaywallFont
15
+ import com.revenuecat.purchases.ui.revenuecatui.fonts.PaywallFontFamily
13
16
 
14
17
  internal class RNPaywallsModule(reactContext: ReactApplicationContext) :
15
18
  ReactContextBaseJavaModule(reactContext) {
@@ -36,12 +39,14 @@ internal class RNPaywallsModule(reactContext: ReactApplicationContext) :
36
39
  fun presentPaywall(
37
40
  offeringIdentifier: String?,
38
41
  displayCloseButton: Boolean?,
42
+ fontFamily: String?,
39
43
  promise: Promise
40
44
  ) {
41
45
  presentPaywall(
42
46
  null,
43
47
  offeringIdentifier,
44
48
  displayCloseButton,
49
+ fontFamily,
45
50
  promise
46
51
  )
47
52
  }
@@ -51,12 +56,14 @@ internal class RNPaywallsModule(reactContext: ReactApplicationContext) :
51
56
  requiredEntitlementIdentifier: String,
52
57
  offeringIdentifier: String?,
53
58
  displayCloseButton: Boolean,
59
+ fontFamily: String?,
54
60
  promise: Promise
55
61
  ) {
56
62
  presentPaywall(
57
63
  requiredEntitlementIdentifier,
58
64
  offeringIdentifier,
59
65
  displayCloseButton,
66
+ fontFamily,
60
67
  promise
61
68
  )
62
69
  }
@@ -71,14 +78,18 @@ internal class RNPaywallsModule(reactContext: ReactApplicationContext) :
71
78
  // Keep: Required for RN built in Event Emitter Calls.
72
79
  }
73
80
 
81
+ @OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
74
82
  private fun presentPaywall(
75
83
  requiredEntitlementIdentifier: String?,
76
84
  offeringIdentifier: String?,
77
85
  displayCloseButton: Boolean?,
86
+ fontFamilyName: String?,
78
87
  promise: Promise
79
88
  ) {
80
89
  val fragment = currentActivityFragment ?: return
81
-
90
+ val fontFamily = fontFamilyName?.let {
91
+ FontAssetManager.getPaywallFontFamily(fontFamilyName = it, fragment.resources.assets)
92
+ }
82
93
  presentPaywallFromFragment(
83
94
  fragment = fragment,
84
95
  PresentPaywallOptions(
@@ -91,7 +102,8 @@ internal class RNPaywallsModule(reactContext: ReactApplicationContext) :
91
102
  override fun onPaywallResult(paywallResult: String) {
92
103
  promise.resolve(paywallResult)
93
104
  }
94
- }
105
+ },
106
+ fontFamily = fontFamily
95
107
  )
96
108
  )
97
109
  }
@@ -0,0 +1,7 @@
1
+ package com.revenuecat.purchases.react.ui
2
+
3
+ import android.view.View
4
+ import com.facebook.react.uimanager.UIManagerHelper
5
+
6
+ internal val View.surfaceId
7
+ get() = UIManagerHelper.getSurfaceId(this)
@@ -0,0 +1,13 @@
1
+ package com.revenuecat.purchases.react.ui.events
2
+
3
+ import com.revenuecat.purchases.react.ui.PaywallEventKey
4
+ import com.revenuecat.purchases.react.ui.PaywallEventName
5
+
6
+ internal class OnDismissEvent(
7
+ surfaceId: Int,
8
+ viewTag: Int,
9
+ ) : PaywallEvent<OnDismissEvent>(surfaceId, viewTag) {
10
+ override fun getPaywallEventName() = PaywallEventName.ON_DISMISS
11
+
12
+ override fun getPayload(): Map<PaywallEventKey, Map<String, Any?>> = emptyMap()
13
+ }
@@ -0,0 +1,17 @@
1
+ package com.revenuecat.purchases.react.ui.events
2
+
3
+ import com.revenuecat.purchases.react.ui.PaywallEventKey
4
+ import com.revenuecat.purchases.react.ui.PaywallEventName
5
+
6
+ internal class OnMeasureEvent(
7
+ surfaceId: Int,
8
+ viewTag: Int,
9
+ private val height: Int
10
+ ) : PaywallEvent<OnDismissEvent>(surfaceId, viewTag) {
11
+ override fun getPaywallEventName() = PaywallEventName.ON_MEASURE
12
+
13
+ override fun getPayload() = mapOf(
14
+ PaywallEventKey.MEASUREMENTS to mapOf(PaywallEventKey.HEIGHT.key to height),
15
+ )
16
+ }
17
+
@@ -0,0 +1,13 @@
1
+ package com.revenuecat.purchases.react.ui.events
2
+
3
+ import com.revenuecat.purchases.react.ui.PaywallEventKey
4
+ import com.revenuecat.purchases.react.ui.PaywallEventName
5
+
6
+ internal class OnPurchaseCancelledEvent(
7
+ surfaceId: Int,
8
+ viewTag: Int,
9
+ ) : PaywallEvent<OnPurchaseCancelledEvent>(surfaceId, viewTag) {
10
+ override fun getPaywallEventName() = PaywallEventName.ON_PURCHASE_CANCELLED
11
+
12
+ override fun getPayload(): Map<PaywallEventKey, Map<String, Any?>> = emptyMap()
13
+ }
@@ -0,0 +1,18 @@
1
+ package com.revenuecat.purchases.react.ui.events
2
+
3
+ import com.revenuecat.purchases.react.ui.PaywallEventKey
4
+ import com.revenuecat.purchases.react.ui.PaywallEventName
5
+
6
+ internal class OnPurchaseCompletedEvent(
7
+ surfaceId: Int,
8
+ viewTag: Int,
9
+ private val customerInfo: Map<String, Any?>,
10
+ private val storeTransaction: Map<String, Any?>
11
+ ) : PaywallEvent<OnPurchaseCompletedEvent>(surfaceId, viewTag) {
12
+ override fun getPaywallEventName() = PaywallEventName.ON_PURCHASE_COMPLETED
13
+
14
+ override fun getPayload() = mapOf(
15
+ PaywallEventKey.CUSTOMER_INFO to customerInfo,
16
+ PaywallEventKey.STORE_TRANSACTION to storeTransaction
17
+ )
18
+ }
@@ -0,0 +1,14 @@
1
+ package com.revenuecat.purchases.react.ui.events
2
+
3
+ import com.revenuecat.purchases.react.ui.PaywallEventKey
4
+ import com.revenuecat.purchases.react.ui.PaywallEventName
5
+
6
+ internal class OnPurchaseErrorEvent(
7
+ surfaceId: Int,
8
+ viewTag: Int,
9
+ private val error: Map<String, Any?>
10
+ ) : PaywallEvent<OnPurchaseErrorEvent>(surfaceId, viewTag) {
11
+ override fun getPaywallEventName() = PaywallEventName.ON_PURCHASE_ERROR
12
+
13
+ override fun getPayload() = mapOf(PaywallEventKey.ERROR to error)
14
+ }
@@ -0,0 +1,16 @@
1
+ package com.revenuecat.purchases.react.ui.events
2
+
3
+ import com.revenuecat.purchases.react.ui.PaywallEventKey
4
+ import com.revenuecat.purchases.react.ui.PaywallEventName
5
+
6
+ internal class OnPurchaseStartedEvent(
7
+ surfaceId: Int,
8
+ viewTag: Int,
9
+ private val packageMap: Map<String, Any?>
10
+ ) : PaywallEvent<OnPurchaseStartedEvent>(surfaceId, viewTag) {
11
+ override fun getPaywallEventName() = PaywallEventName.ON_PURCHASE_STARTED
12
+
13
+ override fun getPayload() = mapOf(
14
+ PaywallEventKey.PACKAGE to packageMap,
15
+ )
16
+ }
@@ -0,0 +1,14 @@
1
+ package com.revenuecat.purchases.react.ui.events
2
+
3
+ import com.revenuecat.purchases.react.ui.PaywallEventKey
4
+ import com.revenuecat.purchases.react.ui.PaywallEventName
5
+
6
+ internal class OnRestoreCompletedEvent(
7
+ surfaceId: Int,
8
+ viewTag: Int,
9
+ private val customerInfo: Map<String, Any?>,
10
+ ) : PaywallEvent<OnRestoreCompletedEvent>(surfaceId, viewTag) {
11
+ override fun getPaywallEventName() = PaywallEventName.ON_RESTORE_COMPLETED
12
+
13
+ override fun getPayload() = mapOf(PaywallEventKey.CUSTOMER_INFO to customerInfo)
14
+ }