Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove usage of RCTEventEmitter in Android #961

Merged
merged 5 commits into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,18 @@ import com.facebook.react.bridge.WritableNativeMap
import com.facebook.react.common.MapBuilder
import com.facebook.react.uimanager.SimpleViewManager
import com.facebook.react.uimanager.ThemedReactContext
import com.facebook.react.uimanager.UIManagerHelper
import com.facebook.react.uimanager.annotations.ReactProp
import com.facebook.react.uimanager.events.RCTEventEmitter
import com.facebook.react.uimanager.events.Event
import com.revenuecat.purchases.hybridcommon.ui.PaywallListenerWrapper
import com.revenuecat.purchases.react.ui.events.OnDismissEvent
import com.revenuecat.purchases.react.ui.events.OnPurchaseCancelledEvent
import com.revenuecat.purchases.react.ui.events.OnPurchaseCompletedEvent
import com.revenuecat.purchases.react.ui.events.OnPurchaseErrorEvent
import com.revenuecat.purchases.react.ui.events.OnPurchaseStartedEvent
import com.revenuecat.purchases.react.ui.events.OnRestoreCompletedEvent
import com.revenuecat.purchases.react.ui.events.OnRestoreErrorEvent
import com.revenuecat.purchases.react.ui.events.OnRestoreStartedEvent
import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIPurchasesAPI
import com.revenuecat.purchases.ui.revenuecatui.fonts.CustomFontProvider

