@klarna/react-native-klarna-network-payment 0.0.1 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. package/README.md +143 -29
  2. package/android/build.gradle +95 -0
  3. package/android/src/main/AndroidManifest.xml +1 -0
  4. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/klarnanetwork/payment/KlarnaNetworkPaymentButtonViewSpec.kt +22 -0
  5. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/klarnanetwork/payment/KlarnaNetworkPaymentModule.kt +46 -0
  6. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/klarnanetwork/payment/KlarnaNetworkPaymentModuleImpl.kt +163 -0
  7. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/klarnanetwork/payment/KlarnaNetworkPaymentPackage.kt +30 -0
  8. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/klarnanetwork/payment/KlarnaPaymentButtonPressEvent.kt +19 -0
  9. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/klarnanetwork/payment/KlarnaPaymentButtonViewManager.kt +276 -0
  10. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/klarnanetwork/payment/KlarnaPaymentPresentationMapper.kt +132 -0
  11. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/klarnanetwork/payment/KlarnaPaymentRequestMapper.kt +328 -0
  12. package/android/src/main/java/com/klarna/mobile/sdk/reactnative/klarnanetwork/payment/KlarnaPaymentResponseMapper.kt +145 -0
  13. package/android/src/test/java/com/klarna/mobile/sdk/reactnative/klarnanetwork/payment/KlarnaNetworkPaymentModuleImplTest.kt +361 -0
  14. package/android/src/test/java/com/klarna/mobile/sdk/reactnative/klarnanetwork/payment/KlarnaPaymentButtonViewManagerTest.kt +155 -0
  15. package/android/src/test/java/com/klarna/mobile/sdk/reactnative/klarnanetwork/payment/KlarnaPaymentPresentationMapperTest.kt +447 -0
  16. package/android/src/test/java/com/klarna/mobile/sdk/reactnative/klarnanetwork/payment/KlarnaPaymentRequestMapperTest.kt +489 -0
  17. package/android/src/test/java/com/klarna/mobile/sdk/reactnative/klarnanetwork/payment/KlarnaPaymentResponseMapperTest.kt +456 -0
  18. package/ios/Sources/KlarnaNetworkPayment.h +5 -0
  19. package/ios/Sources/KlarnaNetworkPayment.mm +110 -0
  20. package/ios/Sources/KlarnaNetworkPaymentModuleImpl.swift +196 -0
  21. package/ios/Sources/KlarnaPaymentButtonComponentView.mm +147 -0
  22. package/ios/Sources/KlarnaPaymentButtonViewImpl.swift +77 -0
  23. package/ios/Sources/KlarnaPaymentPresentationMapping.swift +102 -0
  24. package/ios/Sources/KlarnaPaymentRequestDataMapping.swift +232 -0
  25. package/ios/Sources/KlarnaPaymentRequestMapping.swift +103 -0
  26. package/ios/Tests/KlarnaNetworkPaymentModuleImplTests.swift +143 -0
  27. package/ios/Tests/KlarnaPaymentButtonViewImplTests.swift +122 -0
  28. package/ios/Tests/KlarnaPaymentPresentationMappingTests.swift +335 -0
  29. package/lib/commonjs/KlarnaNetworkPayment.js +6 -0
  30. package/lib/commonjs/KlarnaNetworkPayment.js.map +1 -0
  31. package/lib/commonjs/KlarnaNetworkPaymentImpl.js +44 -0
  32. package/lib/commonjs/KlarnaNetworkPaymentImpl.js.map +1 -0
  33. package/lib/commonjs/KlarnaNetworkPaymentMapper.js +164 -0
  34. package/lib/commonjs/KlarnaNetworkPaymentMapper.js.map +1 -0
  35. package/lib/commonjs/KlarnaPaymentButton.js +43 -0
  36. package/lib/commonjs/KlarnaPaymentButton.js.map +1 -0
  37. package/lib/commonjs/Specs/KlarnaPaymentButtonNativeComponent.js +10 -0
  38. package/lib/commonjs/Specs/KlarnaPaymentButtonNativeComponent.js.map +1 -0
  39. package/lib/commonjs/Specs/NativeKlarnaNetworkPayment.js +13 -0
  40. package/lib/commonjs/Specs/NativeKlarnaNetworkPayment.js.map +1 -0
  41. package/lib/commonjs/index.js +51 -0
  42. package/lib/commonjs/index.js.map +1 -0
  43. package/lib/commonjs/types/KlarnaPaymentRequest.js +6 -0
  44. package/lib/commonjs/types/KlarnaPaymentRequest.js.map +1 -0
  45. package/lib/commonjs/types/KlarnaPaymentRequestState.js +2 -0
  46. package/lib/commonjs/types/KlarnaPaymentRequestState.js.map +1 -0
  47. package/lib/commonjs/types/KlarnaPaymentRequestStateContext.js +6 -0
  48. package/lib/commonjs/types/KlarnaPaymentRequestStateContext.js.map +1 -0
  49. package/lib/commonjs/types/KlarnaPaymentRequestStateReason.js +2 -0
  50. package/lib/commonjs/types/KlarnaPaymentRequestStateReason.js.map +1 -0
  51. package/lib/commonjs/types/models/KlarnaBillingPlan.js +6 -0
  52. package/lib/commonjs/types/models/KlarnaBillingPlan.js.map +1 -0
  53. package/lib/commonjs/types/models/KlarnaCollectCustomerProfileType.js +2 -0
  54. package/lib/commonjs/types/models/KlarnaCollectCustomerProfileType.js.map +1 -0
  55. package/lib/commonjs/types/models/KlarnaCustomer.js +6 -0
  56. package/lib/commonjs/types/models/KlarnaCustomer.js.map +1 -0
  57. package/lib/commonjs/types/models/KlarnaFreeTrial.js +2 -0
  58. package/lib/commonjs/types/models/KlarnaFreeTrial.js.map +1 -0
  59. package/lib/commonjs/types/models/KlarnaInterval.js +2 -0
  60. package/lib/commonjs/types/models/KlarnaInterval.js.map +1 -0
  61. package/lib/commonjs/types/models/KlarnaLineItem.js +2 -0
  62. package/lib/commonjs/types/models/KlarnaLineItem.js.map +1 -0
  63. package/lib/commonjs/types/models/KlarnaOndemandService.js +6 -0
  64. package/lib/commonjs/types/models/KlarnaOndemandService.js.map +1 -0
  65. package/lib/commonjs/types/models/KlarnaPartnerCustomer.js +6 -0
  66. package/lib/commonjs/types/models/KlarnaPartnerCustomer.js.map +1 -0
  67. package/lib/commonjs/types/models/KlarnaPaymentPresentation.js +6 -0
  68. package/lib/commonjs/types/models/KlarnaPaymentPresentation.js.map +1 -0
  69. package/lib/commonjs/types/models/KlarnaPaymentRequestData.js +6 -0
  70. package/lib/commonjs/types/models/KlarnaPaymentRequestData.js.map +1 -0
  71. package/lib/commonjs/types/models/KlarnaRequestCustomerToken.js +6 -0
  72. package/lib/commonjs/types/models/KlarnaRequestCustomerToken.js.map +1 -0
  73. package/lib/commonjs/types/models/KlarnaRequestCustomerTokenScope.js +2 -0
  74. package/lib/commonjs/types/models/KlarnaRequestCustomerTokenScope.js.map +1 -0
  75. package/lib/commonjs/types/models/KlarnaShipping.js +6 -0
  76. package/lib/commonjs/types/models/KlarnaShipping.js.map +1 -0
  77. package/lib/commonjs/types/models/KlarnaShippingConfig.js +6 -0
  78. package/lib/commonjs/types/models/KlarnaShippingConfig.js.map +1 -0
  79. package/lib/commonjs/types/models/KlarnaShippingConfigMode.js +2 -0
  80. package/lib/commonjs/types/models/KlarnaShippingConfigMode.js.map +1 -0
  81. package/lib/commonjs/types/models/KlarnaShippingOption.js +6 -0
  82. package/lib/commonjs/types/models/KlarnaShippingOption.js.map +1 -0
  83. package/lib/commonjs/types/models/KlarnaShippingRecipient.js +2 -0
  84. package/lib/commonjs/types/models/KlarnaShippingRecipient.js.map +1 -0
  85. package/lib/commonjs/types/models/KlarnaShippingType.js +2 -0
  86. package/lib/commonjs/types/models/KlarnaShippingType.js.map +1 -0
  87. package/lib/commonjs/types/models/KlarnaShippingTypeAttribute.js +2 -0
  88. package/lib/commonjs/types/models/KlarnaShippingTypeAttribute.js.map +1 -0
  89. package/lib/commonjs/types/models/KlarnaSubscription.js +6 -0
  90. package/lib/commonjs/types/models/KlarnaSubscription.js.map +1 -0
  91. package/lib/commonjs/types/models/KlarnaSupplementaryPurchaseData.js +6 -0
  92. package/lib/commonjs/types/models/KlarnaSupplementaryPurchaseData.js.map +1 -0
  93. package/lib/commonjs/types/models/index.js +2 -0
  94. package/lib/commonjs/types/models/index.js.map +1 -0
  95. package/lib/module/KlarnaNetworkPayment.js +2 -0
  96. package/lib/module/KlarnaNetworkPayment.js.map +1 -0
  97. package/lib/module/KlarnaNetworkPaymentImpl.js +36 -0
  98. package/lib/module/KlarnaNetworkPaymentImpl.js.map +1 -0
  99. package/lib/module/KlarnaNetworkPaymentMapper.js +146 -0
  100. package/lib/module/KlarnaNetworkPaymentMapper.js.map +1 -0
  101. package/lib/module/KlarnaPaymentButton.js +37 -0
  102. package/lib/module/KlarnaPaymentButton.js.map +1 -0
  103. package/lib/module/Specs/KlarnaPaymentButtonNativeComponent.js +3 -0
  104. package/lib/module/Specs/KlarnaPaymentButtonNativeComponent.js.map +1 -0
  105. package/lib/module/Specs/NativeKlarnaNetworkPayment.js +9 -0
  106. package/lib/module/Specs/NativeKlarnaNetworkPayment.js.map +1 -0
  107. package/lib/module/index.js +40 -0
  108. package/lib/module/index.js.map +1 -0
  109. package/lib/module/types/KlarnaPaymentRequest.js +2 -0
  110. package/lib/module/types/KlarnaPaymentRequest.js.map +1 -0
  111. package/lib/module/types/KlarnaPaymentRequestState.js +2 -0
  112. package/lib/module/types/KlarnaPaymentRequestState.js.map +1 -0
  113. package/lib/module/types/KlarnaPaymentRequestStateContext.js +2 -0
  114. package/lib/module/types/KlarnaPaymentRequestStateContext.js.map +1 -0
  115. package/lib/module/types/KlarnaPaymentRequestStateReason.js +2 -0
  116. package/lib/module/types/KlarnaPaymentRequestStateReason.js.map +1 -0
  117. package/lib/module/types/models/KlarnaBillingPlan.js +2 -0
  118. package/lib/module/types/models/KlarnaBillingPlan.js.map +1 -0
  119. package/lib/module/types/models/KlarnaCollectCustomerProfileType.js +2 -0
  120. package/lib/module/types/models/KlarnaCollectCustomerProfileType.js.map +1 -0
  121. package/lib/module/types/models/KlarnaCustomer.js +2 -0
  122. package/lib/module/types/models/KlarnaCustomer.js.map +1 -0
  123. package/lib/module/types/models/KlarnaFreeTrial.js +2 -0
  124. package/lib/module/types/models/KlarnaFreeTrial.js.map +1 -0
  125. package/lib/module/types/models/KlarnaInterval.js +2 -0
  126. package/lib/module/types/models/KlarnaInterval.js.map +1 -0
  127. package/lib/module/types/models/KlarnaLineItem.js +2 -0
  128. package/lib/module/types/models/KlarnaLineItem.js.map +1 -0
  129. package/lib/module/types/models/KlarnaOndemandService.js +2 -0
  130. package/lib/module/types/models/KlarnaOndemandService.js.map +1 -0
  131. package/lib/module/types/models/KlarnaPartnerCustomer.js +2 -0
  132. package/lib/module/types/models/KlarnaPartnerCustomer.js.map +1 -0
  133. package/lib/module/types/models/KlarnaPaymentPresentation.js +2 -0
  134. package/lib/module/types/models/KlarnaPaymentPresentation.js.map +1 -0
  135. package/lib/module/types/models/KlarnaPaymentRequestData.js +2 -0
  136. package/lib/module/types/models/KlarnaPaymentRequestData.js.map +1 -0
  137. package/lib/module/types/models/KlarnaRequestCustomerToken.js +2 -0
  138. package/lib/module/types/models/KlarnaRequestCustomerToken.js.map +1 -0
  139. package/lib/module/types/models/KlarnaRequestCustomerTokenScope.js +2 -0
  140. package/lib/module/types/models/KlarnaRequestCustomerTokenScope.js.map +1 -0
  141. package/lib/module/types/models/KlarnaShipping.js +2 -0
  142. package/lib/module/types/models/KlarnaShipping.js.map +1 -0
  143. package/lib/module/types/models/KlarnaShippingConfig.js +2 -0
  144. package/lib/module/types/models/KlarnaShippingConfig.js.map +1 -0
  145. package/lib/module/types/models/KlarnaShippingConfigMode.js +2 -0
  146. package/lib/module/types/models/KlarnaShippingConfigMode.js.map +1 -0
  147. package/lib/module/types/models/KlarnaShippingOption.js +2 -0
  148. package/lib/module/types/models/KlarnaShippingOption.js.map +1 -0
  149. package/lib/module/types/models/KlarnaShippingRecipient.js +2 -0
  150. package/lib/module/types/models/KlarnaShippingRecipient.js.map +1 -0
  151. package/lib/module/types/models/KlarnaShippingType.js +2 -0
  152. package/lib/module/types/models/KlarnaShippingType.js.map +1 -0
  153. package/lib/module/types/models/KlarnaShippingTypeAttribute.js +2 -0
  154. package/lib/module/types/models/KlarnaShippingTypeAttribute.js.map +1 -0
  155. package/lib/module/types/models/KlarnaSubscription.js +2 -0
  156. package/lib/module/types/models/KlarnaSubscription.js.map +1 -0
  157. package/lib/module/types/models/KlarnaSupplementaryPurchaseData.js +2 -0
  158. package/lib/module/types/models/KlarnaSupplementaryPurchaseData.js.map +1 -0
  159. package/lib/module/types/models/index.js +2 -0
  160. package/lib/module/types/models/index.js.map +1 -0
  161. package/lib/typescript/KlarnaNetworkPayment.d.ts +22 -0
  162. package/lib/typescript/KlarnaNetworkPayment.d.ts.map +1 -0
  163. package/lib/typescript/KlarnaNetworkPaymentImpl.d.ts +12 -0
  164. package/lib/typescript/KlarnaNetworkPaymentImpl.d.ts.map +1 -0
  165. package/lib/typescript/KlarnaNetworkPaymentMapper.d.ts +273 -0
  166. package/lib/typescript/KlarnaNetworkPaymentMapper.d.ts.map +1 -0
  167. package/lib/typescript/KlarnaPaymentButton.d.ts +51 -0
  168. package/lib/typescript/KlarnaPaymentButton.d.ts.map +1 -0
  169. package/lib/typescript/Specs/KlarnaPaymentButtonNativeComponent.d.ts +16 -0
  170. package/lib/typescript/Specs/KlarnaPaymentButtonNativeComponent.d.ts.map +1 -0
  171. package/lib/typescript/Specs/NativeKlarnaNetworkPayment.d.ts +13 -0
  172. package/lib/typescript/Specs/NativeKlarnaNetworkPayment.d.ts.map +1 -0
  173. package/lib/typescript/index.d.ts +14 -0
  174. package/lib/typescript/index.d.ts.map +1 -0
  175. package/lib/typescript/types/KlarnaPaymentRequest.d.ts +19 -0
  176. package/lib/typescript/types/KlarnaPaymentRequest.d.ts.map +1 -0
  177. package/lib/typescript/types/KlarnaPaymentRequestState.d.ts +15 -0
  178. package/lib/typescript/types/KlarnaPaymentRequestState.d.ts.map +1 -0
  179. package/lib/typescript/types/KlarnaPaymentRequestStateContext.d.ts +12 -0
  180. package/lib/typescript/types/KlarnaPaymentRequestStateContext.d.ts.map +1 -0
  181. package/lib/typescript/types/KlarnaPaymentRequestStateReason.d.ts +13 -0
  182. package/lib/typescript/types/KlarnaPaymentRequestStateReason.d.ts.map +1 -0
  183. package/lib/typescript/types/models/KlarnaBillingPlan.d.ts +17 -0
  184. package/lib/typescript/types/models/KlarnaBillingPlan.d.ts.map +1 -0
  185. package/lib/typescript/types/models/KlarnaCollectCustomerProfileType.d.ts +19 -0
  186. package/lib/typescript/types/models/KlarnaCollectCustomerProfileType.d.ts.map +1 -0
  187. package/lib/typescript/types/models/KlarnaCustomer.d.ts +11 -0
  188. package/lib/typescript/types/models/KlarnaCustomer.d.ts.map +1 -0
  189. package/lib/typescript/types/models/KlarnaFreeTrial.d.ts +7 -0
  190. package/lib/typescript/types/models/KlarnaFreeTrial.d.ts.map +1 -0
  191. package/lib/typescript/types/models/KlarnaInterval.d.ts +11 -0
  192. package/lib/typescript/types/models/KlarnaInterval.d.ts.map +1 -0
  193. package/lib/typescript/types/models/KlarnaLineItem.d.ts +28 -0
  194. package/lib/typescript/types/models/KlarnaLineItem.d.ts.map +1 -0
  195. package/lib/typescript/types/models/KlarnaOndemandService.d.ts +17 -0
  196. package/lib/typescript/types/models/KlarnaOndemandService.d.ts.map +1 -0
  197. package/lib/typescript/types/models/KlarnaPartnerCustomer.d.ts +15 -0
  198. package/lib/typescript/types/models/KlarnaPartnerCustomer.d.ts.map +1 -0
  199. package/lib/typescript/types/models/KlarnaPaymentPresentation.d.ts +119 -0
  200. package/lib/typescript/types/models/KlarnaPaymentPresentation.d.ts.map +1 -0
  201. package/lib/typescript/types/models/KlarnaPaymentRequestData.d.ts +24 -0
  202. package/lib/typescript/types/models/KlarnaPaymentRequestData.d.ts.map +1 -0
  203. package/lib/typescript/types/models/KlarnaRequestCustomerToken.d.ts +9 -0
  204. package/lib/typescript/types/models/KlarnaRequestCustomerToken.d.ts.map +1 -0
  205. package/lib/typescript/types/models/KlarnaRequestCustomerTokenScope.d.ts +9 -0
  206. package/lib/typescript/types/models/KlarnaRequestCustomerTokenScope.d.ts.map +1 -0
  207. package/lib/typescript/types/models/KlarnaShipping.d.ts +15 -0
  208. package/lib/typescript/types/models/KlarnaShipping.d.ts.map +1 -0
  209. package/lib/typescript/types/models/KlarnaShippingConfig.d.ts +9 -0
  210. package/lib/typescript/types/models/KlarnaShippingConfig.d.ts.map +1 -0
  211. package/lib/typescript/types/models/KlarnaShippingConfigMode.d.ts +5 -0
  212. package/lib/typescript/types/models/KlarnaShippingConfigMode.d.ts.map +1 -0
  213. package/lib/typescript/types/models/KlarnaShippingOption.d.ts +12 -0
  214. package/lib/typescript/types/models/KlarnaShippingOption.d.ts.map +1 -0
  215. package/lib/typescript/types/models/KlarnaShippingRecipient.d.ts +14 -0
  216. package/lib/typescript/types/models/KlarnaShippingRecipient.d.ts.map +1 -0
  217. package/lib/typescript/types/models/KlarnaShippingType.d.ts +25 -0
  218. package/lib/typescript/types/models/KlarnaShippingType.d.ts.map +1 -0
  219. package/lib/typescript/types/models/KlarnaShippingTypeAttribute.d.ts +21 -0
  220. package/lib/typescript/types/models/KlarnaShippingTypeAttribute.d.ts.map +1 -0
  221. package/lib/typescript/types/models/KlarnaSubscription.d.ts +14 -0
  222. package/lib/typescript/types/models/KlarnaSubscription.d.ts.map +1 -0
  223. package/lib/typescript/types/models/KlarnaSupplementaryPurchaseData.d.ts +21 -0
  224. package/lib/typescript/types/models/KlarnaSupplementaryPurchaseData.d.ts.map +1 -0
  225. package/lib/typescript/types/models/index.d.ts +22 -0
  226. package/lib/typescript/types/models/index.d.ts.map +1 -0
  227. package/package.json +120 -6
  228. package/react-native-klarna-network-payment.podspec +28 -0
  229. package/src/KlarnaNetworkPayment.ts +30 -0
  230. package/src/KlarnaNetworkPaymentImpl.ts +79 -0
  231. package/src/KlarnaNetworkPaymentMapper.ts +204 -0
  232. package/src/KlarnaPaymentButton.tsx +80 -0
  233. package/src/Specs/KlarnaPaymentButtonNativeComponent.ts +22 -0
  234. package/src/Specs/NativeKlarnaNetworkPayment.ts +17 -0
  235. package/src/index.tsx +63 -0
  236. package/src/types/KlarnaPaymentRequest.ts +19 -0
  237. package/src/types/KlarnaPaymentRequestState.ts +14 -0
  238. package/src/types/KlarnaPaymentRequestStateContext.ts +12 -0
  239. package/src/types/KlarnaPaymentRequestStateReason.ts +12 -0
  240. package/src/types/models/KlarnaBillingPlan.ts +17 -0
  241. package/src/types/models/KlarnaCollectCustomerProfileType.ts +18 -0
  242. package/src/types/models/KlarnaCustomer.ts +11 -0
  243. package/src/types/models/KlarnaFreeTrial.ts +6 -0
  244. package/src/types/models/KlarnaInterval.ts +10 -0
  245. package/src/types/models/KlarnaLineItem.ts +27 -0
  246. package/src/types/models/KlarnaOndemandService.ts +17 -0
  247. package/src/types/models/KlarnaPartnerCustomer.ts +15 -0
  248. package/src/types/models/KlarnaPaymentPresentation.ts +135 -0
  249. package/src/types/models/KlarnaPaymentRequestData.ts +24 -0
  250. package/src/types/models/KlarnaRequestCustomerToken.ts +9 -0
  251. package/src/types/models/KlarnaRequestCustomerTokenScope.ts +8 -0
  252. package/src/types/models/KlarnaShipping.ts +15 -0
  253. package/src/types/models/KlarnaShippingConfig.ts +9 -0
  254. package/src/types/models/KlarnaShippingConfigMode.ts +4 -0
  255. package/src/types/models/KlarnaShippingOption.ts +12 -0
  256. package/src/types/models/KlarnaShippingRecipient.ts +13 -0
  257. package/src/types/models/KlarnaShippingType.ts +24 -0
  258. package/src/types/models/KlarnaShippingTypeAttribute.ts +20 -0
  259. package/src/types/models/KlarnaSubscription.ts +14 -0
  260. package/src/types/models/KlarnaSupplementaryPurchaseData.ts +21 -0
  261. package/src/types/models/index.ts +35 -0
