react-native-hyperswitch-dev-sdk 0.4.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.
- package/HyperswitchSdkReactNative.podspec +42 -0
- package/LICENSE +201 -0
- package/android/build.gradle +161 -0
- package/android/gradle.properties +5 -0
- package/android/hyperswitch_autolinking.gradle +378 -0
- package/android/proguard-rules.pro +72 -0
- package/android/src/legacy/java/com/facebook/react/viewmanagers/GooglePayButtonManagerDelegate.java +41 -0
- package/android/src/legacy/java/com/facebook/react/viewmanagers/GooglePayButtonManagerInterface.java +20 -0
- package/android/src/legacy/java/com/facebook/react/viewmanagers/NativePaymentWidgetManagerDelegate.java +38 -0
- package/android/src/legacy/java/com/facebook/react/viewmanagers/NativePaymentWidgetManagerInterface.java +21 -0
- package/android/src/legacy/java/com/hyperswitchsdkreactnative/NativeHyperswitchSdkNativeSpec.java +106 -0
- package/android/src/legacy/java/com/hyperswitchsdkreactnative/NativeHyperswitchSdkReactNativeSpec.java +77 -0
- package/android/src/legacy/java/com/hyperswitchsdkreactnative/NativePaymentWidgetNativeSpec.java +36 -0
- package/android/src/main/AndroidManifest.xml +15 -0
- package/android/src/main/assets/hyperswitch.bundle +1535 -0
- package/android/src/main/java/com/hyperswitchsdkreactnative/HyperswitchSdkReactNativePackage.kt +47 -0
- package/android/src/main/java/com/hyperswitchsdkreactnative/modules/NativePaymentWidgetModule.kt +173 -0
- package/android/src/main/java/com/hyperswitchsdkreactnative/modules/ReactNativeHyperswitchModule.kt +396 -0
- package/android/src/main/java/com/hyperswitchsdkreactnative/views/PaymentElementViewManager.kt +99 -0
- package/android/src/main/java/io/hyperswitch/HyperswitchReactPackageProvider.kt +19 -0
- package/android/src/main/java/io/hyperswitch/PaymentEventType.kt +18 -0
- package/android/src/main/java/io/hyperswitch/model/ElementConfiguration.kt +58 -0
- package/android/src/main/java/io/hyperswitch/paymentsession/ExitHeadlessCallBackManager.kt +47 -0
- package/android/src/main/java/io/hyperswitch/paymentsession/GetPaymentSessionCallBackManager.kt +23 -0
- package/android/src/main/java/io/hyperswitch/paymentsession/PaymentMethod.kt +167 -0
- package/android/src/main/java/io/hyperswitch/paymentsession/PaymentSessionHandler.kt +68 -0
- package/android/src/main/java/io/hyperswitch/paymentsession/PaymentSessionHandlerImpl.kt +179 -0
- package/android/src/main/java/io/hyperswitch/paymentsession/PaymentSessionReactLauncher.kt +226 -0
- package/android/src/main/java/io/hyperswitch/paymentsession/PaymentSheetCallbackManager.kt +40 -0
- package/android/src/main/java/io/hyperswitch/paymentsheet/PaymentResult.kt +63 -0
- package/android/src/main/java/io/hyperswitch/react/GooglePayButtonManager.kt +54 -0
- package/android/src/main/java/io/hyperswitch/react/HyperActivity.kt +73 -0
- package/android/src/main/java/io/hyperswitch/react/HyperEventEmitter.kt +144 -0
- package/android/src/main/java/io/hyperswitch/react/HyperFragment.kt +429 -0
- package/android/src/main/java/io/hyperswitch/react/HyperFragmentManager.kt +155 -0
- package/android/src/main/java/io/hyperswitch/react/HyperHeadlessModule.kt +43 -0
- package/android/src/main/java/io/hyperswitch/react/HyperModule.kt +405 -0
- package/android/src/main/java/io/hyperswitch/react/HyperPackage.kt +16 -0
- package/android/src/main/java/io/hyperswitch/react/ReactNativeController.kt +251 -0
- package/android/src/main/java/io/hyperswitch/utils/ConversionUtils.kt +256 -0
- package/android/src/main/java/io/hyperswitch/utils/StandardResult.kt +45 -0
- package/android/src/main/java/io/hyperswitch/view/GooglePayButtonView.kt +59 -0
- package/android/src/main/java/io/hyperswitch/view/PaymentWidgetView.kt +405 -0
- package/android/src/main/res/values/attrs.xml +6 -0
- package/android/src/main/res/values/strings.xml +5 -0
- package/android/src/main/res/values/theme.xml +16 -0
- package/ios/Modules/ReactNative/HyperswitchModule.swift +470 -0
- package/ios/Modules/ReactNative/HyperswitchSdkReactNative.h +5 -0
- package/ios/Modules/ReactNative/HyperswitchSdkReactNative.mm +121 -0
- package/ios/Modules/ReactNative/NativeHyperswitchModule.h +18 -0
- package/ios/Modules/ReactNative/NativeHyperswitchModule.mm +165 -0
- package/ios/Modules/ReactNative/NativeHyperswitchModuleImpl.swift +290 -0
- package/ios/Modules/ReactNative/NativePaymentElementModule.mm +129 -0
- package/ios/Views/Fabric/ApplePayView.h +14 -0
- package/ios/Views/Fabric/ApplePayView.mm +89 -0
- package/ios/Views/Fabric/NativePaymentElementView.h +21 -0
- package/ios/Views/Fabric/NativePaymentElementView.mm +200 -0
- package/ios/Views/Fabric/NativePaymentWidgetViewRegistry.h +37 -0
- package/ios/Views/Fabric/NativePaymentWidgetViewRegistry.m +45 -0
- package/ios/Views/Native/NativePaymentWidget.m +26 -0
- package/ios/Views/Native/NativePaymentWidget.swift +420 -0
- package/ios/hyperswitchSDK/Core/ApplePay/ApplePayHandler.swift +261 -0
- package/ios/hyperswitchSDK/Core/ApplePay/ApplePayViewManager.m +18 -0
- package/ios/hyperswitchSDK/Core/ApplePay/ApplePayViewManager.swift +126 -0
- package/ios/hyperswitchSDK/Core/DeviceDataCollection/HeadlessWebView.swift +144 -0
- package/ios/hyperswitchSDK/Core/HyperCVCWidget/CVCWidget.swift +136 -0
- package/ios/hyperswitchSDK/Core/HyperExpressCheckout/ExpressCheckoutLauncher.swift +116 -0
- package/ios/hyperswitchSDK/Core/HyperExpressCheckout/ExpressCheckoutWidget.swift +42 -0
- package/ios/hyperswitchSDK/Core/HyperPaymentCardTextField/PaymentCardTextField+SwiftUI.swift +67 -0
- package/ios/hyperswitchSDK/Core/HyperPaymentCardTextField/PaymentCardTextField.swift +44 -0
- package/ios/hyperswitchSDK/Core/HyperPaymentCardTextField/PaymentHandler.swift +59 -0
- package/ios/hyperswitchSDK/Core/HyperPaymentCardTextField/PaymentIntentParams.swift +31 -0
- package/ios/hyperswitchSDK/Core/HyperPaymentCardTextField/PaymentMethodParams.swift +25 -0
- package/ios/hyperswitchSDK/Core/HyperPaymentMethodManagement/PaymentManagementConfiguration.swift +213 -0
- package/ios/hyperswitchSDK/Core/HyperPaymentMethodManagement/PaymentMethodManagementWidget.swift +92 -0
- package/ios/hyperswitchSDK/Core/HyperPaymentSheet/PaymentSheet+Events.swift +36 -0
- package/ios/hyperswitchSDK/Core/HyperPaymentSheet/PaymentSheetView+SwiftUI.swift +49 -0
- package/ios/hyperswitchSDK/Core/HyperPaymentSheet/PaymentSheetView+UIKit.swift +49 -0
- package/ios/hyperswitchSDK/Core/HyperPaymentSheet/PaymentSheetView.swift +68 -0
- package/ios/hyperswitchSDK/Core/HyperPaymentWidget/PaymentWidget.swift +212 -0
- package/ios/hyperswitchSDK/Core/HyperSession/PaymentSession+UIKit.swift +228 -0
- package/ios/hyperswitchSDK/Core/HyperSession/PaymentSessionTypes.swift +174 -0
- package/ios/hyperswitchSDK/Core/NativeModule/HyperHeadless.m +15 -0
- package/ios/hyperswitchSDK/Core/NativeModule/HyperHeadless.swift +108 -0
- package/ios/hyperswitchSDK/Core/NativeModule/HyperModule.m +31 -0
- package/ios/hyperswitchSDK/Core/NativeModule/HyperModule.swift +343 -0
- package/ios/hyperswitchSDK/Core/NativeModule/OTAServices.swift +117 -0
- package/ios/hyperswitchSDK/Core/NativeModule/RNHeadlessManager.swift +47 -0
- package/ios/hyperswitchSDK/Core/NativeModule/RNResponseHandler.swift +12 -0
- package/ios/hyperswitchSDK/Core/NativeModule/RNViewManager.swift +55 -0
- package/ios/hyperswitchSDK/Core/NativeModule/WidgetAction.swift +30 -0
- package/ios/hyperswitchSDK/Core/NativeModule/WidgetResponseRegistry.swift +92 -0
- package/ios/hyperswitchSDK/Core/NativeModule/hyper-Bridging-Header.h +12 -0
- package/ios/hyperswitchSDK/Core/Resources/HyperOTA.plist +20 -0
- package/ios/hyperswitchSDK/Core/Resources/hyperswitch.bundle +1531 -0
- package/ios/hyperswitchSDK/CoreLite/ApplePayHandlerLite.swift +251 -0
- package/ios/hyperswitchSDK/CoreLite/PaymentSession+Lite.swift +25 -0
- package/ios/hyperswitchSDK/CoreLite/PaymentSheetView+Lite.swift +45 -0
- package/ios/hyperswitchSDK/CoreLite/SwiftUI+Lite.swift +48 -0
- package/ios/hyperswitchSDK/CoreLite/WebViewController.swift +278 -0
- package/ios/hyperswitchSDK/Shared/APIClient.swift +22 -0
- package/ios/hyperswitchSDK/Shared/Codable+UIKit.swift +75 -0
- package/ios/hyperswitchSDK/Shared/CustomEndpointConfiguration.swift +67 -0
- package/ios/hyperswitchSDK/Shared/DictionaryConverter.swift +104 -0
- package/ios/hyperswitchSDK/Shared/Environment.swift +24 -0
- package/ios/hyperswitchSDK/Shared/Extensions.swift +101 -0
- package/ios/hyperswitchSDK/Shared/Helper.swift +40 -0
- package/ios/hyperswitchSDK/Shared/HyperEvents/PaymentEventData.swift +125 -0
- package/ios/hyperswitchSDK/Shared/HyperEvents/PaymentEventSubscriptionBuilder.swift +45 -0
- package/ios/hyperswitchSDK/Shared/HyperEvents/PaymentEventType.swift +30 -0
- package/ios/hyperswitchSDK/Shared/HyperNetworking.swift +151 -0
- package/ios/hyperswitchSDK/Shared/HyperParams.swift +44 -0
- package/ios/hyperswitchSDK/Shared/HyperUIViewController.swift +27 -0
- package/ios/hyperswitchSDK/Shared/Hyperswitch.swift +20 -0
- package/ios/hyperswitchSDK/Shared/HyperswitchConfigurationSchema.swift +54 -0
- package/ios/hyperswitchSDK/Shared/HyperswitchEnvironment.swift +11 -0
- package/ios/hyperswitchSDK/Shared/NativeLogger/Debouncer.swift +37 -0
- package/ios/hyperswitchSDK/Shared/NativeLogger/LogBuilder.swift +113 -0
- package/ios/hyperswitchSDK/Shared/NativeLogger/LogFileManager.swift +76 -0
- package/ios/hyperswitchSDK/Shared/NativeLogger/LogManager.swift +113 -0
- package/ios/hyperswitchSDK/Shared/NativeLogger/LogPayload.swift +91 -0
- package/ios/hyperswitchSDK/Shared/PaymentMethodType.swift +15 -0
- package/ios/hyperswitchSDK/Shared/PaymentSession.swift +98 -0
- package/ios/hyperswitchSDK/Shared/PaymentSessionConfiguration.swift +14 -0
- package/ios/hyperswitchSDK/Shared/PaymentSheet.swift +33 -0
- package/ios/hyperswitchSDK/Shared/PaymentSheetAppearance+Codable.swift +182 -0
- package/ios/hyperswitchSDK/Shared/PaymentSheetAppearance.swift +238 -0
- package/ios/hyperswitchSDK/Shared/PaymentSheetConfiguration.swift +161 -0
- package/ios/hyperswitchSDK/Shared/SDKParams.swift +43 -0
- package/ios/hyperswitchSDK/Shared/SavedPaymentMethodsConfiguration.swift +20 -0
- package/ios/hyperswitchSDK/Shared/SwiftUIManager.swift +28 -0
- package/ios/hyperswitchSDK/Shared/Version.swift +12 -0
- package/lib/bs/JuspayTechReactNativeHyperswitch.cmi +0 -0
- package/lib/bs/JuspayTechReactNativeHyperswitch.cmj +0 -0
- package/lib/bs/JuspayTechReactNativeHyperswitch.cmt +0 -0
- package/lib/bs/JuspayTechReactNativeHyperswitch.mlmap +0 -0
- package/lib/bs/build.ninja +8 -0
- package/lib/bs/install.ninja +9 -0
- package/lib/bs/src/context/HyperProvider-JuspayTechReactNativeHyperswitch.cmt +0 -0
- package/lib/bs/src/context/WidgetRegistry-JuspayTechReactNativeHyperswitch.cmt +0 -0
- package/lib/bs/src/core/Hyper-JuspayTechReactNativeHyperswitch.cmt +0 -0
- package/lib/bs/src/core/HyperElements-JuspayTechReactNativeHyperswitch.cmt +0 -0
- package/lib/bs/src/hooks/usePaymentSession-JuspayTechReactNativeHyperswitch.cmt +0 -0
- package/lib/bs/src/hooks/useWidget-JuspayTechReactNativeHyperswitch.cmt +0 -0
- package/lib/bs/src/modules/NativeHyperswitchSdk-JuspayTechReactNativeHyperswitch.cmt +0 -0
- package/lib/bs/src/types/HyperTypes-JuspayTechReactNativeHyperswitch.cmt +0 -0
- package/lib/bs/src/types/NativeModuleTypes-JuspayTechReactNativeHyperswitch.cmt +0 -0
- package/lib/bs/src/types/PaymentSheetConfiguration-JuspayTechReactNativeHyperswitch.cmt +0 -0
- package/lib/bs/src/utils/AppearanceTransformer-JuspayTechReactNativeHyperswitch.cmt +0 -0
- package/lib/bs/src/utils/EventValidator-JuspayTechReactNativeHyperswitch.cmt +0 -0
- package/lib/bs/src/utils/NewArchUtils-JuspayTechReactNativeHyperswitch.cmt +0 -0
- package/lib/bs/src/utils/PaymentSheetEventManager-JuspayTechReactNativeHyperswitch.cmt +0 -0
- package/lib/bs/src/utils/ReactNativeUtils-JuspayTechReactNativeHyperswitch.cmt +0 -0
- package/lib/bs/src/utils/ResponseHandler-JuspayTechReactNativeHyperswitch.cmt +0 -0
- package/lib/bs/src/views/CVCElement-JuspayTechReactNativeHyperswitch.cmt +0 -0
- package/lib/bs/src/views/NativePaymentWidget-JuspayTechReactNativeHyperswitch.cmt +0 -0
- package/lib/bs/src/views/NativePaymentWidgetImpl-JuspayTechReactNativeHyperswitch.cmt +0 -0
- package/lib/bs/src/views/PaymentElement-JuspayTechReactNativeHyperswitch.cmt +0 -0
- package/lib/commonjs/index.bundle.js +2 -0
- package/lib/commonjs/index.bundle.js.map +1 -0
- package/lib/module/index.bundle.js +2 -0
- package/lib/module/index.bundle.js.map +1 -0
- package/lib/typescript/babel.config.d.ts +10 -0
- package/lib/typescript/babel.config.d.ts.map +1 -0
- package/lib/typescript/eslint.config.d.mts +3 -0
- package/lib/typescript/eslint.config.d.mts.map +1 -0
- package/lib/typescript/rollup.config.d.ts +23 -0
- package/lib/typescript/rollup.config.d.ts.map +1 -0
- package/lib/typescript/scripts/bootstrap.d.ts +2 -0
- package/lib/typescript/scripts/bootstrap.d.ts.map +1 -0
- package/lib/typescript/src/context/Elements.d.ts +7 -0
- package/lib/typescript/src/context/Elements.d.ts.map +1 -0
- package/lib/typescript/src/context/HyperElements.d.ts +23 -0
- package/lib/typescript/src/context/HyperElements.d.ts.map +1 -0
- package/lib/typescript/src/context/PaymentSession.d.ts +15 -0
- package/lib/typescript/src/context/PaymentSession.d.ts.map +1 -0
- package/lib/typescript/src/context/SavedPaymentMethods.d.ts +5 -0
- package/lib/typescript/src/context/SavedPaymentMethods.d.ts.map +1 -0
- package/lib/typescript/src/context/WidgetRegistry.d.ts +8 -0
- package/lib/typescript/src/context/WidgetRegistry.d.ts.map +1 -0
- package/lib/typescript/src/context/hooks.d.ts +5 -0
- package/lib/typescript/src/context/hooks.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +10 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/modules/NativeHyperswitchSdk.d.ts +61 -0
- package/lib/typescript/src/modules/NativeHyperswitchSdk.d.ts.map +1 -0
- package/lib/typescript/src/specs/ApplePayViewNativeComponent.d.ts +10 -0
- package/lib/typescript/src/specs/ApplePayViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/specs/NativeHyperHeadless.d.ts +14 -0
- package/lib/typescript/src/specs/NativeHyperHeadless.d.ts.map +1 -0
- package/lib/typescript/src/specs/NativeHyperswitchModule.d.ts +32 -0
- package/lib/typescript/src/specs/NativeHyperswitchModule.d.ts.map +1 -0
- package/lib/typescript/src/specs/NativeHyperswitchSdkNative.d.ts +33 -0
- package/lib/typescript/src/specs/NativeHyperswitchSdkNative.d.ts.map +1 -0
- package/lib/typescript/src/specs/NativePaymentElementModule.d.ts +9 -0
- package/lib/typescript/src/specs/NativePaymentElementModule.d.ts.map +1 -0
- package/lib/typescript/src/specs/PaymentElementNativeComponent.d.ts +19 -0
- package/lib/typescript/src/specs/PaymentElementNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/specs/utils.d.ts +15 -0
- package/lib/typescript/src/specs/utils.d.ts.map +1 -0
- package/lib/typescript/src/types/NativeModuleTypes.d.ts +67 -0
- package/lib/typescript/src/types/NativeModuleTypes.d.ts.map +1 -0
- package/lib/typescript/src/types/PaymentSheetConfiguration.d.ts +255 -0
- package/lib/typescript/src/types/PaymentSheetConfiguration.d.ts.map +1 -0
- package/lib/typescript/src/types/definitions.d.ts +85 -0
- package/lib/typescript/src/types/definitions.d.ts.map +1 -0
- package/lib/typescript/src/types/elements/index.d.ts +23 -0
- package/lib/typescript/src/types/elements/index.d.ts.map +1 -0
- package/lib/typescript/src/types/paymentresult/index.d.ts +5 -0
- package/lib/typescript/src/types/paymentresult/index.d.ts.map +1 -0
- package/lib/typescript/src/types/savedPaymentMethods/index.d.ts +69 -0
- package/lib/typescript/src/types/savedPaymentMethods/index.d.ts.map +1 -0
- package/lib/typescript/src/utils/EventValidator.d.ts +9 -0
- package/lib/typescript/src/utils/EventValidator.d.ts.map +1 -0
- package/lib/typescript/src/utils/InitializationState.d.ts +13 -0
- package/lib/typescript/src/utils/InitializationState.d.ts.map +1 -0
- package/lib/typescript/src/utils/LaunchOptions.d.ts +7 -0
- package/lib/typescript/src/utils/LaunchOptions.d.ts.map +1 -0
- package/lib/typescript/src/utils/NewArchUtils.d.ts +7 -0
- package/lib/typescript/src/utils/NewArchUtils.d.ts.map +1 -0
- package/lib/typescript/src/utils/ReactNativeUtils.d.ts +3 -0
- package/lib/typescript/src/utils/ReactNativeUtils.d.ts.map +1 -0
- package/lib/typescript/src/views/CVCElement.d.ts +15 -0
- package/lib/typescript/src/views/CVCElement.d.ts.map +1 -0
- package/lib/typescript/src/views/NativePaymentWidget.d.ts +3 -0
- package/lib/typescript/src/views/NativePaymentWidget.d.ts.map +1 -0
- package/lib/typescript/src/views/NativePaymentWidgetImpl.d.ts +5 -0
- package/lib/typescript/src/views/NativePaymentWidgetImpl.d.ts.map +1 -0
- package/lib/typescript/src/views/PaymentElement.d.ts +18 -0
- package/lib/typescript/src/views/PaymentElement.d.ts.map +1 -0
- package/package.json +184 -0
- package/src/context/Elements.ts +80 -0
- package/src/context/HyperElements.tsx +81 -0
- package/src/context/PaymentSession.ts +121 -0
- package/src/context/SavedPaymentMethods.ts +80 -0
- package/src/context/WidgetRegistry.ts +74 -0
- package/src/context/hooks.ts +79 -0
- package/src/index.ts +53 -0
- package/src/modules/NativeHyperswitchSdk.ts +155 -0
- package/src/specs/ApplePayViewNativeComponent.ts +11 -0
- package/src/specs/NativeHyperHeadless.ts +22 -0
- package/src/specs/NativeHyperswitchModule.ts +51 -0
- package/src/specs/NativeHyperswitchSdkNative.ts +62 -0
- package/src/specs/NativePaymentElementModule.ts +25 -0
- package/src/specs/PaymentElementNativeComponent.ts +21 -0
- package/src/specs/utils.ts +15 -0
- package/src/types/NativeModuleTypes.ts +73 -0
- package/src/types/PaymentSheetConfiguration.ts +360 -0
- package/src/types/definitions.ts +109 -0
- package/src/types/elements/index.ts +33 -0
- package/src/types/paymentresult/index.ts +4 -0
- package/src/types/savedPaymentMethods/index.ts +74 -0
- package/src/utils/EventValidator.ts +39 -0
- package/src/utils/InitializationState.ts +28 -0
- package/src/utils/LaunchOptions.ts +41 -0
- package/src/utils/NewArchUtils.ts +18 -0
- package/src/utils/ReactNativeUtils.ts +13 -0
- package/src/views/CVCElement.tsx +122 -0
- package/src/views/NativePaymentWidget.ts +2 -0
- package/src/views/NativePaymentWidgetImpl.ts +16 -0
- package/src/views/PaymentElement.tsx +189 -0
- package/tsconfig.build.json +21 -0
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
package io.hyperswitch.react
|
|
2
|
+
|
|
3
|
+
import android.annotation.SuppressLint
|
|
4
|
+
import android.os.Bundle
|
|
5
|
+
import android.util.Log
|
|
6
|
+
import android.view.MotionEvent
|
|
7
|
+
import android.view.View
|
|
8
|
+
import android.view.ViewGroup
|
|
9
|
+
import com.facebook.react.ReactFragment
|
|
10
|
+
import com.facebook.react.ReactHost
|
|
11
|
+
import com.facebook.react.ReactNativeHost
|
|
12
|
+
import com.facebook.react.ReactRootView
|
|
13
|
+
import com.facebook.react.bridge.Arguments
|
|
14
|
+
import com.facebook.react.bridge.ReadableMap
|
|
15
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
16
|
+
import com.facebook.react.views.scroll.ReactHorizontalScrollView
|
|
17
|
+
import com.facebook.react.views.scroll.ReactScrollView
|
|
18
|
+
import com.proyecto26.inappbrowser.ChromeTabsDismissedEvent
|
|
19
|
+
import com.proyecto26.inappbrowser.ChromeTabsManagerActivity
|
|
20
|
+
import io.hyperswitch.PaymentEvent
|
|
21
|
+
import io.hyperswitch.PaymentEventListener
|
|
22
|
+
import io.hyperswitch.model.ElementUpdateIntentResult
|
|
23
|
+
import io.hyperswitch.paymentsession.ExitHeadlessCallBackManager
|
|
24
|
+
import io.hyperswitch.paymentsheet.PaymentResult
|
|
25
|
+
import io.hyperswitch.redirect.RedirectEvent
|
|
26
|
+
import io.hyperswitch.utils.ConversionUtils
|
|
27
|
+
import io.hyperswitch.utils.StandardResult
|
|
28
|
+
import org.greenrobot.eventbus.EventBus
|
|
29
|
+
import org.greenrobot.eventbus.Subscribe
|
|
30
|
+
import org.json.JSONObject
|
|
31
|
+
import java.util.concurrent.ConcurrentHashMap
|
|
32
|
+
import kotlin.collections.set
|
|
33
|
+
import kotlin.text.ifEmpty
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
enum class EventName {
|
|
37
|
+
CONFIRM_PAYMENT_ACTION,
|
|
38
|
+
CONFIRM_CVC_PAYMENT
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
enum class CallbackType {
|
|
42
|
+
PAYMENT_RESULT,
|
|
43
|
+
CONFIRM_ACTION,
|
|
44
|
+
CONFIRM_CVC_ACTION,
|
|
45
|
+
UPDATE_INTENT_INIT,
|
|
46
|
+
UPDATE_INTENT_COMPLETE,
|
|
47
|
+
PAYMENT_CONFIRM_BUTTON_CLICK
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
sealed class HyperCallback {
|
|
52
|
+
class Payment(val fn: ((String) -> Unit)) : HyperCallback()
|
|
53
|
+
class UpdateIntentInit(val fn: (() -> Unit)?) : HyperCallback()
|
|
54
|
+
class UpdateIntentComplete(val fn: ((String) -> Unit)) : HyperCallback()
|
|
55
|
+
class ConfirmButtonTriggered(
|
|
56
|
+
val callback: (data: String, onPaymentResultCallback: (Boolean) -> Unit) -> Unit,
|
|
57
|
+
) : HyperCallback()
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
class HyperFragment : ReactFragment() {
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Instance-level registry. No companion object, no static map.
|
|
64
|
+
* Keyed by [CallbackType] so each slot is independently replaceable.
|
|
65
|
+
*/
|
|
66
|
+
private val callbacks = ConcurrentHashMap<CallbackType, HyperCallback>()
|
|
67
|
+
|
|
68
|
+
/** Per-widget listener set by HyperswitchBoundElement.subscribe(). Null for PaymentSheet. */
|
|
69
|
+
private var paymentEventListener: PaymentEventListener? = null
|
|
70
|
+
|
|
71
|
+
private var onExit: (() -> Unit)? = null
|
|
72
|
+
|
|
73
|
+
fun setOnExit(callback: () -> Unit) {
|
|
74
|
+
onExit = callback
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
fun setOnPaymentResult(callback: ((String) -> Unit)) {
|
|
78
|
+
callbacks[CallbackType.PAYMENT_RESULT] = HyperCallback.Payment(callback)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
fun setOnPaymentConfirmButtonClick(callback: (data: String, onPaymentResultCallback: ((Boolean) -> Unit)) -> Unit) {
|
|
82
|
+
callbacks[CallbackType.PAYMENT_CONFIRM_BUTTON_CLICK] = HyperCallback.ConfirmButtonTriggered(
|
|
83
|
+
callback
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
fun setOnEventCallback(listener: PaymentEventListener) {
|
|
88
|
+
this.paymentEventListener = listener
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
fun updatePaymentIntentInit(callback: (() -> Unit)?) {
|
|
92
|
+
val rootTag = reactDelegate.reactRootView?.rootViewTag ?: -1
|
|
93
|
+
if (rootTag == -1) {
|
|
94
|
+
callback?.invoke()
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
if (callbacks[CallbackType.UPDATE_INTENT_INIT] != null) {
|
|
98
|
+
callback?.invoke()
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
callbacks[CallbackType.UPDATE_INTENT_INIT] = HyperCallback.UpdateIntentInit(callback)
|
|
102
|
+
reactNativeHost.reactInstanceManager.currentReactContext
|
|
103
|
+
?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
104
|
+
?.emit("updateIntentInit", Arguments.createMap().apply {
|
|
105
|
+
putInt("rootTag", rootTag)
|
|
106
|
+
})
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
fun updatePaymentIntentComplete(
|
|
110
|
+
sdkAuthorization: String,
|
|
111
|
+
callback: ((String) -> Unit)
|
|
112
|
+
) {
|
|
113
|
+
val rootTag = reactDelegate.reactRootView?.rootViewTag ?: -1
|
|
114
|
+
if (rootTag == -1) {
|
|
115
|
+
callback.invoke(
|
|
116
|
+
ElementUpdateIntentResult.Failure(
|
|
117
|
+
Throwable("React context not ready").apply {
|
|
118
|
+
initCause(Throwable("REACT_CONTEXT_NOT_READY"))
|
|
119
|
+
}
|
|
120
|
+
).toString()
|
|
121
|
+
)
|
|
122
|
+
return
|
|
123
|
+
}
|
|
124
|
+
if (callbacks[CallbackType.UPDATE_INTENT_COMPLETE] != null) {
|
|
125
|
+
callback.invoke(
|
|
126
|
+
ElementUpdateIntentResult.Failure(
|
|
127
|
+
Throwable("Update intent complete already in progress").apply {
|
|
128
|
+
initCause(Throwable("ALREADY_IN_PROGRESS"))
|
|
129
|
+
}
|
|
130
|
+
).toString()
|
|
131
|
+
)
|
|
132
|
+
return
|
|
133
|
+
}
|
|
134
|
+
callbacks[CallbackType.UPDATE_INTENT_COMPLETE] =
|
|
135
|
+
HyperCallback.UpdateIntentComplete(callback)
|
|
136
|
+
reactNativeHost.reactInstanceManager.currentReactContext
|
|
137
|
+
?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
138
|
+
?.emit("updateIntentComplete", Arguments.createMap().apply {
|
|
139
|
+
putString("sdkAuthorization", sdkAuthorization)
|
|
140
|
+
putInt("rootTag", rootTag)
|
|
141
|
+
})
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
fun confirmPayment(callback: ((String) -> Unit)) {
|
|
145
|
+
if (callbacks.containsKey(CallbackType.CONFIRM_ACTION)) {
|
|
146
|
+
callback.invoke(
|
|
147
|
+
StandardResult.Failed(error = Throwable("Payment already in progress")).toJSONString()
|
|
148
|
+
)
|
|
149
|
+
return
|
|
150
|
+
}
|
|
151
|
+
val rootTag = reactDelegate.reactRootView?.rootViewTag ?: -1
|
|
152
|
+
if (rootTag == -1) {
|
|
153
|
+
callback.invoke(
|
|
154
|
+
StandardResult.Failed(error = Throwable("React Context not ready")).toJSONString()
|
|
155
|
+
)
|
|
156
|
+
return
|
|
157
|
+
}
|
|
158
|
+
if (callbacks[CallbackType.UPDATE_INTENT_COMPLETE] != null) {
|
|
159
|
+
callback.invoke(
|
|
160
|
+
StandardResult.Failed(error = Throwable("Payment Intent update is in progress"))
|
|
161
|
+
.toJSONString()
|
|
162
|
+
)
|
|
163
|
+
return
|
|
164
|
+
}
|
|
165
|
+
callbacks[CallbackType.CONFIRM_ACTION] = HyperCallback.Payment(callback)
|
|
166
|
+
reactNativeHost.reactInstanceManager.currentReactContext
|
|
167
|
+
?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
168
|
+
?.emit("triggerWidgetAction", Arguments.createMap().apply {
|
|
169
|
+
putString("actionType", EventName.CONFIRM_PAYMENT_ACTION.name)
|
|
170
|
+
putInt("rootTag", rootTag)
|
|
171
|
+
})
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Called directly on this instance by the native module after finding the
|
|
176
|
+
* fragment via [UIManagerModule] + [androidx.fragment.app.FragmentManager.findFragment].
|
|
177
|
+
*
|
|
178
|
+
* PAYMENT_RESULT → fires CONFIRM_ACTION if present, otherwise PAYMENT_RESULT.
|
|
179
|
+
* CONFIRM_ACTION → fires and removes CONFIRM_ACTION (one-shot resolve).
|
|
180
|
+
*/
|
|
181
|
+
fun notifyResult(type: CallbackType, result: String) {
|
|
182
|
+
try {
|
|
183
|
+
when (type) {
|
|
184
|
+
CallbackType.PAYMENT_RESULT -> {
|
|
185
|
+
val confirmCallback =
|
|
186
|
+
callbacks.remove(CallbackType.CONFIRM_ACTION) as? HyperCallback.Payment
|
|
187
|
+
val confirmCvcCallback =
|
|
188
|
+
callbacks.remove(CallbackType.CONFIRM_CVC_ACTION) as? HyperCallback.Payment
|
|
189
|
+
|
|
190
|
+
when {
|
|
191
|
+
confirmCallback != null -> {
|
|
192
|
+
// val parsed = parseResult(result)
|
|
193
|
+
confirmCallback.fn.invoke(result)
|
|
194
|
+
onExit?.invoke()
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
confirmCvcCallback != null -> {
|
|
198
|
+
// val parsed = parseResult(result)
|
|
199
|
+
confirmCvcCallback.fn.invoke(result)
|
|
200
|
+
onExit?.invoke()
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
else -> {
|
|
204
|
+
// val parsed = parseResult(result)
|
|
205
|
+
(callbacks.remove(CallbackType.PAYMENT_RESULT) as? HyperCallback.Payment)
|
|
206
|
+
?.fn?.invoke(result)
|
|
207
|
+
onExit?.invoke()
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
CallbackType.UPDATE_INTENT_INIT ->
|
|
213
|
+
(callbacks.remove(CallbackType.UPDATE_INTENT_INIT) as? HyperCallback.UpdateIntentInit)?.fn?.invoke()
|
|
214
|
+
|
|
215
|
+
CallbackType.UPDATE_INTENT_COMPLETE ->
|
|
216
|
+
(callbacks.remove(CallbackType.UPDATE_INTENT_COMPLETE) as? HyperCallback.UpdateIntentComplete)?.fn?.invoke(
|
|
217
|
+
result
|
|
218
|
+
)
|
|
219
|
+
//
|
|
220
|
+
CallbackType.CONFIRM_ACTION -> {
|
|
221
|
+
// val parsed = parseResult(result)
|
|
222
|
+
(callbacks.remove(CallbackType.CONFIRM_ACTION) as? HyperCallback.Payment)?.fn?.invoke(
|
|
223
|
+
result
|
|
224
|
+
)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
CallbackType.CONFIRM_CVC_ACTION -> {
|
|
228
|
+
// val parsed = parseResult(result)
|
|
229
|
+
(callbacks.remove(CallbackType.CONFIRM_CVC_ACTION) as? HyperCallback.Payment)?.fn?.invoke(
|
|
230
|
+
result
|
|
231
|
+
)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
else -> Log.i("HyperFragment", "notifyResult: unhandled type $type")
|
|
235
|
+
}
|
|
236
|
+
} catch (e: Exception) {
|
|
237
|
+
Log.e("HyperFragment", "Error in notifyResult", e)
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
fun notifyConfirmButtonClicked(payload: String, callback: (Boolean) -> Unit) {
|
|
242
|
+
val confirmTriggeredCallback =
|
|
243
|
+
callbacks[CallbackType.PAYMENT_CONFIRM_BUTTON_CLICK] as HyperCallback.ConfirmButtonTriggered?
|
|
244
|
+
if (confirmTriggeredCallback == null) {
|
|
245
|
+
callback.invoke(true)
|
|
246
|
+
} else {
|
|
247
|
+
confirmTriggeredCallback.callback.invoke(payload, callback)
|
|
248
|
+
}
|
|
249
|
+
callbacks.remove(CallbackType.CONFIRM_ACTION)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Called directly on this instance for streaming widget lifecycle events.
|
|
254
|
+
*/
|
|
255
|
+
fun notifyEvent(eventType: String, result: ReadableMap) {
|
|
256
|
+
try {
|
|
257
|
+
val payload = ConversionUtils.readableMapToMap(result)
|
|
258
|
+
val listener = paymentEventListener
|
|
259
|
+
if (listener != null) {
|
|
260
|
+
val event = PaymentEvent(type = eventType, payload = payload)
|
|
261
|
+
listener.onPaymentEvent(event)
|
|
262
|
+
} else {
|
|
263
|
+
HyperEventEmitter.emitPaymentEvent(eventType, payload)
|
|
264
|
+
}
|
|
265
|
+
} catch (e: Exception) {
|
|
266
|
+
Log.e("HyperFragment", "Error in notifyEvent", e)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
fun confirmCvcPayment(
|
|
272
|
+
sdkAuthorization: String,
|
|
273
|
+
paymentToken: String,
|
|
274
|
+
billing: String?,
|
|
275
|
+
callback: ((String) -> Unit)
|
|
276
|
+
) {
|
|
277
|
+
val rootTag = reactDelegate.reactRootView?.rootViewTag ?: -1
|
|
278
|
+
if (rootTag == -1) {
|
|
279
|
+
val paymentResult = StandardResult.Failed(error = Throwable("cannot find the view"))
|
|
280
|
+
callback.invoke(paymentResult.toJSONString())
|
|
281
|
+
return
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
val exitCallback = { data: PaymentResult ->
|
|
285
|
+
callback.invoke(data.toJSONString())
|
|
286
|
+
}
|
|
287
|
+
val registered = ExitHeadlessCallBackManager.tryRegisterCallback(rootTag, exitCallback)
|
|
288
|
+
if (!registered) {
|
|
289
|
+
val paymentResult =
|
|
290
|
+
StandardResult.Failed(error = Throwable("CVC payment already in progress for this widget").apply {
|
|
291
|
+
initCause(Throwable("ALREADY_IN_PROGRESS"))
|
|
292
|
+
})
|
|
293
|
+
callback.invoke(paymentResult.toJSONString())
|
|
294
|
+
return
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
val map = Arguments.createMap()
|
|
298
|
+
map.putString("actionType", EventName.CONFIRM_CVC_PAYMENT.name)
|
|
299
|
+
map.putInt("rootTag", rootTag)
|
|
300
|
+
map.putString("sdkAuthorization", sdkAuthorization)
|
|
301
|
+
map.putString("paymentToken", paymentToken)
|
|
302
|
+
billing?.let { map.putString("billing", it) }
|
|
303
|
+
reactNativeHost.reactInstanceManager.currentReactContext
|
|
304
|
+
?.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
305
|
+
?.emit("triggerWidgetAction", map)
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
309
|
+
super.onCreate(savedInstanceState)
|
|
310
|
+
registerEventBus()
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
314
|
+
super.onViewCreated(view, savedInstanceState)
|
|
315
|
+
val reactRootView = view as? ReactRootView ?: return
|
|
316
|
+
var scrollFixScheduled = false
|
|
317
|
+
reactRootView.setOnHierarchyChangeListener(object : ViewGroup.OnHierarchyChangeListener {
|
|
318
|
+
override fun onChildViewAdded(parent: View?, child: View?) {
|
|
319
|
+
if (!scrollFixScheduled) {
|
|
320
|
+
scrollFixScheduled = true
|
|
321
|
+
view.post {
|
|
322
|
+
scrollFixScheduled = false
|
|
323
|
+
fixScrollInterception(reactRootView)
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
override fun onChildViewRemoved(parent: View?, child: View?) {}
|
|
329
|
+
})
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
override fun onDestroyView() {
|
|
333
|
+
try {
|
|
334
|
+
super.onDestroyView()
|
|
335
|
+
callbacks.clear()
|
|
336
|
+
onExit = null
|
|
337
|
+
paymentEventListener = null
|
|
338
|
+
} catch (_: Exception) {
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
override fun onDestroy() {
|
|
343
|
+
try {
|
|
344
|
+
super.onDestroy()
|
|
345
|
+
unRegisterEventBus()
|
|
346
|
+
callbacks.clear()
|
|
347
|
+
onExit = null
|
|
348
|
+
paymentEventListener = null
|
|
349
|
+
} catch (_: Exception) {
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
override fun onPause() {
|
|
354
|
+
try {
|
|
355
|
+
super.onPause()
|
|
356
|
+
} catch (_: Exception) {
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// ── Scroll fix ────────────────────────────────────────────────────────────
|
|
361
|
+
|
|
362
|
+
@SuppressLint("ClickableViewAccessibility")
|
|
363
|
+
private fun fixScrollInterception(root: ViewGroup) {
|
|
364
|
+
root.isNestedScrollingEnabled = true
|
|
365
|
+
findReactScrollViews(root).forEach { scrollView ->
|
|
366
|
+
scrollView.isNestedScrollingEnabled = true
|
|
367
|
+
scrollView.setOnTouchListener { v, event ->
|
|
368
|
+
when (event.action) {
|
|
369
|
+
MotionEvent.ACTION_DOWN,
|
|
370
|
+
MotionEvent.ACTION_MOVE -> v.parent?.requestDisallowInterceptTouchEvent(true)
|
|
371
|
+
|
|
372
|
+
MotionEvent.ACTION_UP,
|
|
373
|
+
MotionEvent.ACTION_CANCEL -> v.parent?.requestDisallowInterceptTouchEvent(false)
|
|
374
|
+
}
|
|
375
|
+
false
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
private fun findReactScrollViews(root: ViewGroup): List<ViewGroup> {
|
|
381
|
+
val result = mutableListOf<ViewGroup>()
|
|
382
|
+
for (i in 0 until root.childCount) {
|
|
383
|
+
val child = root.getChildAt(i)
|
|
384
|
+
if (child is ReactScrollView || child is ReactHorizontalScrollView) result.add(child as ViewGroup)
|
|
385
|
+
if (child is ViewGroup) result.addAll(findReactScrollViews(child))
|
|
386
|
+
}
|
|
387
|
+
return result
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// ── EventBus ──────────────────────────────────────────────────────────────
|
|
391
|
+
|
|
392
|
+
private fun registerEventBus() {
|
|
393
|
+
if (!EventBus.getDefault().isRegistered(this)) EventBus.getDefault().register(this)
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
private fun unRegisterEventBus() {
|
|
397
|
+
if (EventBus.getDefault().isRegistered(this)) EventBus.getDefault().unregister(this)
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
@Subscribe
|
|
402
|
+
fun onEvent(event: RedirectEvent) {
|
|
403
|
+
unRegisterEventBus()
|
|
404
|
+
EventBus.getDefault()
|
|
405
|
+
.post(ChromeTabsDismissedEvent(event.message, event.resultType, event.isError))
|
|
406
|
+
startActivity(ChromeTabsManagerActivity.createDismissIntent(requireContext()))
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
override fun getReactNativeHost(): ReactNativeHost = ReactNativeController.getReactNativeHost()
|
|
410
|
+
override fun getReactHost(): ReactHost = ReactNativeController.getReactHost()
|
|
411
|
+
|
|
412
|
+
class Builder {
|
|
413
|
+
private var mComponentName: String? = null
|
|
414
|
+
private var mLaunchOptions: Bundle? = null
|
|
415
|
+
private var mFabricEnabled: Boolean = false
|
|
416
|
+
|
|
417
|
+
fun setComponentName(componentName: String?) = apply { mComponentName = componentName }
|
|
418
|
+
fun setLaunchOptions(launchOptions: Bundle?) = apply { mLaunchOptions = launchOptions }
|
|
419
|
+
fun setFabricEnabled(fabricEnabled: Boolean) = apply { mFabricEnabled = fabricEnabled }
|
|
420
|
+
|
|
421
|
+
fun build(): HyperFragment = HyperFragment().also { fragment ->
|
|
422
|
+
fragment.arguments = Bundle().apply {
|
|
423
|
+
putString(ARG_COMPONENT_NAME, mComponentName)
|
|
424
|
+
putBundle(ARG_LAUNCH_OPTIONS, mLaunchOptions)
|
|
425
|
+
putBoolean(ARG_FABRIC_ENABLED, mFabricEnabled)
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
package io.hyperswitch.react
|
|
2
|
+
|
|
3
|
+
import android.os.Handler
|
|
4
|
+
import android.os.Looper
|
|
5
|
+
import android.view.View
|
|
6
|
+
import android.widget.FrameLayout
|
|
7
|
+
import androidx.fragment.app.Fragment
|
|
8
|
+
import androidx.fragment.app.FragmentActivity
|
|
9
|
+
import androidx.fragment.app.FragmentManager
|
|
10
|
+
import java.util.concurrent.ConcurrentHashMap
|
|
11
|
+
import java.util.concurrent.atomic.AtomicInteger
|
|
12
|
+
|
|
13
|
+
object HyperFragmentManager {
|
|
14
|
+
|
|
15
|
+
// Thread-safe collections; all mutations happen on the main thread via mainHandler,
|
|
16
|
+
// but public query methods (isActive, isPending, getFragment) can be called from any thread.
|
|
17
|
+
private val fragmentRegistry = ConcurrentHashMap<String, Fragment>()
|
|
18
|
+
private val pendingTags = ConcurrentHashMap.newKeySet<String>()
|
|
19
|
+
private val debounceHandlers = ConcurrentHashMap<String, Runnable>()
|
|
20
|
+
private val mainHandler = Handler(Looper.getMainLooper())
|
|
21
|
+
|
|
22
|
+
// Monotonically increasing counter for stable, collision-free view IDs.
|
|
23
|
+
private val idCounter = AtomicInteger(0x00F00001)
|
|
24
|
+
|
|
25
|
+
private const val DEBOUNCE_MS = 300L
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Request to add/replace a fragment. Debounced per tag —
|
|
29
|
+
* rapid successive calls for the same tag collapse into one.
|
|
30
|
+
*/
|
|
31
|
+
fun addOrReplace(
|
|
32
|
+
activity: FragmentActivity,
|
|
33
|
+
container: FrameLayout,
|
|
34
|
+
fragment: Fragment,
|
|
35
|
+
tag: String,
|
|
36
|
+
addToBackStack: Boolean = true,
|
|
37
|
+
debounce: Boolean = true
|
|
38
|
+
) {
|
|
39
|
+
if (debounce) {
|
|
40
|
+
scheduleAddOrReplace(activity, container, fragment, tag, addToBackStack)
|
|
41
|
+
} else {
|
|
42
|
+
commitAddOrReplace(activity, container, fragment, tag, addToBackStack)
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private fun scheduleAddOrReplace(
|
|
47
|
+
activity: FragmentActivity,
|
|
48
|
+
container: FrameLayout,
|
|
49
|
+
fragment: Fragment,
|
|
50
|
+
tag: String,
|
|
51
|
+
addToBackStack: Boolean
|
|
52
|
+
) {
|
|
53
|
+
// Cancel any previously scheduled runnable for this tag
|
|
54
|
+
debounceHandlers[tag]?.let { mainHandler.removeCallbacks(it) }
|
|
55
|
+
|
|
56
|
+
// Mark as pending so callers can check
|
|
57
|
+
pendingTags.add(tag)
|
|
58
|
+
|
|
59
|
+
val runnable = Runnable {
|
|
60
|
+
pendingTags.remove(tag)
|
|
61
|
+
debounceHandlers.remove(tag)
|
|
62
|
+
if (!activity.isFinishing && !activity.isDestroyed) {
|
|
63
|
+
commitAddOrReplace(activity, container, fragment, tag, addToBackStack)
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
debounceHandlers[tag] = runnable
|
|
68
|
+
mainHandler.postDelayed(runnable, DEBOUNCE_MS)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private fun commitAddOrReplace(
|
|
72
|
+
activity: FragmentActivity,
|
|
73
|
+
container: FrameLayout,
|
|
74
|
+
fragment: Fragment,
|
|
75
|
+
tag: String,
|
|
76
|
+
addToBackStack: Boolean
|
|
77
|
+
) {
|
|
78
|
+
try {
|
|
79
|
+
if (activity.isFinishing || activity.isDestroyed) return
|
|
80
|
+
if (container.parent == null || !container.isAttachedToWindow) return
|
|
81
|
+
if (fragment.isAdded) return
|
|
82
|
+
|
|
83
|
+
val fm: FragmentManager = activity.supportFragmentManager
|
|
84
|
+
|
|
85
|
+
// Remove existing fragment with the same tag if present, including its back-stack entry
|
|
86
|
+
// so that onDestroy is called and the React tree is fully released.
|
|
87
|
+
val existing = fm.findFragmentByTag(tag)
|
|
88
|
+
if (existing != null) {
|
|
89
|
+
fm.popBackStackImmediate(tag, FragmentManager.POP_BACK_STACK_INCLUSIVE)
|
|
90
|
+
if (existing.isAdded) {
|
|
91
|
+
fm.beginTransaction().remove(existing).commitNowAllowingStateLoss()
|
|
92
|
+
}
|
|
93
|
+
fragmentRegistry.remove(tag)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (container.id == View.NO_ID) {
|
|
97
|
+
container.id = generateStableId()
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
val tx = fm.beginTransaction().add(container.id, fragment, tag)
|
|
101
|
+
if (addToBackStack) tx.addToBackStack(tag)
|
|
102
|
+
tx.commitNowAllowingStateLoss()
|
|
103
|
+
|
|
104
|
+
fragmentRegistry[tag] = fragment
|
|
105
|
+
} catch (e: Exception) {
|
|
106
|
+
e.printStackTrace()
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Cancel any pending debounced creation for this tag.
|
|
112
|
+
*/
|
|
113
|
+
fun cancelPending(tag: String) {
|
|
114
|
+
debounceHandlers[tag]?.let { mainHandler.removeCallbacks(it) }
|
|
115
|
+
debounceHandlers.remove(tag)
|
|
116
|
+
pendingTags.remove(tag)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
fun remove(activity: FragmentActivity, tag: String) {
|
|
120
|
+
cancelPending(tag)
|
|
121
|
+
val fm = activity.supportFragmentManager
|
|
122
|
+
val fragment = fm.findFragmentByTag(tag)
|
|
123
|
+
if (fragment != null) {
|
|
124
|
+
// Pop from back stack if the fragment was added with addToBackStack=true.
|
|
125
|
+
// This is a no-op when the fragment was added without a back-stack entry.
|
|
126
|
+
fm.popBackStackImmediate(tag, FragmentManager.POP_BACK_STACK_INCLUSIVE)
|
|
127
|
+
// If still attached (was never on the back stack), remove it directly.
|
|
128
|
+
if (fragment.isAdded) {
|
|
129
|
+
fm.beginTransaction().remove(fragment).commitNowAllowingStateLoss()
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
fragmentRegistry.remove(tag)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
fun removeAll(activity: FragmentActivity) {
|
|
136
|
+
debounceHandlers.keys.toList().forEach { cancelPending(it) }
|
|
137
|
+
val fm = activity.supportFragmentManager
|
|
138
|
+
fragmentRegistry.keys.toList().forEach { tag ->
|
|
139
|
+
if (fm.findFragmentByTag(tag) != null) {
|
|
140
|
+
fm.popBackStackImmediate(tag, FragmentManager.POP_BACK_STACK_INCLUSIVE)
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
fragmentRegistry.clear()
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** True if a debounced commit is scheduled but not yet executed */
|
|
147
|
+
fun isPending(tag: String): Boolean = pendingTags.contains(tag)
|
|
148
|
+
|
|
149
|
+
fun isActive(tag: String): Boolean = fragmentRegistry.containsKey(tag)
|
|
150
|
+
|
|
151
|
+
fun getFragment(tag: String): Fragment? = fragmentRegistry[tag]
|
|
152
|
+
|
|
153
|
+
/** Generates a unique, valid view ID using an atomic counter. */
|
|
154
|
+
internal fun generateStableId(): Int = idCounter.getAndIncrement()
|
|
155
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
package io.hyperswitch.react
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.Callback
|
|
4
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
5
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
6
|
+
import com.facebook.react.bridge.ReactMethod
|
|
7
|
+
import com.facebook.react.bridge.ReadableArray
|
|
8
|
+
import com.facebook.react.bridge.ReadableMap
|
|
9
|
+
import com.hyperswitchsdkreactnative.NativeHyperHeadlessSpec
|
|
10
|
+
import io.hyperswitch.paymentsession.GetPaymentSessionCallBackManager
|
|
11
|
+
import io.hyperswitch.paymentsession.PaymentSessionHandlerImpl
|
|
12
|
+
|
|
13
|
+
class HyperHeadlessModule internal constructor(private val rct: ReactApplicationContext) :
|
|
14
|
+
NativeHyperHeadlessSpec(rct) {
|
|
15
|
+
override fun getName(): String = NAME
|
|
16
|
+
|
|
17
|
+
@ReactMethod
|
|
18
|
+
override fun getPaymentSession(
|
|
19
|
+
rootTag: Double,
|
|
20
|
+
getPaymentMethodData: ReadableMap,
|
|
21
|
+
getPaymentMethodData2: ReadableMap,
|
|
22
|
+
getPaymentMethodDataArray: ReadableArray,
|
|
23
|
+
callback: Callback
|
|
24
|
+
) {
|
|
25
|
+
val handler = PaymentSessionHandlerImpl(
|
|
26
|
+
sdkAuthorization = GetPaymentSessionCallBackManager.getSdkAuthorization(),
|
|
27
|
+
defaultMethodData = getPaymentMethodData,
|
|
28
|
+
lastUsedMethodData = getPaymentMethodData2,
|
|
29
|
+
allMethodsData = getPaymentMethodDataArray,
|
|
30
|
+
jsCallback = callback,
|
|
31
|
+
)
|
|
32
|
+
GetPaymentSessionCallBackManager.executeCallback(handler)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@ReactMethod
|
|
36
|
+
override fun exitHeadless(rootTag: Double, status: String) {
|
|
37
|
+
// ExitHeadlessCallBackManager.executeCallback(rootTag, status)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
companion object {
|
|
41
|
+
const val NAME = "HyperHeadless"
|
|
42
|
+
}
|
|
43
|
+
}
|