Expand All @@ -27,14 +36,14 @@ internal abstract class BasePaywallViewManager<T : View> : SimpleViewManager<T>(

override fun getExportedCustomDirectEventTypeConstants(): Map<String, Any>? {
return MapBuilder.builder<String, Any>()
.putEvent(PaywallEvent.ON_PURCHASE_STARTED)
.putEvent(PaywallEvent.ON_PURCHASE_COMPLETED)
.putEvent(PaywallEvent.ON_PURCHASE_ERROR)
.putEvent(PaywallEvent.ON_PURCHASE_CANCELLED)
.putEvent(PaywallEvent.ON_RESTORE_STARTED)
.putEvent(PaywallEvent.ON_RESTORE_COMPLETED)
.putEvent(PaywallEvent.ON_RESTORE_ERROR)
.putEvent(PaywallEvent.ON_DISMISS)
.putEvent(PaywallEventName.ON_PURCHASE_STARTED)
.putEvent(PaywallEventName.ON_PURCHASE_COMPLETED)
.putEvent(PaywallEventName.ON_PURCHASE_ERROR)
.putEvent(PaywallEventName.ON_PURCHASE_CANCELLED)
.putEvent(PaywallEventName.ON_RESTORE_STARTED)
.putEvent(PaywallEventName.ON_RESTORE_COMPLETED)
.putEvent(PaywallEventName.ON_RESTORE_ERROR)
.putEvent(PaywallEventName.ON_DISMISS)
.build()
}

Expand All @@ -51,7 +60,8 @@ internal abstract class BasePaywallViewManager<T : View> : SimpleViewManager<T>(
}

private fun setOfferingIdProp(view: T, props: ReadableMap?) {
val offeringIdentifier = props?.getDynamic(OPTION_OFFERING)?.asMap()?.getString(OFFERING_IDENTIFIER)
val offeringIdentifier =
props?.getDynamic(OPTION_OFFERING)?.asMap()?.getString(OFFERING_IDENTIFIER)
offeringIdentifier?.let {
setOfferingId(view, it)
}
Expand All @@ -72,67 +82,87 @@ internal abstract class BasePaywallViewManager<T : View> : SimpleViewManager<T>(
}
}

// TODO: RCTEventEmitter is deprecated, and RCTModernEventEmitter should be used instead
// but documentation is not clear on how to use it so keeping this for now
internal fun createPaywallListenerWrapper(
themedReactContext: ThemedReactContext,
view: View
) = object : PaywallListenerWrapper() {

override fun onPurchaseStarted(rcPackage: Map<String, Any?>) {
val payload = mapOf(
PaywallEventKey.PACKAGE to rcPackage,
val event = OnPurchaseStartedEvent(
surfaceId = view.surfaceId,
viewTag = view.id,
rcPackage
)
emitEvent(themedReactContext, view.id, PaywallEvent.ON_PURCHASE_STARTED, payload)
emitEvent(themedReactContext, view.id, event)
}

override fun onPurchaseCompleted(
customerInfo: Map<String, Any?>,
storeTransaction: Map<String, Any?>
) {
val payload = mapOf(
PaywallEventKey.CUSTOMER_INFO to customerInfo,
PaywallEventKey.STORE_TRANSACTION to storeTransaction
val event = OnPurchaseCompletedEvent(
surfaceId = view.surfaceId,
viewTag = view.id,
customerInfo,
storeTransaction
)
emitEvent(themedReactContext, view.id, PaywallEvent.ON_PURCHASE_COMPLETED, payload)
emitEvent(themedReactContext, view.id, event)
}

override fun onPurchaseError(error: Map<String, Any?>) {
val payload = mapOf(PaywallEventKey.ERROR to error)
emitEvent(themedReactContext, view.id, PaywallEvent.ON_PURCHASE_ERROR, payload)
val event = OnPurchaseErrorEvent(
surfaceId = view.surfaceId,
viewTag = view.id,
error
)
emitEvent(themedReactContext, view.id, event)
}

override fun onPurchaseCancelled() {
emitEvent(themedReactContext, view.id, PaywallEvent.ON_PURCHASE_CANCELLED)
val event = OnPurchaseCancelledEvent(
surfaceId = view.surfaceId,
viewTag = view.id,
)
emitEvent(themedReactContext, view.id, event)
}

override fun onRestoreStarted() {
emitEvent(themedReactContext, view.id, PaywallEvent.ON_RESTORE_STARTED)
val event = OnRestoreStartedEvent(
surfaceId = view.surfaceId,
viewTag = view.id,
)
emitEvent(themedReactContext, view.id, event)
}

override fun onRestoreCompleted(customerInfo: Map<String, Any?>) {
val payload = mapOf(PaywallEventKey.CUSTOMER_INFO to customerInfo)
emitEvent(themedReactContext, view.id, PaywallEvent.ON_RESTORE_COMPLETED, payload)
val event = OnRestoreCompletedEvent(
surfaceId = view.surfaceId,
viewTag = view.id,
customerInfo,
)
emitEvent(themedReactContext, view.id, event)
}

override fun onRestoreError(error: Map<String, Any?>) {
val payload = mapOf(PaywallEventKey.ERROR to error)
emitEvent(themedReactContext, view.id, PaywallEvent.ON_RESTORE_ERROR, payload)
val event = OnRestoreErrorEvent(
surfaceId = view.surfaceId,
viewTag = view.id,
error,
)
emitEvent(themedReactContext, view.id, event)
}

}

internal fun getDismissHandler(
themedReactContext: ThemedReactContext,
view: T
): (() -> Unit) {
return {
emitEvent(themedReactContext, view.id, PaywallEvent.ON_DISMISS)
}
view: View,
): (() -> Unit) = {
val event = OnDismissEvent(view.surfaceId, view.id)
emitEvent(themedReactContext, view.id, event)
}

private fun MapBuilder.Builder<String, Any>.putEvent(
paywallEvent: PaywallEvent
paywallEvent: PaywallEventName
): MapBuilder.Builder<String, Any> {
val registrationName = MapBuilder.of("registrationName", paywallEvent.eventName)
return this.put(paywallEvent.eventName, registrationName)
Expand All @@ -148,28 +178,9 @@ internal abstract class BasePaywallViewManager<T : View> : SimpleViewManager<T>(
private fun emitEvent(
context: ThemedReactContext,
viewId: Int,
event: PaywallEvent,
payload: Map<PaywallEventKey, Map<String, Any?>>,
) {
val convertedPayload = WritableNativeMap().apply {
payload.forEach { (key, value) ->
putMap(key.key, RNPurchasesConverters.convertMapToWriteableMap(value))
}
}
emitEvent(context, viewId, event, convertedPayload)
}

@Suppress("DEPRECATION")
private fun emitEvent(
context: ThemedReactContext,
viewId: Int,
event: PaywallEvent,
payload: WritableNativeMap? = null
event: Event<*>,
) {
context.getJSModule(RCTEventEmitter::class.java).receiveEvent(
viewId,
event.eventName,
payload
)
val eventDispatcher = UIManagerHelper.getEventDispatcherForReactTag(context, viewId)
eventDispatcher?.dispatchEvent(event)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.revenuecat.purchases.react.ui

internal enum class PaywallEvent(val eventName: String) {
internal enum class PaywallEventName(val eventName: String) {
ON_PURCHASE_STARTED("onPurchaseStarted"),
ON_PURCHASE_COMPLETED("onPurchaseCompleted"),
ON_PURCHASE_ERROR("onPurchaseError"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ internal class PaywallFooterViewManager : BasePaywallViewManager<PaywallFooterVi
}
}
}
}.also {
it.setPaywallListener(createPaywallListenerWrapper(themedReactContext, it))
it.setDismissHandler(getDismissHandler(themedReactContext, it))
}.also { view ->
view.setPaywallListener(createPaywallListenerWrapper(themedReactContext, view))
view.setDismissHandler(getDismissHandler(themedReactContext, view))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.revenuecat.purchases.ui.revenuecatui.ExperimentalPreviewRevenueCatUIP
import com.revenuecat.purchases.ui.revenuecatui.fonts.CustomFontProvider
import com.revenuecat.purchases.ui.revenuecatui.views.PaywallView


@OptIn(ExperimentalPreviewRevenueCatUIPurchasesAPI::class)
internal class PaywallViewManager : BasePaywallViewManager<PaywallView>() {

Expand All @@ -17,9 +18,9 @@ internal class PaywallViewManager : BasePaywallViewManager<PaywallView>() {
}

override fun createViewInstance(themedReactContext: ThemedReactContext): PaywallView {
return PaywallView(themedReactContext).also {
it.setPaywallListener(createPaywallListenerWrapper(themedReactContext, it))
it.setDismissHandler(getDismissHandler(themedReactContext, it))
return PaywallView(themedReactContext).also { view ->
view.setPaywallListener(createPaywallListenerWrapper(themedReactContext, view))
view.setDismissHandler(getDismissHandler(themedReactContext, view))
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.revenuecat.purchases.react.ui

import android.view.View
import com.facebook.react.uimanager.UIManagerHelper

internal val View.surfaceId
get() = UIManagerHelper.getSurfaceId(this)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.revenuecat.purchases.react.ui.events

import com.revenuecat.purchases.react.ui.PaywallEventKey
import com.revenuecat.purchases.react.ui.PaywallEventName

internal class OnDismissEvent(
surfaceId: Int,
viewTag: Int,
) : PaywallEvent<OnDismissEvent>(surfaceId, viewTag) {
override fun getPaywallEventName() = PaywallEventName.ON_DISMISS

override fun getPayload(): Map<PaywallEventKey, Map<String, Any?>> = emptyMap()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.revenuecat.purchases.react.ui.events

import com.revenuecat.purchases.react.ui.PaywallEventKey
import com.revenuecat.purchases.react.ui.PaywallEventName

internal class OnPurchaseCancelledEvent(
surfaceId: Int,
viewTag: Int,
) : PaywallEvent<OnPurchaseCancelledEvent>(surfaceId, viewTag) {
override fun getPaywallEventName() = PaywallEventName.ON_PURCHASE_CANCELLED

override fun getPayload(): Map<PaywallEventKey, Map<String, Any?>> = emptyMap()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.revenuecat.purchases.react.ui.events

import com.revenuecat.purchases.react.ui.PaywallEventKey
import com.revenuecat.purchases.react.ui.PaywallEventName

internal class OnPurchaseCompletedEvent(
surfaceId: Int,
viewTag: Int,
private val customerInfo: Map<String, Any?>,
private val storeTransaction: Map<String, Any?>
) : PaywallEvent<OnPurchaseCompletedEvent>(surfaceId, viewTag) {
override fun getPaywallEventName() = PaywallEventName.ON_PURCHASE_COMPLETED

override fun getPayload() = mapOf(
PaywallEventKey.CUSTOMER_INFO to customerInfo,
PaywallEventKey.STORE_TRANSACTION to storeTransaction
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.revenuecat.purchases.react.ui.events

import com.revenuecat.purchases.react.ui.PaywallEventKey
import com.revenuecat.purchases.react.ui.PaywallEventName

internal class OnPurchaseErrorEvent(
surfaceId: Int,
viewTag: Int,
private val error: Map<String, Any?>
) : PaywallEvent<OnPurchaseErrorEvent>(surfaceId, viewTag) {
override fun getPaywallEventName() = PaywallEventName.ON_PURCHASE_ERROR

override fun getPayload() = mapOf(PaywallEventKey.ERROR to error)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.revenuecat.purchases.react.ui.events

import com.revenuecat.purchases.react.ui.PaywallEventKey
import com.revenuecat.purchases.react.ui.PaywallEventName

internal class OnPurchaseStartedEvent(
surfaceId: Int,
viewTag: Int,
private val packageMap: Map<String, Any?>
) : PaywallEvent<OnPurchaseStartedEvent>(surfaceId, viewTag) {
override fun getPaywallEventName() = PaywallEventName.ON_PURCHASE_STARTED

override fun getPayload() = mapOf(
PaywallEventKey.PACKAGE to packageMap,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.revenuecat.purchases.react.ui.events

import com.revenuecat.purchases.react.ui.PaywallEventKey
import com.revenuecat.purchases.react.ui.PaywallEventName

internal class OnRestoreCompletedEvent(
surfaceId: Int,
viewTag: Int,
private val customerInfo: Map<String, Any?>,
) : PaywallEvent<OnRestoreCompletedEvent>(surfaceId, viewTag) {
override fun getPaywallEventName() = PaywallEventName.ON_RESTORE_COMPLETED

override fun getPayload() = mapOf(PaywallEventKey.CUSTOMER_INFO to customerInfo)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.revenuecat.purchases.react.ui.events

import com.revenuecat.purchases.react.ui.PaywallEventKey
import com.revenuecat.purchases.react.ui.PaywallEventName

internal class OnRestoreErrorEvent(
surfaceId: Int,
viewTag: Int,
private val error: Map<String, Any?>
) : PaywallEvent<OnRestoreErrorEvent>(surfaceId, viewTag) {
override fun getPaywallEventName() = PaywallEventName.ON_RESTORE_ERROR

override fun getPayload() = mapOf(PaywallEventKey.ERROR to error)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.revenuecat.purchases.react.ui.events

import com.revenuecat.purchases.react.ui.PaywallEventKey
import com.revenuecat.purchases.react.ui.PaywallEventName

internal class OnRestoreStartedEvent(
surfaceId: Int,
viewTag: Int,
) : PaywallEvent<OnRestoreStartedEvent>(surfaceId, viewTag) {
override fun getPaywallEventName() = PaywallEventName.ON_RESTORE_STARTED

override fun getPayload(): Map<PaywallEventKey, Map<String, Any?>> = emptyMap()
}
Loading