@@ -0,0 +1,276 @@
1
+ package com.klarna.mobile.sdk.reactnative.klarnanetwork.payment
2
+
3
+ import android.content.res.Configuration
4
+ import android.os.Handler
5
+ import android.os.Looper
6
+ import android.os.SystemClock
7
+ import android.view.Choreographer
8
+ import android.view.View
9
+ import android.view.ViewGroup
10
+ import android.view.ViewTreeObserver
11
+ import android.widget.FrameLayout
12
+ import com.facebook.react.bridge.ReactContext
13
+ import com.facebook.react.uimanager.ThemedReactContext
14
+ import com.facebook.react.uimanager.UIManagerHelper
15
+ import com.klarna.mobile.sdk.api.KlarnaTheme
16
+ import com.klarna.mobile.sdk.api.button.KlarnaButtonShape
17
+ import com.klarna.mobile.sdk.api.button.KlarnaButtonStyle
18
+ import com.klarna.mobile.sdk.klarna.network.core.api.button.KlarnaButtonState
19
+ import com.klarna.mobile.sdk.klarna.network.payment.button.api.KlarnaPaymentButton
20
+ import com.klarna.mobile.sdk.klarna.network.payment.button.api.KlarnaPaymentButtonConfiguration
21
+ import com.klarna.mobile.sdk.klarna.network.payment.button.api.KlarnaPaymentButtonIntent
22
+ import com.klarna.mobile.sdk.reactnative.klarnanetwork.core.KlarnaNetworkCoreModuleImpl
23
+
24
+ class KlarnaPaymentButtonViewManager : KlarnaNetworkPaymentButtonViewSpec<FrameLayout>() {
25
+
26
+ companion object {
27
+ const val REACT_CLASS = "KlarnaNetworkPaymentButton"
28
+ // Staggered re-measure delays to catch async content loads inside KlarnaPaymentButton.
29
+ private val LAYOUT_RETRY_DELAYS_MS = longArrayOf(100, 500, 1500)
30
+ }
31
+
32
+ private val handler = Handler(Looper.getMainLooper())
33
+ private val viewStates = mutableMapOf<FrameLayout, ViewState>()
34
+
35
+ override fun getName(): String = REACT_CLASS
36
+
37
+ override fun createViewInstance(context: ThemedReactContext): FrameLayout {
38
+ val view = FrameLayout(context)
39
+ viewStates[view] = ViewState()
40
+ return view
41
+ }
42
+
43
+ override fun setInstanceId(view: FrameLayout?, value: String?) {
44
+ view ?: return
45
+ if (viewStates[view]?.instanceId == value) return
46
+ viewStates[view]?.instanceId = value
47
+ scheduleButtonCreation(view)
48
+ }
49
+
50
+ override fun setState(view: FrameLayout?, value: String?) {
51
+ view ?: return
52
+ viewStates[view]?.state = value
53
+ val button = view.getChildAt(0) as? KlarnaPaymentButton
54
+ if (button != null) {
55
+ // State can be updated in-place without recreating the button.
56
+ button.state = parseState(value)
57
+ } else {
58
+ scheduleButtonCreation(view)
59
+ }
60
+ }
61
+
62
+ override fun setIntent(view: FrameLayout?, value: String?) {
63
+ view ?: return
64
+ viewStates[view]?.intent = value
65
+ scheduleButtonCreation(view)
66
+ }
67
+
68
+ override fun setShape(view: FrameLayout?, value: String?) {
69
+ view ?: return
70
+ viewStates[view]?.shape = value
71
+ scheduleButtonCreation(view)
72
+ }
73
+
74
+ override fun setButtonStyle(view: FrameLayout?, value: String?) {
75
+ view ?: return
76
+ viewStates[view]?.buttonStyle = value
77
+ scheduleButtonCreation(view)
78
+ }
79
+
80
+ override fun setTheme(view: FrameLayout?, value: String?) {
81
+ view ?: return
82
+ viewStates[view]?.theme = value
83
+ scheduleButtonCreation(view)
84
+ }
85
+
86
+ override fun onDropViewInstance(view: FrameLayout) {
87
+ tearDownButton(view)
88
+ viewStates.remove(view)
89
+ super.onDropViewInstance(view)
90
+ }
91
+
92
+ private fun tearDownButton(view: FrameLayout) {
93
+ removePreDrawListener(view)
94
+ handler.removeCallbacksAndMessages(view)
95
+ view.removeAllViews()
96
+ }
97
+
98
+ private fun removePreDrawListener(view: FrameLayout) {
99
+ val state = viewStates[view] ?: return
100
+ val (button, listener) = state.preDrawListener ?: return
101
+ state.preDrawListener = null
102
+ val observer = button.viewTreeObserver
103
+ if (observer.isAlive) observer.removeOnPreDrawListener(listener)
104
+ }
105
+
106
+ private fun scheduleButtonCreation(view: FrameLayout) {
107
+ val state = viewStates[view] ?: return
108
+ if (state.pendingCreate) return
109
+ state.pendingCreate = true
110
+ Choreographer.getInstance().postFrameCallback {
111
+ state.pendingCreate = false
112
+ tearDownButton(view)
113
+ createButton(view)
114
+ }
115
+ }
116
+
117
+ private fun nextGeneration(view: FrameLayout): Int {
118
+ val state = viewStates[view] ?: return 0
119
+ return ++state.generation
120
+ }
121
+
122
+ private fun isCurrentGeneration(view: FrameLayout, generation: Int): Boolean =
123
+ viewStates[view]?.generation == generation
124
+
125
+ private fun createButton(view: FrameLayout) {
126
+ val state = viewStates[view] ?: return
127
+ val instanceId = state.instanceId ?: return
128
+ val sdk = KlarnaNetworkCoreModuleImpl.getInstance(instanceId) ?: return
129
+
130
+ val configuration = KlarnaPaymentButtonConfiguration(
131
+ intent = parseIntent(state.intent),
132
+ state = parseState(state.state),
133
+ shape = parseShape(state.shape),
134
+ style = parseStyle(state.buttonStyle),
135
+ theme = parseTheme(state.theme),
136
+ )
137
+
138
+ try {
139
+ val button = KlarnaPaymentButton(view.context, sdk, configuration)
140
+ button.setOnClickListener {
141
+ val reactContext = view.context as? ReactContext ?: return@setOnClickListener
142
+ UIManagerHelper.getEventDispatcherForReactTag(reactContext, view.id)
143
+ ?.dispatchEvent(KlarnaPaymentButtonPressEvent(UIManagerHelper.getSurfaceId(view), view.id))
144
+ }
145
+ view.addView(button, ViewGroup.LayoutParams(
146
+ ViewGroup.LayoutParams.MATCH_PARENT,
147
+ ViewGroup.LayoutParams.WRAP_CONTENT,
148
+ ))
149
+ val generation = nextGeneration(view)
150
+ setupManualLayout(view, button, generation)
151
+ } catch (e: Exception) {
152
+ android.util.Log.e(REACT_CLASS, "Failed to create KlarnaPaymentButton", e)
153
+ }
154
+ }
155
+
156
+ private fun setupManualLayout(view: FrameLayout, button: KlarnaPaymentButton, generation: Int) {
157
+ // Phase 1: frame-by-frame polling until the button height stabilises.
158
+ // Capped at maxFrames to prevent an indefinite loop if the button never reports
159
+ // a positive height (e.g. SDK error or missing data).
160
+ val maxFrames = 90
161
+ var frameCount = 0
162
+ val lastHeightPx = intArrayOf(-1)
163
+ val stableFrameCount = intArrayOf(0)
164
+ val frameCallback = object : Choreographer.FrameCallback {
165
+ override fun doFrame(frameTimeNanos: Long) {
166
+ if (!isCurrentGeneration(view, generation) || !button.isAttachedToWindow) return
167
+ frameCount++
168
+ measureAndLayout(view, button)
169
+ val currentHeightPx = button.height
170
+ when {
171
+ currentHeightPx <= 0 -> stableFrameCount[0] = 0
172
+ currentHeightPx == lastHeightPx[0] -> stableFrameCount[0]++
173
+ else -> stableFrameCount[0] = 0
174
+ }
175
+ lastHeightPx[0] = currentHeightPx
176
+ if (frameCount < maxFrames && (currentHeightPx <= 0 || stableFrameCount[0] < 3)) {
177
+ Choreographer.getInstance().postFrameCallback(this)
178
+ }
179
+ }
180
+ }
181
+ Choreographer.getInstance().postFrameCallback(frameCallback)
182
+
183
+ // Phase 2: OnPreDrawListener catches any subsequent layout changes once the
184
+ // button's internal content finishes loading and triggers a redraw.
185
+ val preDrawListener = ViewTreeObserver.OnPreDrawListener {
186
+ if (isCurrentGeneration(view, generation) && button.isAttachedToWindow) {
187
+ measureAndLayout(view, button)
188
+ }
189
+ true
190
+ }
191
+ button.viewTreeObserver.addOnPreDrawListener(preDrawListener)
192
+ viewStates[view]?.preDrawListener = button to preDrawListener
193
+
194
+ // Phase 3: staggered re-measures to catch async content loads that may not
195
+ // trigger a layout pass on their own (same pattern as KlarnaMessagingPlacementViewManager).
196
+ for (delay in LAYOUT_RETRY_DELAYS_MS) {
197
+ handler.postAtTime({
198
+ if (isCurrentGeneration(view, generation) && button.isAttachedToWindow) {
199
+ measureAndLayout(view, button)
200
+ }
201
+ }, view, SystemClock.uptimeMillis() + delay)
202
+ }
203
+ }
204
+
205
+ private fun measureAndLayout(view: FrameLayout, button: KlarnaPaymentButton) {
206
+ val containerWidth = view.measuredWidth
207
+ val containerHeight = view.measuredHeight
208
+ if (containerWidth <= 0) return
209
+ // First pass: unspecified height so the button reports its natural minimum.
210
+ button.measure(
211
+ View.MeasureSpec.makeMeasureSpec(containerWidth, View.MeasureSpec.EXACTLY),
212
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
213
+ )
214
+ // naturalHeight must be read AFTER measure() so it reflects the button's actual content.
215
+ val naturalHeight = button.measuredHeight
216
+ // Button content not yet loaded — bail out and let Phase 1/3 retry.
217
+ if (naturalHeight <= 0) return
218
+ // Grow freely with the container, but never shrink below the button's natural minimum.
219
+ val height = maxOf(containerHeight, naturalHeight)
220
+ // Second pass: commit the resolved height so the button lays itself out correctly.
221
+ button.measure(
222
+ View.MeasureSpec.makeMeasureSpec(containerWidth, View.MeasureSpec.EXACTLY),
223
+ View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY),
224
+ )
225
+ button.layout(0, 0, button.measuredWidth, button.measuredHeight)
226
+ button.requestLayout()
227
+ }
228
+
229
+ // region Prop parsing
230
+
231
+ internal fun parseState(value: String?): KlarnaButtonState = when (value) {
232
+ "disabled" -> KlarnaButtonState.DISABLED
233
+ "loading" -> KlarnaButtonState.LOADING
234
+ else -> KlarnaButtonState.DEFAULT
235
+ }
236
+
237
+ internal fun parseIntent(value: String?): KlarnaPaymentButtonIntent = when (value) {
238
+ "subscribe" -> KlarnaPaymentButtonIntent.SUBSCRIBE
239
+ "addToWallet" -> KlarnaPaymentButtonIntent.ADD_TO_WALLET
240
+ else -> KlarnaPaymentButtonIntent.PAY
241
+ }
242
+
243
+ internal fun parseShape(value: String?): KlarnaButtonShape = when (value) {
244
+ "roundedRect" -> KlarnaButtonShape.ROUNDED_RECT
245
+ "pill" -> KlarnaButtonShape.PILL
246
+ "rectangle" -> KlarnaButtonShape.RECTANGLE
247
+ else -> KlarnaButtonShape.ROUNDED_RECT
248
+ }
249
+
250
+ internal fun parseStyle(value: String?): KlarnaButtonStyle = when (value) {
251
+ "filled" -> KlarnaButtonStyle.FILLED
252
+ "outlined" -> KlarnaButtonStyle.OUTLINED
253
+ else -> KlarnaButtonStyle.FILLED
254
+ }
255
+
256
+ internal fun parseTheme(value: String?): KlarnaTheme = when (value) {
257
+ "light" -> KlarnaTheme.LIGHT
258
+ "dark" -> KlarnaTheme.DARK
259
+ "automatic" -> KlarnaTheme.AUTOMATIC
260
+ else -> KlarnaTheme.DARK
261
+ }
262
+
263
+ // endregion
264
+
265
+ private data class ViewState(
266
+ var instanceId: String? = null,
267
+ var state: String? = null,
268
+ var intent: String? = null,
269
+ var shape: String? = null,
270
+ var buttonStyle: String? = null,
271
+ var theme: String? = null,
272
+ var pendingCreate: Boolean = false,
273
+ var generation: Int = 0,
274
+ var preDrawListener: Pair<KlarnaPaymentButton, ViewTreeObserver.OnPreDrawListener>? = null,
275
+ )
276
+ }
@@ -0,0 +1,132 @@
1
+ package com.klarna.mobile.sdk.reactnative.klarnanetwork.payment
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.WritableMap
5
+ import com.klarna.mobile.sdk.klarna.network.payment.api.presentation.models.KlarnaPaymentPresentationContent
6
+ import com.klarna.mobile.sdk.klarna.network.payment.api.presentation.models.KlarnaPaymentPresentationIcon
7
+ import com.klarna.mobile.sdk.klarna.network.payment.api.presentation.models.KlarnaPaymentPresentationPaymentButton
8
+ import com.klarna.mobile.sdk.klarna.network.payment.api.presentation.models.KlarnaPaymentPresentationPaymentOption
9
+ import com.klarna.mobile.sdk.klarna.network.payment.api.presentation.models.KlarnaPaymentPresentationText
10
+ import com.klarna.mobile.sdk.klarna.network.payment.api.presentation.models.KlarnaPaymentPresentationTextPart
11
+
12
+ internal fun KlarnaPaymentPresentationContent.toWritableMap(): WritableMap = Arguments.createMap().apply {
13
+ putString(PresentationKeys.INSTRUCTION, instruction.toString())
14
+ putString(PresentationKeys.PAYMENT_STATUS, paymentStatus?.toString())
15
+ val opt = paymentOption
16
+ if (opt != null) putMap(PresentationKeys.PAYMENT_OPTION, opt.toWritableMap()) else putNull(PresentationKeys.PAYMENT_OPTION)
17
+ val saved = savedPaymentOption
18
+ if (saved != null) putMap(PresentationKeys.SAVED_PAYMENT_OPTION, saved.toWritableMap()) else putNull(PresentationKeys.SAVED_PAYMENT_OPTION)
19
+ }
20
+
21
+ internal fun KlarnaPaymentPresentationPaymentOption.toWritableMap(): WritableMap = Arguments.createMap().apply {
22
+ putString(PresentationKeys.PAYMENT_OPTION_ID, paymentOptionId)
23
+ val h = header; if (h != null) putMap(PresentationKeys.HEADER, h.toWritableMap()) else putNull(PresentationKeys.HEADER)
24
+ val b = badge; if (b != null) putMap(PresentationKeys.BADGE, b.toWritableMap()) else putNull(PresentationKeys.BADGE)
25
+ val sub = subheader; if (sub != null) putMap(PresentationKeys.SUBHEADER, sub.toWritableMap()) else putNull(PresentationKeys.SUBHEADER)
26
+ val msg = message; if (msg != null) putMap(PresentationKeys.MESSAGE, msg.toWritableMap()) else putNull(PresentationKeys.MESSAGE)
27
+ val t = terms; if (t != null) putMap(PresentationKeys.TERMS, t.toWritableMap()) else putNull(PresentationKeys.TERMS)
28
+ val btn = paymentButton; if (btn != null) putMap(PresentationKeys.PAYMENT_BUTTON, btn.toWritableMap()) else putNull(PresentationKeys.PAYMENT_BUTTON)
29
+ val ic = icon; if (ic != null) putMap(PresentationKeys.ICON, ic.toWritableMap()) else putNull(PresentationKeys.ICON)
30
+ }
31
+
32
+ internal fun KlarnaPaymentPresentationText.toWritableMap(): WritableMap = Arguments.createMap().apply {
33
+ when (this@toWritableMap) {
34
+ is KlarnaPaymentPresentationText.PlainText -> {
35
+ putString(PresentationKeys.TYPE, PresentationKeys.TYPE_PLAIN_TEXT)
36
+ putString(PresentationKeys.TEXT, text)
37
+ }
38
+ is KlarnaPaymentPresentationText.AttributedText -> {
39
+ putString(PresentationKeys.TYPE, PresentationKeys.TYPE_ATTRIBUTED_TEXT)
40
+ val parts = this@toWritableMap.parts
41
+ if (parts != null) {
42
+ val arr = Arguments.createArray()
43
+ parts.forEach { arr.pushMap(it.toWritableMap()) }
44
+ putArray(PresentationKeys.PARTS, arr)
45
+ } else {
46
+ putNull(PresentationKeys.PARTS)
47
+ }
48
+ }
49
+ }
50
+ }
51
+
52
+ internal fun KlarnaPaymentPresentationTextPart.toWritableMap(): WritableMap = Arguments.createMap().apply {
53
+ when (this@toWritableMap) {
54
+ is KlarnaPaymentPresentationTextPart.PlainText -> {
55
+ putString(PresentationKeys.TYPE, PresentationKeys.TYPE_PLAIN)
56
+ putString(PresentationKeys.TEXT, text)
57
+ val s = styles
58
+ if (s != null) {
59
+ val arr = Arguments.createArray(); s.forEach { arr.pushString(it.toString()) }
60
+ putArray(PresentationKeys.STYLES, arr)
61
+ } else putNull(PresentationKeys.STYLES)
62
+ }
63
+ is KlarnaPaymentPresentationTextPart.Link -> {
64
+ putString(PresentationKeys.TYPE, PresentationKeys.TYPE_LINK)
65
+ putString(PresentationKeys.TEXT, text)
66
+ putString(PresentationKeys.URL, url)
67
+ putString(PresentationKeys.CONTEXT, context?.toString())
68
+ val s = styles
69
+ if (s != null) {
70
+ val arr = Arguments.createArray(); s.forEach { arr.pushString(it.toString()) }
71
+ putArray(PresentationKeys.STYLES, arr)
72
+ } else putNull(PresentationKeys.STYLES)
73
+ }
74
+ }
75
+ }
76
+
77
+ internal fun KlarnaPaymentPresentationPaymentButton.toWritableMap(): WritableMap = Arguments.createMap().apply {
78
+ putString(PresentationKeys.TEXT, text)
79
+ putString(PresentationKeys.IMAGE_URL, imageUrl)
80
+ putString(PresentationKeys.IMAGE_ALIGNMENT, imageAlignment?.toString())
81
+ }
82
+
83
+ internal fun KlarnaPaymentPresentationIcon.toWritableMap(): WritableMap = Arguments.createMap().apply {
84
+ putString(PresentationKeys.ALT, alt)
85
+ putString(PresentationKeys.BADGE_IMAGE_URL, badgeImageUrl)
86
+ putString(PresentationKeys.RECTANGLE_IMAGE_URL, rectangleImageUrl)
87
+ putString(PresentationKeys.SQUARE_IMAGE_URL, squareImageUrl)
88
+ }
89
+
90
+ private object PresentationKeys {
91
+ // KlarnaPaymentPresentationContent
92
+ const val INSTRUCTION = "instruction"
93
+ const val PAYMENT_STATUS = "paymentStatus"
94
+ const val PAYMENT_OPTION = "paymentOption"
95
+ const val SAVED_PAYMENT_OPTION = "savedPaymentOption"
96
+
97
+ // KlarnaPaymentPresentationPaymentOption
98
+ const val PAYMENT_OPTION_ID = "paymentOptionId"
99
+ const val HEADER = "header"
100
+ const val BADGE = "badge"
101
+ const val SUBHEADER = "subheader"
102
+ const val MESSAGE = "message"
103
+ const val TERMS = "terms"
104
+ const val PAYMENT_BUTTON = "paymentButton"
105
+ const val ICON = "icon"
106
+
107
+ // KlarnaPaymentPresentationText / KlarnaPaymentPresentationTextPart (shared keys)
108
+ const val TYPE = "type"
109
+ const val TEXT = "text"
110
+ const val PARTS = "parts"
111
+ const val STYLES = "styles"
112
+ const val URL = "url"
113
+ const val CONTEXT = "context"
114
+
115
+ // Type discriminator values — KlarnaPaymentPresentationText
116
+ const val TYPE_PLAIN_TEXT = "plainText"
117
+ const val TYPE_ATTRIBUTED_TEXT = "attributedText"
118
+
119
+ // Type discriminator values — KlarnaPaymentPresentationTextPart
120
+ const val TYPE_PLAIN = "plain"
121
+ const val TYPE_LINK = "link"
122
+
123
+ // KlarnaPaymentPresentationPaymentButton
124
+ const val IMAGE_URL = "imageUrl"
125
+ const val IMAGE_ALIGNMENT = "imageAlignment"
126
+
127
+ // KlarnaPaymentPresentationIcon
128
+ const val ALT = "alt"
129
+ const val BADGE_IMAGE_URL = "badgeImageUrl"
130
+ const val RECTANGLE_IMAGE_URL = "rectangleImageUrl"
131
+ const val SQUARE_IMAGE_URL = "squareImageUrl"
132
+ }