From a8daaf922a1a6852800ed088a6c48d9d809eae35 Mon Sep 17 00:00:00 2001 From: Vladimir Abramichev Date: Mon, 20 Nov 2023 09:43:20 +0100 Subject: [PATCH 01/18] chore: pump Android version to 5.0.1 --- android/build.gradle | 7 ++- .../com/adyenreactnativesdk/AdyenCheckout.kt | 18 ++----- .../action/ActionComponentDialogFragment.kt | 16 +++--- .../component/dropin/AdyenCheckoutService.kt | 52 ++++++++++--------- .../component/dropin/AdyenDropInComponent.kt | 11 ++-- .../instant/GenericPaymentComponentState.kt | 8 +-- 6 files changed, 55 insertions(+), 57 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index ddcfdeb14..b5f30ffa4 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -3,7 +3,7 @@ def safeExtGet(prop, fallback) { } buildscript { - + ext.kotlin_version = '1.9.10' rootProject.ext.adyenReactNativeRedirectScheme = "adyenreactnative" repositories { @@ -13,7 +13,7 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:7.3.1' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.22" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" } } @@ -58,8 +58,7 @@ repositories { dependencies { //noinspection GradleDynamicVersion api "com.facebook.react:react-native:+" // From node_modules - implementation "org.jetbrains.kotlin:kotlin-stdlib:1.7.22" - implementation "com.adyen.checkout:drop-in:4.13.3" + implementation "com.adyen.checkout:drop-in:5.0.1" implementation 'com.google.android.material:material:1.7.0' implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0" diff --git a/android/src/main/java/com/adyenreactnativesdk/AdyenCheckout.kt b/android/src/main/java/com/adyenreactnativesdk/AdyenCheckout.kt index 9b17b02b4..6ba90c725 100644 --- a/android/src/main/java/com/adyenreactnativesdk/AdyenCheckout.kt +++ b/android/src/main/java/com/adyenreactnativesdk/AdyenCheckout.kt @@ -5,7 +5,7 @@ import android.content.Intent import androidx.activity.result.ActivityResultCaller import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContract -import com.adyen.checkout.components.base.IntentHandlingComponent +import com.adyen.checkout.components.core.internal.IntentHandlingComponent import com.adyen.checkout.dropin.DropIn import com.adyen.checkout.dropin.DropInCallback import com.adyen.checkout.dropin.DropInResult @@ -27,6 +27,7 @@ object AdyenCheckout { @JvmStatic internal fun addDropInListener(callback: ReactDropInCallback) { dropInCallback.callback = WeakReference(callback) +// DropIn.registerForDropInResult(dropInLauncher, callback) } @JvmStatic @@ -40,10 +41,7 @@ object AdyenCheckout { */ @JvmStatic fun setLauncherActivity(activity: ActivityResultCaller) { - dropInLauncher = activity.registerForActivityResult( - ReactDropInResultContract(), - dropInCallback::onDropInResult - ) +// dropInLauncher = activity } /** @@ -103,16 +101,6 @@ object AdyenCheckout { } } -private class ReactDropInResultContract : ActivityResultContract() { - override fun createIntent(context: Context, input: Intent): Intent { - return input - } - - override fun parseResult(resultCode: Int, intent: Intent?): DropInResult? { - return DropIn.handleActivityResult(DropIn.DROP_IN_REQUEST_CODE, resultCode, intent) - } -} - private class DropInCallbackListener : DropInCallback { internal var callback: WeakReference = diff --git a/android/src/main/java/com/adyenreactnativesdk/action/ActionComponentDialogFragment.kt b/android/src/main/java/com/adyenreactnativesdk/action/ActionComponentDialogFragment.kt index 4142672c8..de6422c3f 100644 --- a/android/src/main/java/com/adyenreactnativesdk/action/ActionComponentDialogFragment.kt +++ b/android/src/main/java/com/adyenreactnativesdk/action/ActionComponentDialogFragment.kt @@ -13,13 +13,17 @@ import android.view.View import android.view.ViewGroup import androidx.lifecycle.Observer import com.adyen.checkout.components.* -import com.adyen.checkout.components.base.OutputData -import com.adyen.checkout.components.model.payments.response.Action +import com.adyen.checkout.components.core.ActionComponentData +import com.adyen.checkout.components.core.ComponentError +import com.adyen.checkout.components.core.action.Action +import com.adyen.checkout.components.core.internal.ActionComponent +import com.adyen.checkout.components.core.internal.ui.model.OutputData import com.adyen.checkout.core.exception.CheckoutException import com.adyen.checkout.core.exception.ComponentException -import com.adyen.checkout.core.log.LogUtil -import com.adyen.checkout.core.log.Logger -import com.adyen.checkout.dropin.databinding.FragmentActionComponentBinding +import com.adyen.checkout.core.internal.util.Logger +import com.adyen.checkout.ui.core.internal.ui.ComponentView +import com.adyen.checkout.ui.core.internal.ui.ViewableComponent + import com.google.android.material.bottomsheet.BottomSheetDialogFragment class ActionComponentDialogFragment( @@ -28,7 +32,7 @@ class ActionComponentDialogFragment( ) : BottomSheetDialogFragment(), Observer { companion object { - private val TAG = LogUtil.getTag() + private val TAG = "ActionComponentDialogFragment" const val ACTION = "ACTION" } diff --git a/android/src/main/java/com/adyenreactnativesdk/component/dropin/AdyenCheckoutService.kt b/android/src/main/java/com/adyenreactnativesdk/component/dropin/AdyenCheckoutService.kt index 23d700807..ede79b3ac 100644 --- a/android/src/main/java/com/adyenreactnativesdk/component/dropin/AdyenCheckoutService.kt +++ b/android/src/main/java/com/adyenreactnativesdk/component/dropin/AdyenCheckoutService.kt @@ -7,11 +7,13 @@ package com.adyenreactnativesdk.component.dropin import android.util.Log import com.adyen.checkout.card.CardComponentState -import com.adyen.checkout.components.ActionComponentData -import com.adyen.checkout.components.PaymentComponentState -import com.adyen.checkout.components.model.payments.response.Action -import com.adyen.checkout.dropin.service.DropInService -import com.adyen.checkout.dropin.service.DropInServiceResult +import com.adyen.checkout.components.core.ActionComponentData +import com.adyen.checkout.components.core.PaymentComponentData +import com.adyen.checkout.components.core.PaymentComponentState +import com.adyen.checkout.components.core.action.Action +import com.adyen.checkout.dropin.DropInService +import com.adyen.checkout.dropin.DropInServiceResult + import com.adyen.checkout.googlepay.GooglePayComponentState import com.adyenreactnativesdk.component.dropin.DropInServiceProxy.DropInModuleListener import com.adyenreactnativesdk.component.model.SubmitMap @@ -19,47 +21,49 @@ import com.facebook.react.bridge.ReadableMap import org.json.JSONObject open class AdyenCheckoutService : DropInService(), DropInModuleListener { + override fun onCreate() { super.onCreate() DropInServiceProxy.shared.moduleListener = this } - override fun onPaymentsCallRequested( - paymentComponentState: PaymentComponentState<*>, - paymentComponentJson: JSONObject - ) { - if (paymentComponentState is CardComponentState && - paymentComponentJson.getJSONObject(PAYMENT_DETAILS_KEY).isNull(BRAND_KEY) - ) { - val cardType = paymentComponentState.cardType?.txVariant - paymentComponentJson.getJSONObject(PAYMENT_DETAILS_KEY).putOpt(BRAND_KEY, cardType) - } - + override fun onSubmit(state: PaymentComponentState<*>) { var extra: JSONObject? = null - if (paymentComponentState is GooglePayComponentState) { - paymentComponentState.paymentData?.let { + if (state is GooglePayComponentState) { + state.paymentData?.let { extra = JSONObject(it.toJson()) } } + val paymentComponentJson = PaymentComponentData.SERIALIZER.serialize(state.data) val submitMap = SubmitMap(paymentComponentJson, extra) val listener = DropInServiceProxy.shared.serviceListener listener?.onDidSubmit(submitMap.toJSONObject()) ?: Log.e( TAG, "Invalid state: DropInServiceListener is missing" - ) + ) } - override fun onDetailsCallRequested( - actionComponentData: ActionComponentData, - actionComponentJson: JSONObject - ) { + override fun onAdditionalDetails(actionComponentData: ActionComponentData) { val listener = DropInServiceProxy.shared.serviceListener + val actionComponentJson = ActionComponentData.SERIALIZER.serialize(actionComponentData) listener?.onDidProvide(actionComponentJson) ?: Log.e( TAG, "Invalid state: DropInServiceListener is missing" - ) + ) + } + + fun onPaymentsCallRequested( + paymentComponentState: PaymentComponentState<*>, + paymentComponentJson: JSONObject + ) { + if (paymentComponentState is CardComponentState && + paymentComponentJson.getJSONObject(PAYMENT_DETAILS_KEY).isNull(BRAND_KEY) + ) { + val cardType = paymentComponentState.cardBrand?.txVariant + paymentComponentJson.getJSONObject(PAYMENT_DETAILS_KEY).putOpt(BRAND_KEY, cardType) + } } override fun onAction(jsonObject: JSONObject) { diff --git a/android/src/main/java/com/adyenreactnativesdk/component/dropin/AdyenDropInComponent.kt b/android/src/main/java/com/adyenreactnativesdk/component/dropin/AdyenDropInComponent.kt index 2746fe806..0396f2648 100644 --- a/android/src/main/java/com/adyenreactnativesdk/component/dropin/AdyenDropInComponent.kt +++ b/android/src/main/java/com/adyenreactnativesdk/component/dropin/AdyenDropInComponent.kt @@ -11,6 +11,7 @@ import com.adyen.checkout.adyen3ds2.Adyen3DS2Configuration import com.adyen.checkout.bcmc.BcmcConfiguration import com.adyen.checkout.card.CardConfiguration import com.adyen.checkout.dropin.DropIn.startPayment +import com.adyen.checkout.dropin.DropInConfiguration import com.adyen.checkout.dropin.DropInConfiguration.Builder import com.adyen.checkout.googlepay.GooglePayConfiguration import com.adyen.checkout.redirect.RedirectComponent @@ -57,10 +58,12 @@ class AdyenDropInComponent(context: ReactApplicationContext?) : BaseModule(conte } } - val builder = Builder(reactApplicationContext, AdyenCheckoutService::class.java, clientKey) - .setEnvironment(environment) - - parser.locale?.let { builder.setShopperLocale(it) } + val builder: Builder + if (parser.locale != null) { + builder = Builder(parser.locale, reactApplicationContext, environment, clientKey) + } else { + builder = Builder(reactApplicationContext, environment, clientKey) + } configureDropIn(builder, configuration) configureBcmc(builder, configuration) configure3DS(builder) diff --git a/android/src/main/java/com/adyenreactnativesdk/component/instant/GenericPaymentComponentState.kt b/android/src/main/java/com/adyenreactnativesdk/component/instant/GenericPaymentComponentState.kt index b87bbb1d0..3389d63e8 100644 --- a/android/src/main/java/com/adyenreactnativesdk/component/instant/GenericPaymentComponentState.kt +++ b/android/src/main/java/com/adyenreactnativesdk/component/instant/GenericPaymentComponentState.kt @@ -1,13 +1,13 @@ package com.adyenreactnativesdk.component.instant -import com.adyen.checkout.components.model.payments.request.PaymentComponentData -import com.adyen.checkout.components.model.payments.request.PaymentMethodDetails +import com.adyen.checkout.components.core.PaymentComponentData +import com.adyen.checkout.components.core.paymentmethod.PaymentMethodDetails -data class GenericPaymentComponentState( +data class GenericPaymentComponentState( /** * @return The data that was collected by the component. */ - val data: PaymentComponentData, + val data: PaymentComponentData, /** * @return If the component UI data is valid. */ From c5c85decf5772e78b9bdb5d5a99073f00d448ad6 Mon Sep 17 00:00:00 2001 From: Vladimir Abramichev Date: Mon, 20 Nov 2023 16:50:02 +0100 Subject: [PATCH 02/18] chore: update Instant --- .../action/ActionComponentDialogFragment.kt | 171 ----------- .../action/ActionHandler.kt | 276 ------------------ .../component/BaseModule.kt | 7 +- .../component/dropin/AdyenDropInComponent.kt | 8 +- .../instant/AdyenInstantComponent.kt | 84 +++--- .../instant/GenericPaymentComponentState.kt | 24 -- .../component/instant/InstantComponentData.kt | 18 ++ .../component/instant/InstantEvent.kt | 18 ++ .../component/instant/InstantFragment.kt | 152 ++++++++++ .../component/instant/InstantViewModel.kt | 77 +++++ .../component/instant/InstantViewState.kt | 15 + .../ui/PaymentComponentListener.kt | 8 - .../ui/PendingPaymentDialogFragment.kt | 54 ---- .../src/main/res/layout/fragment_instant.xml | 56 ++++ 14 files changed, 376 insertions(+), 592 deletions(-) delete mode 100644 android/src/main/java/com/adyenreactnativesdk/action/ActionComponentDialogFragment.kt delete mode 100644 android/src/main/java/com/adyenreactnativesdk/action/ActionHandler.kt delete mode 100644 android/src/main/java/com/adyenreactnativesdk/component/instant/GenericPaymentComponentState.kt create mode 100644 android/src/main/java/com/adyenreactnativesdk/component/instant/InstantComponentData.kt create mode 100644 android/src/main/java/com/adyenreactnativesdk/component/instant/InstantEvent.kt create mode 100644 android/src/main/java/com/adyenreactnativesdk/component/instant/InstantFragment.kt create mode 100644 android/src/main/java/com/adyenreactnativesdk/component/instant/InstantViewModel.kt create mode 100644 android/src/main/java/com/adyenreactnativesdk/component/instant/InstantViewState.kt delete mode 100644 android/src/main/java/com/adyenreactnativesdk/ui/PaymentComponentListener.kt delete mode 100644 android/src/main/java/com/adyenreactnativesdk/ui/PendingPaymentDialogFragment.kt create mode 100644 android/src/main/res/layout/fragment_instant.xml diff --git a/android/src/main/java/com/adyenreactnativesdk/action/ActionComponentDialogFragment.kt b/android/src/main/java/com/adyenreactnativesdk/action/ActionComponentDialogFragment.kt deleted file mode 100644 index de6422c3f..000000000 --- a/android/src/main/java/com/adyenreactnativesdk/action/ActionComponentDialogFragment.kt +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2022 Adyen N.V. - * - * This file is open source and available under the MIT license. See the LICENSE file for more info. - */ - -package com.adyenreactnativesdk.action - -import android.content.DialogInterface -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.lifecycle.Observer -import com.adyen.checkout.components.* -import com.adyen.checkout.components.core.ActionComponentData -import com.adyen.checkout.components.core.ComponentError -import com.adyen.checkout.components.core.action.Action -import com.adyen.checkout.components.core.internal.ActionComponent -import com.adyen.checkout.components.core.internal.ui.model.OutputData -import com.adyen.checkout.core.exception.CheckoutException -import com.adyen.checkout.core.exception.ComponentException -import com.adyen.checkout.core.internal.util.Logger -import com.adyen.checkout.ui.core.internal.ui.ComponentView -import com.adyen.checkout.ui.core.internal.ui.ViewableComponent - -import com.google.android.material.bottomsheet.BottomSheetDialogFragment - -class ActionComponentDialogFragment( - private val configuration: ActionHandlerConfiguration, - private val callback: ActionHandlingInterface -) : BottomSheetDialogFragment(), Observer { - - companion object { - private val TAG = "ActionComponentDialogFragment" - const val ACTION = "ACTION" - } - - private var isCanceled = false - private lateinit var binding: FragmentActionComponentBinding - private lateinit var action: Action - private lateinit var actionType: String - private lateinit var componentView: ComponentView> - private lateinit var actionComponent: ViewableComponent<*, *, ActionComponentData> - private var isHandled = true - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - Logger.d(TAG, "onCreate") - action = - arguments?.getParcelable(ACTION) ?: throw IllegalArgumentException("Action not found") - actionType = action.type ?: throw IllegalArgumentException("Action type not found") - } - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? - ): View { - binding = FragmentActionComponentBinding.inflate(inflater) - isCanceled = false - return binding.root - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - Logger.d(TAG, "onViewCreated") - binding.header.visibility = View.GONE - - try { - @Suppress("UNCHECKED_CAST") - componentView = ActionHandler.getViewFor( - requireContext(), - actionType - ) as ComponentView> - actionComponent = getComponent(action) - attachComponent(actionComponent, componentView) - - if (shouldFinishWithAction()) { - with(binding.buttonFinish) { -// isVisible = true - setOnClickListener { callback.onFinish() } - } - } - - if (!isHandled) { - (actionComponent as ActionComponent<*>).handleAction(requireActivity(), action) - isHandled = true - } else { - Logger.d(TAG, "action already handled") - } - } catch (e: CheckoutException) { - handleError(ComponentError(e)) - } - } - - override fun onDismiss(dialog: DialogInterface) { - super.onDismiss(dialog) - if (isCanceled) { - callback.onError(CheckoutException("Cancelled")) - } - } - - override fun onCancel(dialog: DialogInterface) { - super.onCancel(dialog) - isCanceled = true - Logger.d(TAG, "onCancel") - callback.onClose() - } - - override fun onChanged(actionComponentData: ActionComponentData?) { - Logger.d(TAG, "onChanged") - if (actionComponentData != null) { - callback.provide(actionComponentData) - } - } - - fun setToHandleWhenStarting() { - Logger.d(TAG, "setToHandleWhenStarting") - isHandled = false - } - - /** - * Return the possible viewable action components - */ - @SuppressWarnings("ThrowsCount") - private fun getComponent(action: Action): ViewableComponent<*, *, ActionComponentData> { - val provider = ActionHandler.getActionProviderFor(action) - ?: throw ComponentException("Unexpected Action component type - $actionType") - if (!provider.requiresView(action)) { - throw ComponentException("Action is not viewable - action: ${action.type} - paymentMethod: ${action.paymentMethodType}") - } - val component = - ActionHandler.getActionComponentFor(requireActivity(), null, provider, configuration) - if (!component.canHandleAction(action)) { - throw ComponentException("Unexpected Action component type - action: ${action.type} - paymentMethod: ${action.paymentMethodType}") - } - - @Suppress("UNCHECKED_CAST") - return component as ViewableComponent<*, *, ActionComponentData> - } - - private fun attachComponent( - component: ViewableComponent<*, *, ActionComponentData>, - componentView: ComponentView> - ) { - component.observe(viewLifecycleOwner, this) - component.observeErrors(viewLifecycleOwner, createErrorHandlerObserver()) - binding.componentContainer.addView(componentView as View) - @Suppress("UNCHECKED_CAST") - componentView.attach(component, viewLifecycleOwner) - } - - private fun createErrorHandlerObserver(): Observer { - return Observer { - if (it != null) { - handleError(it) - } - } - } - - private fun handleError(componentError: ComponentError) { - Logger.e(TAG, componentError.errorMessage) - callback.onError(componentError.exception) - } - - private fun shouldFinishWithAction(): Boolean { - return ActionHandler.getActionProviderFor(action)?.providesDetails() == false - } - -} diff --git a/android/src/main/java/com/adyenreactnativesdk/action/ActionHandler.kt b/android/src/main/java/com/adyenreactnativesdk/action/ActionHandler.kt deleted file mode 100644 index 41b13d570..000000000 --- a/android/src/main/java/com/adyenreactnativesdk/action/ActionHandler.kt +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright (c) 2022 Adyen N.V. - * - * This file is open source and available under the MIT license. See the LICENSE file for more info. - */ - -package com.adyenreactnativesdk.action - -import android.content.Context -import android.content.Intent -import android.util.Log -import androidx.fragment.app.DialogFragment -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentActivity -import androidx.lifecycle.Observer -import com.adyen.checkout.adyen3ds2.Adyen3DS2Component -import com.adyen.checkout.adyen3ds2.Adyen3DS2Configuration -import com.adyen.checkout.await.AwaitComponent -import com.adyen.checkout.await.AwaitConfiguration -import com.adyen.checkout.await.AwaitView -import com.adyen.checkout.components.ActionComponentData -import com.adyen.checkout.components.ActionComponentProvider -import com.adyen.checkout.components.ComponentView -import com.adyen.checkout.components.ViewableComponent -import com.adyen.checkout.components.base.* -import com.adyen.checkout.components.model.payments.response.Action -import com.adyen.checkout.components.util.ActionTypes -import com.adyen.checkout.core.api.Environment -import com.adyen.checkout.core.exception.CheckoutException -import com.adyen.checkout.core.log.LogUtil -import com.adyen.checkout.qrcode.QRCodeComponent -import com.adyen.checkout.qrcode.QRCodeConfiguration -import com.adyen.checkout.qrcode.QRCodeView -import com.adyen.checkout.redirect.RedirectComponent -import com.adyen.checkout.redirect.RedirectConfiguration -import com.adyen.checkout.voucher.VoucherComponent -import com.adyen.checkout.voucher.VoucherConfiguration -import com.adyen.checkout.voucher.VoucherView -import com.adyen.checkout.wechatpay.WeChatPayActionComponent -import com.adyen.checkout.wechatpay.WeChatPayActionConfiguration -import com.adyenreactnativesdk.AdyenCheckout -import com.adyenreactnativesdk.BuildConfig -import com.adyenreactnativesdk.ui.Cancelable -import com.adyenreactnativesdk.ui.PendingPaymentDialogFragment -import java.lang.ref.WeakReference -import java.util.* - -class ActionHandlerConfiguration( - val shopperLocale: Locale, - val environment: Environment, - val clientKey: String -) - -interface ActionHandlingInterface { - // Same signature as the Fragment Protocol interface - fun provide(actionComponentData: ActionComponentData) - fun onError(error: Exception) - fun onClose() - fun onFinish() -} - -class ActionHandler( - private val callback: ActionHandlingInterface, - private val configuration: ActionHandlerConfiguration -) : Observer, - Cancelable { - - private var dialog: WeakReference = WeakReference(null) - private var loadedComponent: BaseActionComponent<*>? = null - private var loadedAction: Action? = null - - override fun onChanged(componentData: ActionComponentData?) { - if (componentData != null) { - callback.provide(componentData) - } - } - - private var pendingPaymentDialogFragment : PendingPaymentDialogFragment? = null - - fun handleAction(activity: FragmentActivity, action: Action) { - Log.d(TAG, "handleAction - ${action.type}") - val provider = getActionProviderFor(action) - if (provider == null) { - Log.e(TAG, "Unknown Action - ${action.type}") - return - } - - loadedAction = action - - activity.runOnUiThread { - if (provider.requiresView(action)) { - val actionFragment = ActionComponentDialogFragment(configuration, callback) - actionFragment.show(activity.supportFragmentManager, ACTION_FRAGMENT_TAG) - actionFragment.setToHandleWhenStarting() - dialog = WeakReference(actionFragment) - } else { - pendingPaymentDialogFragment = PendingPaymentDialogFragment.newInstance() - pendingPaymentDialogFragment?.cancelable = this - pendingPaymentDialogFragment?.showNow(activity.supportFragmentManager, TAG) - loadComponent(pendingPaymentDialogFragment, activity, provider) - loadedComponent?.handleAction(activity, action) - } - } - } - - fun hide(activity: FragmentActivity) { - dialog.get()?.dismiss() - dialog.clear() - loadedComponent = null - pendingPaymentDialogFragment?.dismiss() - pendingPaymentDialogFragment = null - } - - override fun canceled() { - callback.onClose() - } - - private fun loadComponent( - fragment: Fragment?, - activity: FragmentActivity, - provider: ActionComponentProvider, out Configuration> - ) { - getActionComponentFor(activity, fragment, provider, configuration).apply { - loadedComponent = this - observe(activity, this@ActionHandler) - observeErrors(activity) { callback.onError(it.exception) } - Log.d(TAG, "handleAction - loaded a new component - ${this::class.java.simpleName}") - } - } - - companion object { - private val TAG = LogUtil.getTag() - const val ACTION_FRAGMENT_TAG = "ACTION_DIALOG_FRAGMENT" - internal const val REDIRECT_RESULT_SCHEME = BuildConfig.adyenReactNativeRedirectScheme + "://" - - internal fun getReturnUrl(context: Context): String { - return REDIRECT_RESULT_SCHEME + context.packageName - } - - @JvmStatic - @Deprecated( - message = "This method is deprecated on beta-8", - replaceWith = ReplaceWith("AdyenCheckout.handleIntent(intent)")) - fun handleIntent(intent: Intent) { - AdyenCheckout.handleIntent(intent) - } - - private inline fun getDefaultConfigForAction( - configuration: ActionHandlerConfiguration - ): T { - val shopperLocale = configuration.shopperLocale - val environment = configuration.environment - val clientKey = configuration.clientKey - - // get default builder for Configuration type - val builder: BaseConfigurationBuilder = when (T::class) { - AwaitConfiguration::class -> AwaitConfiguration.Builder( - shopperLocale, - environment, - clientKey - ) - RedirectConfiguration::class -> RedirectConfiguration.Builder( - shopperLocale, - environment, - clientKey - ) - QRCodeConfiguration::class -> QRCodeConfiguration.Builder( - shopperLocale, - environment, - clientKey - ) - Adyen3DS2Configuration::class -> Adyen3DS2Configuration.Builder( - shopperLocale, - environment, - clientKey - ) - WeChatPayActionConfiguration::class -> WeChatPayActionConfiguration.Builder( - shopperLocale, - environment, - clientKey - ) - VoucherConfiguration::class -> VoucherConfiguration.Builder( - shopperLocale, - environment, - clientKey - ) - else -> throw CheckoutException("Unable to find component configuration for class - ${T::class}") - } - - @Suppress("UNCHECKED_CAST") - return builder.build() as T - } - - internal fun getActionProviderFor(action: Action): ActionComponentProvider, out Configuration>? { - val allActionProviders = listOf( - RedirectComponent.PROVIDER, - Adyen3DS2Component.PROVIDER, - WeChatPayActionComponent.PROVIDER, - AwaitComponent.PROVIDER, - QRCodeComponent.PROVIDER, - VoucherComponent.PROVIDER - ) - return allActionProviders.firstOrNull { it.canHandleAction(action) } - } - - internal fun getActionComponentFor( - activity: FragmentActivity, - fragment: Fragment?, - provider: ActionComponentProvider, out Configuration>, - configuration: ActionHandlerConfiguration - ): BaseActionComponent { - var lifecycleOwner = fragment ?: activity - val actionComponent = when (provider) { - RedirectComponent.PROVIDER -> { - RedirectComponent.PROVIDER.get( - lifecycleOwner, - activity.application, - getDefaultConfigForAction(configuration) - ) - } - Adyen3DS2Component.PROVIDER -> { - Adyen3DS2Component.PROVIDER.get( - lifecycleOwner, - activity.application, - getDefaultConfigForAction(configuration) - ) - } - WeChatPayActionComponent.PROVIDER -> { - WeChatPayActionComponent.PROVIDER.get( - lifecycleOwner, - activity.application, - getDefaultConfigForAction(configuration) - ) - } - AwaitComponent.PROVIDER -> { - AwaitComponent.PROVIDER.get( - lifecycleOwner, - activity.application, - getDefaultConfigForAction(configuration) - ) - } - QRCodeComponent.PROVIDER -> { - QRCodeComponent.PROVIDER.get( - lifecycleOwner, - activity.application, - getDefaultConfigForAction(configuration) - ) - } - else -> { - throw CheckoutException("Unable to find component for provider - $provider") - } - } - - if (actionComponent is IntentHandlingComponent) - AdyenCheckout.setIntentHandler(actionComponent) - - return actionComponent - } - - internal fun getViewFor( - context: Context, - paymentType: String - ): ComponentView> { - @Suppress("UNCHECKED_CAST") - return when (paymentType) { - ActionTypes.AWAIT -> AwaitView(context) - ActionTypes.QR_CODE -> QRCodeView(context) - ActionTypes.VOUCHER -> VoucherView(context) - else -> { - throw CheckoutException("Unable to find view for type - $paymentType") - } - // TODO check if this generic approach can be improved - } as ComponentView> - } - } -} diff --git a/android/src/main/java/com/adyenreactnativesdk/component/BaseModule.kt b/android/src/main/java/com/adyenreactnativesdk/component/BaseModule.kt index 4d43da688..f35125738 100644 --- a/android/src/main/java/com/adyenreactnativesdk/component/BaseModule.kt +++ b/android/src/main/java/com/adyenreactnativesdk/component/BaseModule.kt @@ -8,9 +8,8 @@ package com.adyenreactnativesdk.component import android.content.Context import android.os.Build import androidx.appcompat.app.AppCompatActivity -import com.adyen.checkout.components.model.PaymentMethodsApiResponse -import com.adyen.checkout.components.model.paymentmethods.PaymentMethod -import com.adyenreactnativesdk.action.ActionHandler +import com.adyen.checkout.components.core.PaymentMethod +import com.adyen.checkout.components.core.PaymentMethodsApiResponse import com.adyenreactnativesdk.util.ReactNativeError import com.adyenreactnativesdk.util.ReactNativeJson import com.facebook.react.bridge.ReactApplicationContext @@ -23,8 +22,6 @@ import java.util.* abstract class BaseModule(context: ReactApplicationContext?) : ReactContextBaseJavaModule(context) { - protected var actionHandler: ActionHandler? = null - protected fun sendEvent(eventName: String, map: ReadableMap?) { reactApplicationContext .getJSModule(RCTDeviceEventEmitter::class.java) diff --git a/android/src/main/java/com/adyenreactnativesdk/component/dropin/AdyenDropInComponent.kt b/android/src/main/java/com/adyenreactnativesdk/component/dropin/AdyenDropInComponent.kt index 0396f2648..ea3177a2d 100644 --- a/android/src/main/java/com/adyenreactnativesdk/component/dropin/AdyenDropInComponent.kt +++ b/android/src/main/java/com/adyenreactnativesdk/component/dropin/AdyenDropInComponent.kt @@ -76,14 +76,14 @@ class AdyenDropInComponent(context: ReactApplicationContext?) : BaseModule(conte } configureCards(builder, configuration, countryCode) val currentActivity = reactApplicationContext.currentActivity - val resultIntent = Intent(currentActivity, currentActivity!!.javaClass) - resultIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + // val resultIntent = Intent(currentActivity, currentActivity!!.javaClass) + // resultIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) AdyenCheckout.addDropInListener(this) AdyenCheckout.dropInLauncher?.let { - startPayment(currentActivity, it, paymentMethodsResponse, builder.build(), resultIntent) + startPayment(currentActivity, it, paymentMethodsResponse, builder.build(), AdyenCheckoutService::class.java) } ?: run { - startPayment(currentActivity, paymentMethodsResponse, builder.build(), resultIntent) + startPayment(currentActivity, paymentMethodsResponse, builder.build(), AdyenCheckoutService::class.java) } } diff --git a/android/src/main/java/com/adyenreactnativesdk/component/instant/AdyenInstantComponent.kt b/android/src/main/java/com/adyenreactnativesdk/component/instant/AdyenInstantComponent.kt index 54294cf43..4f37d68be 100644 --- a/android/src/main/java/com/adyenreactnativesdk/component/instant/AdyenInstantComponent.kt +++ b/android/src/main/java/com/adyenreactnativesdk/component/instant/AdyenInstantComponent.kt @@ -1,28 +1,27 @@ package com.adyenreactnativesdk.component.instant -import com.adyen.checkout.components.ActionComponentData -import com.adyen.checkout.components.model.payments.request.GenericPaymentMethod -import com.adyen.checkout.components.model.payments.request.PaymentComponentData -import com.adyen.checkout.components.model.payments.request.PaymentMethodDetails -import com.adyen.checkout.components.model.payments.response.Action +import android.content.Context +import com.adyen.checkout.components.core.ActionComponentData +import com.adyen.checkout.components.core.ComponentCallback +import com.adyen.checkout.components.core.ComponentError +import com.adyen.checkout.components.core.PaymentComponentData +import com.adyen.checkout.components.core.action.Action +import com.adyen.checkout.instant.InstantComponentState +import com.adyen.checkout.instant.InstantPaymentConfiguration import com.adyenreactnativesdk.AdyenCheckout -import com.adyenreactnativesdk.action.ActionHandler -import com.adyenreactnativesdk.action.ActionHandlerConfiguration -import com.adyenreactnativesdk.action.ActionHandlingInterface import com.adyenreactnativesdk.component.BaseModule import com.adyenreactnativesdk.component.BaseModuleException import com.adyenreactnativesdk.component.model.SubmitMap -import com.adyenreactnativesdk.ui.PaymentComponentListener import com.adyenreactnativesdk.configuration.RootConfigurationParser import com.adyenreactnativesdk.util.AdyenConstants import com.adyenreactnativesdk.util.ReactNativeJson +import com.adyenreactnativesdk.BuildConfig import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReactMethod import com.facebook.react.bridge.ReadableMap import org.json.JSONException -class AdyenInstantComponent(context: ReactApplicationContext?) : BaseModule(context), - PaymentComponentListener, ActionHandlingInterface { +class AdyenInstantComponent(context: ReactApplicationContext?) : BaseModule(context), ComponentCallback { override fun getName(): String { return COMPONENT_NAME @@ -46,21 +45,20 @@ class AdyenInstantComponent(context: ReactApplicationContext?) : BaseModule(cont val config = RootConfigurationParser(configuration) val environment = config.environment - val clientKey: String - config.clientKey.let { - clientKey = if (it != null) it else { + val amount = config.amount + val clientKey = config.clientKey.let { + if (it != null) it else { sendErrorEvent(BaseModuleException.NoClientKey()) return } } + // TODO: add .setAnalyticsConfiguration(getAnalyticsConfiguration()) val shopperLocale = config.locale ?: currentLocale(reactApplicationContext) - - val actionHandlerConfiguration = - ActionHandlerConfiguration(shopperLocale, environment, clientKey) - actionHandler = ActionHandler(this, actionHandlerConfiguration) - - sendPayment(type) + val instantPaymentConfiguration = InstantPaymentConfiguration.Builder(shopperLocale, environment, clientKey) + .setAmount(amount) + .build() + InstantFragment.show(appCompatActivity.supportFragmentManager, instantPaymentConfiguration, type) } @ReactMethod @@ -68,7 +66,7 @@ class AdyenInstantComponent(context: ReactApplicationContext?) : BaseModule(cont try { val jsonObject = ReactNativeJson.convertMapToJson(actionMap) val action = Action.SERIALIZER.deserialize(jsonObject) - actionHandler?.handleAction(appCompatActivity, action) + InstantFragment.handle(appCompatActivity.supportFragmentManager, action) } catch (e: JSONException) { sendErrorEvent(BaseModuleException.InvalidAction(e)) } @@ -77,50 +75,36 @@ class AdyenInstantComponent(context: ReactApplicationContext?) : BaseModule(cont @ReactMethod fun hide(success: Boolean?, message: ReadableMap?) { appCompatActivity.runOnUiThread { - actionHandler?.hide(appCompatActivity) - actionHandler = null + InstantFragment.hide(appCompatActivity.supportFragmentManager) AdyenCheckout.removeIntentHandler() } } - override fun onError(error: Exception) { - sendErrorEvent(error) - } - - override fun onSubmit(data: PaymentComponentData<*>) { - val jsonObject = PaymentComponentData.SERIALIZER.serialize(data) - jsonObject.put(AdyenConstants.PARAMETER_RETURN_URL, ActionHandler.getReturnUrl(reactApplicationContext)) - val submitMap = SubmitMap(jsonObject, null) - sendEvent(DID_SUBMIT, submitMap.toJSONObject()) - } - - override fun provide(actionComponentData: ActionComponentData) { + override fun onAdditionalDetails(actionComponentData: ActionComponentData) { val jsonObject = ActionComponentData.SERIALIZER.serialize(actionComponentData) sendEvent(DID_PROVIDE, jsonObject) } - override fun onClose() { - sendErrorEvent(BaseModuleException.Canceled()) - } - - override fun onFinish() { - sendEvent(DID_COMPLETE, null) + override fun onError(componentError: ComponentError) { + sendErrorEvent(componentError.exception) } - private fun sendPayment(type: String) { - val paymentComponentData = PaymentComponentData() - paymentComponentData.paymentMethod = GenericPaymentMethod(type) - val paymentComponentState = GenericPaymentComponentState( - paymentComponentData, - isInputValid = true, - isReady = true - ) - onSubmit(paymentComponentState.data) + override fun onSubmit(state: InstantComponentState) { + val jsonObject = PaymentComponentData.SERIALIZER.serialize(state.data) + val returnUrl = getReturnUrl(reactApplicationContext) + jsonObject.put(AdyenConstants.PARAMETER_RETURN_URL, returnUrl) + val submitMap = SubmitMap(jsonObject, null) + sendEvent(DID_SUBMIT, submitMap.toJSONObject()) } companion object { private const val TAG = "InstantComponent" private const val COMPONENT_NAME = "AdyenInstant" + internal const val REDIRECT_RESULT_SCHEME = BuildConfig.adyenReactNativeRedirectScheme + "://" + internal fun getReturnUrl(context: Context): String { + return REDIRECT_RESULT_SCHEME + context.packageName + } } + } diff --git a/android/src/main/java/com/adyenreactnativesdk/component/instant/GenericPaymentComponentState.kt b/android/src/main/java/com/adyenreactnativesdk/component/instant/GenericPaymentComponentState.kt deleted file mode 100644 index 3389d63e8..000000000 --- a/android/src/main/java/com/adyenreactnativesdk/component/instant/GenericPaymentComponentState.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.adyenreactnativesdk.component.instant - -import com.adyen.checkout.components.core.PaymentComponentData -import com.adyen.checkout.components.core.paymentmethod.PaymentMethodDetails - -data class GenericPaymentComponentState( - /** - * @return The data that was collected by the component. - */ - val data: PaymentComponentData, - /** - * @return If the component UI data is valid. - */ - private val isInputValid: Boolean, - private val isReady: Boolean -) { - - /** - * @return If the collected data is valid to be sent to the backend. - */ - val isValid: Boolean - get() = isInputValid && isReady - -} \ No newline at end of file diff --git a/android/src/main/java/com/adyenreactnativesdk/component/instant/InstantComponentData.kt b/android/src/main/java/com/adyenreactnativesdk/component/instant/InstantComponentData.kt new file mode 100644 index 000000000..8228cef54 --- /dev/null +++ b/android/src/main/java/com/adyenreactnativesdk/component/instant/InstantComponentData.kt @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by josephj on 30/1/2023. + */ + +package com.adyenreactnativesdk.component.instant + +import com.adyen.checkout.components.core.ComponentCallback +import com.adyen.checkout.components.core.PaymentMethod +import com.adyen.checkout.instant.InstantComponentState + +internal data class InstantComponentData( + val paymentMethod: PaymentMethod, + val callback: ComponentCallback, +) diff --git a/android/src/main/java/com/adyenreactnativesdk/component/instant/InstantEvent.kt b/android/src/main/java/com/adyenreactnativesdk/component/instant/InstantEvent.kt new file mode 100644 index 000000000..97e8fa820 --- /dev/null +++ b/android/src/main/java/com/adyenreactnativesdk/component/instant/InstantEvent.kt @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2023 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ozgur on 3/1/2023. + */ + +package com.adyenreactnativesdk.component.instant + +import com.adyen.checkout.components.core.action.Action + +internal sealed class InstantEvent { + + data class PaymentResult(val result: String) : InstantEvent() + + data class AdditionalAction(val action: Action) : InstantEvent() +} diff --git a/android/src/main/java/com/adyenreactnativesdk/component/instant/InstantFragment.kt b/android/src/main/java/com/adyenreactnativesdk/component/instant/InstantFragment.kt new file mode 100644 index 000000000..48baf3bd5 --- /dev/null +++ b/android/src/main/java/com/adyenreactnativesdk/component/instant/InstantFragment.kt @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2023 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ozgur on 3/1/2023. + */ + +package com.adyenreactnativesdk.component.instant + +import android.content.Intent +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.Toast +import androidx.core.os.bundleOf +import androidx.core.view.isVisible +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.viewModels +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import com.adyen.checkout.components.core.action.Action +import com.adyen.checkout.instant.InstantPaymentComponent +import com.adyen.checkout.instant.InstantPaymentConfiguration +import com.adyen.checkout.redirect.RedirectComponent +import com.adyenreactnativesdk.databinding.FragmentInstantBinding +import com.google.android.material.bottomsheet.BottomSheetDialogFragment +import kotlinx.coroutines.launch + +class InstantFragment(private val configuration: InstantPaymentConfiguration) : BottomSheetDialogFragment() { + + private var _binding: FragmentInstantBinding? = null + private val binding: FragmentInstantBinding + get() = requireNotNull(_binding) + + private var instantPaymentComponent: InstantPaymentComponent? = null + + private val instantViewModel: InstantViewModel by viewModels() + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { + // Insert return url in extras, so we can access it in the ViewModel through SavedStateHandle + val returnUrl = RedirectComponent.getReturnUrl(requireActivity().applicationContext) + RETURN_URL_PATH + arguments = (arguments ?: bundleOf()).apply { + putString(RETURN_URL_EXTRA, returnUrl) + } + _binding = FragmentInstantBinding.inflate(inflater, container, false) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + viewLifecycleOwner.lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + launch { instantViewModel.instantComponentDataFlow.collect(::setupInstantComponent) } + launch { instantViewModel.events.collect(::onEvent) } + launch { instantViewModel.instantViewState.collect(::onViewState) } + } + } + } + + fun onNewIntent(intent: Intent) { + instantPaymentComponent?.handleIntent(intent) + } + + private fun setupInstantComponent(componentData: InstantComponentData) { + val instantPaymentComponent = InstantPaymentComponent.PROVIDER.get( + this, + componentData.paymentMethod, + configuration, + componentData.callback, + ) + + this.instantPaymentComponent = instantPaymentComponent + binding.componentView.attach(instantPaymentComponent, viewLifecycleOwner) + } + + private fun onEvent(event: InstantEvent) { + when (event) { + is InstantEvent.AdditionalAction -> { + onAction(event.action) + } + is InstantEvent.PaymentResult -> { + onPaymentResult(event.result) + } + } + } + + private fun onPaymentResult(result: String) { + Toast.makeText(requireContext(), result, Toast.LENGTH_SHORT).show() + dismiss() + } + + private fun onViewState(viewState: InstantViewState) { + when (viewState) { + is InstantViewState.Error -> { + binding.errorView.isVisible = true + binding.errorView.text = viewState.errorMessage + binding.progressIndicator.isVisible = false + binding.componentContainer.isVisible = false + } + is InstantViewState.Loading -> { + binding.progressIndicator.isVisible = true + binding.errorView.isVisible = false + binding.componentContainer.isVisible = false + } + is InstantViewState.ShowComponent -> { + binding.progressIndicator.isVisible = false + binding.errorView.isVisible = false + binding.componentContainer.isVisible = true + } + } + } + + private fun onAction(action: Action) { + instantPaymentComponent?.handleAction(action, requireActivity()) + } + + override fun onDestroyView() { + super.onDestroyView() + instantPaymentComponent = null + _binding = null + } + + companion object { + + internal const val TAG = "InstantFragment" + internal const val PAYMENT_METHOD_TYPE_EXTRA = "PAYMENT_METHOD_TYPE_EXTRA" + internal const val RETURN_URL_EXTRA = "RETURN_URL_EXTRA" + internal const val RETURN_URL_PATH = "/instant" + + fun show(fragmentManager: FragmentManager, configuration: InstantPaymentConfiguration, paymentMethodType: String) { + InstantFragment(configuration).apply { + arguments = bundleOf( + PAYMENT_METHOD_TYPE_EXTRA to paymentMethodType + ) + }.show(fragmentManager, TAG) + } + + fun handle(fragmentManager: FragmentManager, action: Action) { + val fragment = fragmentManager.findFragmentByTag(TAG) as InstantFragment + fragment.instantViewModel.handle(action) + } + + fun hide(fragmentManager: FragmentManager) { + val fragment = fragmentManager.findFragmentByTag(TAG) as InstantFragment + fragment.dismiss() + } + } +} diff --git a/android/src/main/java/com/adyenreactnativesdk/component/instant/InstantViewModel.kt b/android/src/main/java/com/adyenreactnativesdk/component/instant/InstantViewModel.kt new file mode 100644 index 000000000..8f3ef6127 --- /dev/null +++ b/android/src/main/java/com/adyenreactnativesdk/component/instant/InstantViewModel.kt @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ozgur on 3/1/2023. + */ + +package com.adyenreactnativesdk.component.instant + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.adyen.checkout.components.core.ActionComponentData +import com.adyen.checkout.components.core.ComponentCallback +import com.adyen.checkout.components.core.ComponentError +import com.adyen.checkout.components.core.action.Action +import com.adyen.checkout.instant.InstantComponentState +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.launch + +internal class InstantViewModel(private val callback: ComponentCallback) : ViewModel(), ComponentCallback { + + private val _instantComponentDataFlow = MutableStateFlow(null) + val instantComponentDataFlow: Flow = _instantComponentDataFlow.filterNotNull() + + private val _instantViewState = MutableStateFlow(InstantViewState.Loading) + val instantViewState: Flow = _instantViewState + + private val _events = MutableSharedFlow() + val events: Flow = _events + + override fun onSubmit(state: InstantComponentState) { + _instantViewState.tryEmit(InstantViewState.Loading) + callback.onSubmit(state) + } + + override fun onAdditionalDetails(actionComponentData: ActionComponentData) { + callback.onAdditionalDetails(actionComponentData) + } + + override fun onError(componentError: ComponentError) { + onComponentError(componentError) + callback.onError(componentError) + } + + fun handle(action: Action) { + viewModelScope.launch(Dispatchers.IO) { + _instantViewState.tryEmit(InstantViewState.ShowComponent) + _events.emit(InstantEvent.AdditionalAction(action)) + } + } + + private fun onComponentError(error: ComponentError) { + viewModelScope.launch { _events.emit(InstantEvent.PaymentResult("Failed: ${error.errorMessage}")) } + } +} + +/* + + private suspend fun handlePaymentResponse(json: JSONObject?) { + json?.let { + when { + json.has("action") -> { + val action = Action.SERIALIZER.deserialize(json.getJSONObject("action")) + _instantViewState.tryEmit(InstantViewState.ShowComponent) + _events.emit(InstantEvent.AdditionalAction(action)) + } + else -> _events.emit(InstantEvent.PaymentResult("Finished: ${json.optString("resultCode")}")) + } + } ?: _events.emit(InstantEvent.PaymentResult("Failed")) + } + + */ diff --git a/android/src/main/java/com/adyenreactnativesdk/component/instant/InstantViewState.kt b/android/src/main/java/com/adyenreactnativesdk/component/instant/InstantViewState.kt new file mode 100644 index 000000000..1efe91650 --- /dev/null +++ b/android/src/main/java/com/adyenreactnativesdk/component/instant/InstantViewState.kt @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2023 Adyen N.V. + * + * This file is open source and available under the MIT license. See the LICENSE file for more info. + * + * Created by ozgur on 4/1/2023. + */ + +package com.adyenreactnativesdk.component.instant + +sealed class InstantViewState { + object Loading : InstantViewState() + class Error(val errorMessage: String) : InstantViewState() + object ShowComponent : InstantViewState() +} diff --git a/android/src/main/java/com/adyenreactnativesdk/ui/PaymentComponentListener.kt b/android/src/main/java/com/adyenreactnativesdk/ui/PaymentComponentListener.kt deleted file mode 100644 index 71df91cc0..000000000 --- a/android/src/main/java/com/adyenreactnativesdk/ui/PaymentComponentListener.kt +++ /dev/null @@ -1,8 +0,0 @@ -package com.adyenreactnativesdk.ui - -import com.adyen.checkout.components.model.payments.request.PaymentComponentData - -interface PaymentComponentListener { - fun onError(exception: Exception) - fun onSubmit(data: PaymentComponentData<*>) -} \ No newline at end of file diff --git a/android/src/main/java/com/adyenreactnativesdk/ui/PendingPaymentDialogFragment.kt b/android/src/main/java/com/adyenreactnativesdk/ui/PendingPaymentDialogFragment.kt deleted file mode 100644 index 253db1ac1..000000000 --- a/android/src/main/java/com/adyenreactnativesdk/ui/PendingPaymentDialogFragment.kt +++ /dev/null @@ -1,54 +0,0 @@ -package com.adyenreactnativesdk.ui - -import android.graphics.Color -import android.graphics.drawable.ColorDrawable -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.View.INVISIBLE -import android.view.View.VISIBLE -import android.view.ViewGroup -import android.widget.Button -import android.widget.ProgressBar -import androidx.core.view.isVisible -import androidx.fragment.app.DialogFragment -import com.adyenreactnativesdk.R - -interface Cancelable { - fun canceled() -} - -class PendingPaymentDialogFragment() : DialogFragment() { - - var cancelable: Cancelable? = null - - override fun onDestroy() { - super.onDestroy() - cancelable = null - } - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - isCancelable = false - return inflater.inflate(R.layout.pending_payment, container, false) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - requireDialog().window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) - - val progress = view.findViewById(R.id.progressBar) - progress.isVisible = cancelable != null - - val button = view.findViewById