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

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.
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
+ }