@stripe/stripe-react-native 0.61.0 → 0.62.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 (102) hide show
  1. package/android/.idea/.name +1 -0
  2. package/android/.idea/AndroidProjectSystem.xml +6 -0
  3. package/android/.idea/android.iml +9 -0
  4. package/android/.idea/caches/deviceStreaming.xml +1550 -0
  5. package/android/.idea/compiler.xml +6 -0
  6. package/android/.idea/gradle.xml +19 -0
  7. package/android/.idea/kotlinc.xml +7 -0
  8. package/android/.idea/migrations.xml +10 -0
  9. package/android/.idea/misc.xml +10 -0
  10. package/android/.idea/runConfigurations.xml +17 -0
  11. package/android/.idea/vcs.xml +6 -0
  12. package/android/gradle.properties +2 -2
  13. package/android/local.properties +8 -0
  14. package/android/src/main/java/com/reactnativestripesdk/PaymentSheetManager.kt +200 -198
  15. package/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt +3 -1
  16. package/android/src/main/java/com/reactnativestripesdk/pushprovisioning/AddToWalletButtonView.kt +17 -16
  17. package/ios/Mappers.swift +15 -2
  18. package/lib/commonjs/components/AddToWalletButton.js +1 -1
  19. package/lib/commonjs/components/AddToWalletButton.js.map +1 -1
  20. package/lib/commonjs/components/AddressSheet.js +1 -1
  21. package/lib/commonjs/components/AddressSheet.js.map +1 -1
  22. package/lib/commonjs/components/AuBECSDebitForm.js +1 -1
  23. package/lib/commonjs/components/AuBECSDebitForm.js.map +1 -1
  24. package/lib/commonjs/components/CardField.js +1 -1
  25. package/lib/commonjs/components/CardField.js.map +1 -1
  26. package/lib/commonjs/components/CardForm.js +1 -1
  27. package/lib/commonjs/components/CardForm.js.map +1 -1
  28. package/lib/commonjs/components/PlatformPayButton.js +1 -1
  29. package/lib/commonjs/components/PlatformPayButton.js.map +1 -1
  30. package/lib/commonjs/components/StripeContainer.js +1 -1
  31. package/lib/commonjs/components/StripeContainer.js.map +1 -1
  32. package/lib/commonjs/connect/Components.js +1 -1
  33. package/lib/commonjs/connect/Components.js.map +1 -1
  34. package/lib/commonjs/connect/ConnectComponentsProvider.js +1 -1
  35. package/lib/commonjs/connect/ConnectComponentsProvider.js.map +1 -1
  36. package/lib/commonjs/connect/EmbeddedComponent.js +1 -1
  37. package/lib/commonjs/connect/EmbeddedComponent.js.map +1 -1
  38. package/lib/commonjs/connect/ModalCloseButton.js +1 -1
  39. package/lib/commonjs/connect/ModalCloseButton.js.map +1 -1
  40. package/lib/commonjs/connect/NavigationBar.js +1 -1
  41. package/lib/commonjs/connect/NavigationBar.js.map +1 -1
  42. package/lib/commonjs/helpers.js +1 -1
  43. package/lib/commonjs/specs/NativeAddToWalletButton.js +1 -1
  44. package/lib/commonjs/specs/NativeAddressSheet.js +1 -1
  45. package/lib/commonjs/specs/NativeApplePayButton.js +1 -1
  46. package/lib/commonjs/specs/NativeAuBECSDebitForm.js +1 -1
  47. package/lib/commonjs/specs/NativeCardField.js +1 -1
  48. package/lib/commonjs/specs/NativeCardField.js.map +1 -1
  49. package/lib/commonjs/specs/NativeCardForm.js +1 -1
  50. package/lib/commonjs/specs/NativeCardForm.js.map +1 -1
  51. package/lib/commonjs/specs/NativeConnectAccountOnboardingView.js +1 -1
  52. package/lib/commonjs/specs/NativeEmbeddedPaymentElement.js +1 -1
  53. package/lib/commonjs/specs/NativeEmbeddedPaymentElement.js.map +1 -1
  54. package/lib/commonjs/specs/NativeGooglePayButton.js +1 -1
  55. package/lib/commonjs/specs/NativeNavigationBar.js +1 -1
  56. package/lib/commonjs/specs/NativePaymentMethodMessagingElement.js +1 -1
  57. package/lib/commonjs/specs/NativeStripeContainer.js +1 -1
  58. package/lib/commonjs/types/EmbeddedPaymentElement.js +1 -1
  59. package/lib/commonjs/types/EmbeddedPaymentElement.js.map +1 -1
  60. package/lib/module/components/AddToWalletButton.js +1 -1
  61. package/lib/module/components/AddToWalletButton.js.map +1 -1
  62. package/lib/module/components/AddressSheet.js +1 -1
  63. package/lib/module/components/AddressSheet.js.map +1 -1
  64. package/lib/module/components/AuBECSDebitForm.js +1 -1
  65. package/lib/module/components/AuBECSDebitForm.js.map +1 -1
  66. package/lib/module/components/CardField.js +1 -1
  67. package/lib/module/components/CardField.js.map +1 -1
  68. package/lib/module/components/CardForm.js +1 -1
  69. package/lib/module/components/CardForm.js.map +1 -1
  70. package/lib/module/components/PlatformPayButton.js +1 -1
  71. package/lib/module/components/PlatformPayButton.js.map +1 -1
  72. package/lib/module/components/StripeContainer.js +1 -1
  73. package/lib/module/components/StripeContainer.js.map +1 -1
  74. package/lib/module/connect/Components.js +1 -1
  75. package/lib/module/connect/Components.js.map +1 -1
  76. package/lib/module/connect/ConnectComponentsProvider.js +1 -1
  77. package/lib/module/connect/ConnectComponentsProvider.js.map +1 -1
  78. package/lib/module/connect/EmbeddedComponent.js +1 -1
  79. package/lib/module/connect/EmbeddedComponent.js.map +1 -1
  80. package/lib/module/connect/ModalCloseButton.js +1 -1
  81. package/lib/module/connect/ModalCloseButton.js.map +1 -1
  82. package/lib/module/connect/NavigationBar.js +1 -1
  83. package/lib/module/connect/NavigationBar.js.map +1 -1
  84. package/lib/module/helpers.js +1 -1
  85. package/lib/module/specs/NativeAddToWalletButton.js +1 -1
  86. package/lib/module/specs/NativeAddressSheet.js +1 -1
  87. package/lib/module/specs/NativeApplePayButton.js +1 -1
  88. package/lib/module/specs/NativeAuBECSDebitForm.js +1 -1
  89. package/lib/module/specs/NativeCardField.js +1 -1
  90. package/lib/module/specs/NativeCardField.js.map +1 -1
  91. package/lib/module/specs/NativeCardForm.js +1 -1
  92. package/lib/module/specs/NativeCardForm.js.map +1 -1
  93. package/lib/module/specs/NativeConnectAccountOnboardingView.js +1 -1
  94. package/lib/module/specs/NativeEmbeddedPaymentElement.js +1 -1
  95. package/lib/module/specs/NativeEmbeddedPaymentElement.js.map +1 -1
  96. package/lib/module/specs/NativeGooglePayButton.js +1 -1
  97. package/lib/module/specs/NativeNavigationBar.js +1 -1
  98. package/lib/module/specs/NativePaymentMethodMessagingElement.js +1 -1
  99. package/lib/module/specs/NativeStripeContainer.js +1 -1
  100. package/lib/module/types/EmbeddedPaymentElement.js +1 -1
  101. package/lib/module/types/EmbeddedPaymentElement.js.map +1 -1
  102. package/package.json +1 -1
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="CompilerConfiguration">
4
+ <bytecodeTargetLevel target="17" />
5
+ </component>
6
+ </project>
@@ -0,0 +1,19 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="GradleMigrationSettings" migrationVersion="1" />
4
+ <component name="GradleSettings">
5
+ <option name="linkedExternalProjectsSettings">
6
+ <GradleProjectSettings>
7
+ <option name="testRunner" value="CHOOSE_PER_TEST" />
8
+ <option name="externalProjectPath" value="$PROJECT_DIR$" />
9
+ <option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
10
+ <option name="modules">
11
+ <set>
12
+ <option value="$PROJECT_DIR$" />
13
+ <option value="$PROJECT_DIR$/lint-rules" />
14
+ </set>
15
+ </option>
16
+ </GradleProjectSettings>
17
+ </option>
18
+ </component>
19
+ </project>
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="KotlinJpsPluginSettings">
4
+ <option name="externalSystemId" value="Gradle" />
5
+ <option name="version" value="1.8.0" />
6
+ </component>
7
+ </project>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ProjectMigrations">
4
+ <option name="MigrateToGradleLocalJavaHome">
5
+ <set>
6
+ <option value="$PROJECT_DIR$" />
7
+ </set>
8
+ </option>
9
+ </component>
10
+ </project>
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="ExternalStorageConfigurationManager" enabled="true" />
4
+ <component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
5
+ <output url="file://$PROJECT_DIR$/build/classes" />
6
+ </component>
7
+ <component name="ProjectType">
8
+ <option name="id" value="Android" />
9
+ </component>
10
+ </project>
@@ -0,0 +1,17 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="RunConfigurationProducerService">
4
+ <option name="ignoredProducers">
5
+ <set>
6
+ <option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
7
+ <option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
8
+ <option value="com.intellij.execution.junit.PatternConfigurationProducer" />
9
+ <option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
10
+ <option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
11
+ <option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
12
+ <option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
13
+ <option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
14
+ </set>
15
+ </option>
16
+ </component>
17
+ </project>
@@ -0,0 +1,6 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="VcsDirectoryMappings">
4
+ <mapping directory="$PROJECT_DIR$/.." vcs="Git" />
5
+ </component>
6
+ </project>
@@ -1,6 +1,6 @@
1
- StripeSdk_kotlinVersion=2.3.10
1
+ StripeSdk_kotlinVersion=2.2.21
2
2
  StripeSdk_compileSdkVersion=30
3
3
  StripeSdk_targetSdkVersion=28
4
4
  StripeSdk_minSdkVersion=21
5
5
  # Keep StripeSdk_stripeVersion in sync with https://github.com/stripe/stripe-identity-react-native/blob/main/android/gradle.properties
6
- StripeSdk_stripeVersion=23.1.+
6
+ StripeSdk_stripeVersion=23.2.+
@@ -0,0 +1,8 @@
1
+ ## This file must *NOT* be checked into Version Control Systems,
2
+ # as it contains information specific to your local configuration.
3
+ #
4
+ # Location of the SDK. This is only used by Gradle.
5
+ # For customization when using a Version Control System, please read the
6
+ # header note.
7
+ #Fri Aug 30 15:10:34 EDT 2024
8
+ sdk.dir=/Users/samer/Library/Android/sdk
@@ -86,209 +86,15 @@ class PaymentSheetManager(
86
86
  internal var paymentSheetIntentCreationCallback = CompletableDeferred<ReadableMap>()
87
87
  internal var paymentSheetConfirmationTokenCreationCallback = CompletableDeferred<ReadableMap>()
88
88
  private var keepJsAwake: KeepJsAwakeTask? = null
89
+ private var lastConfigureWasCustomFlow: Boolean? = null
89
90
 
90
91
  @SuppressLint("RestrictedApi")
91
92
  override fun onCreate() {
92
- val activity = getCurrentActivityOrResolveWithError(initPromise) ?: return
93
- val merchantDisplayName = arguments.getString("merchantDisplayName").orEmpty()
94
- if (merchantDisplayName.isEmpty()) {
95
- initPromise.resolve(
96
- createError(ErrorType.Failed.toString(), "merchantDisplayName cannot be empty or null."),
97
- )
98
- return
99
- }
100
- paymentIntentClientSecret = arguments.getString("paymentIntentClientSecret").orEmpty()
101
- setupIntentClientSecret = arguments.getString("setupIntentClientSecret").orEmpty()
102
- intentConfiguration =
103
- try {
104
- buildIntentConfiguration(arguments.getMap("intentConfiguration"))
105
- } catch (error: PaymentSheetException) {
106
- initPromise.resolve(createError(ErrorType.Failed.toString(), error))
107
- return
108
- }
109
-
110
- // Determine which callback type to use based on what's provided
111
- val intentConfigMap = arguments.getMap("intentConfiguration")
112
- val useConfirmationTokenCallback = intentConfigMap?.hasKey("confirmationTokenConfirmHandler") == true
113
-
114
- val paymentOptionCallback =
115
- PaymentOptionResultCallback { paymentOptionResult ->
116
- paymentOptionResult.paymentOption?.let { paymentOption ->
117
- // Convert drawable to bitmap asynchronously to avoid shared state issues
118
- CoroutineScope(Dispatchers.Default).launch {
119
- val imageString =
120
- try {
121
- convertDrawableToBase64(paymentOption.icon())
122
- } catch (e: Exception) {
123
- val result =
124
- createError(
125
- PaymentSheetErrorType.Failed.toString(),
126
- "Failed to process payment option image: ${e.message}",
127
- )
128
- resolvePresentPromise(result)
129
- return@launch
130
- }
131
-
132
- val option: WritableMap = Arguments.createMap()
133
- option.putString("label", paymentOption.label)
134
- option.putString("image", imageString)
135
- val additionalFields: Map<String, Any> = mapOf("didCancel" to paymentOptionResult.didCancel)
136
- val result = createResult("paymentOption", option, additionalFields)
137
- resolvePresentPromise(result)
138
- }
139
- } ?: run {
140
- val result =
141
- if (paymentSheetTimedOut) {
142
- paymentSheetTimedOut = false
143
- createError(PaymentSheetErrorType.Timeout.toString(), "The payment has timed out")
144
- } else {
145
- createError(
146
- PaymentSheetErrorType.Canceled.toString(),
147
- "The payment option selection flow has been canceled",
148
- )
149
- }
150
- resolvePresentPromise(result)
151
- }
152
- }
153
-
154
- val paymentResultCallback =
155
- PaymentSheetResultCallback { paymentResult ->
156
- if (paymentSheetTimedOut) {
157
- paymentSheetTimedOut = false
158
- resolvePaymentResult(
159
- createError(PaymentSheetErrorType.Timeout.toString(), "The payment has timed out"),
160
- )
161
- } else {
162
- when (paymentResult) {
163
- is PaymentSheetResult.Canceled -> {
164
- resolvePaymentResult(
165
- createError(
166
- PaymentSheetErrorType.Canceled.toString(),
167
- "The payment flow has been canceled",
168
- ),
169
- )
170
- }
171
-
172
- is PaymentSheetResult.Failed -> {
173
- resolvePaymentResult(
174
- createError(PaymentSheetErrorType.Failed.toString(), paymentResult.error),
175
- )
176
- }
177
-
178
- is PaymentSheetResult.Completed -> {
179
- resolvePaymentResult(Arguments.createMap())
180
- }
181
- }
182
- }
183
- }
184
-
185
- val createIntentCallback =
186
- CreateIntentCallback { paymentMethod, shouldSavePaymentMethod ->
187
- val stripeSdkModule: StripeSdkModule? = context.getNativeModule(StripeSdkModule::class.java)
188
- val params =
189
- Arguments.createMap().apply {
190
- putMap("paymentMethod", mapFromPaymentMethod(paymentMethod))
191
- putBoolean("shouldSavePaymentMethod", shouldSavePaymentMethod)
192
- }
193
-
194
- stripeSdkModule?.eventEmitter?.emitOnConfirmHandlerCallback(params)
195
-
196
- val resultFromJavascript = paymentSheetIntentCreationCallback.await()
197
- // reset the completable
198
- paymentSheetIntentCreationCallback = CompletableDeferred<ReadableMap>()
199
-
200
- return@CreateIntentCallback resultFromJavascript.getString("clientSecret")?.let {
201
- CreateIntentResult.Success(clientSecret = it)
202
- }
203
- ?: run {
204
- val errorMap = resultFromJavascript.getMap("error")
205
- CreateIntentResult.Failure(
206
- cause = Exception(errorMap?.getString("message")),
207
- displayMessage = errorMap?.getString("localizedMessage"),
208
- )
209
- }
210
- }
211
-
212
- val createConfirmationTokenCallback =
213
- CreateIntentWithConfirmationTokenCallback { confirmationToken ->
214
- val stripeSdkModule: StripeSdkModule? = context.getNativeModule(StripeSdkModule::class.java)
215
- val params =
216
- Arguments.createMap().apply {
217
- putMap("confirmationToken", mapFromConfirmationToken(confirmationToken))
218
- }
219
-
220
- stripeSdkModule?.eventEmitter?.emitOnConfirmationTokenHandlerCallback(params)
221
-
222
- val resultFromJavascript = paymentSheetConfirmationTokenCreationCallback.await()
223
- // reset the completable
224
- paymentSheetConfirmationTokenCreationCallback = CompletableDeferred<ReadableMap>()
225
-
226
- return@CreateIntentWithConfirmationTokenCallback resultFromJavascript.getString("clientSecret")?.let {
227
- CreateIntentResult.Success(clientSecret = it)
228
- }
229
- ?: run {
230
- val errorMap = resultFromJavascript.getMap("error")
231
- CreateIntentResult.Failure(
232
- cause = Exception(errorMap?.getString("message")),
233
- displayMessage = errorMap?.getString("localizedMessage"),
234
- )
235
- }
236
- }
237
-
238
- if (arguments.getBooleanOr("customFlow", false)) {
239
- if (flowController == null) {
240
- flowController =
241
- if (intentConfiguration != null) {
242
- val builder =
243
- PaymentSheet.FlowController
244
- .Builder(
245
- resultCallback = paymentResultCallback,
246
- paymentOptionResultCallback = paymentOptionCallback,
247
- )
248
- if (useConfirmationTokenCallback) {
249
- builder.createIntentCallback(createConfirmationTokenCallback)
250
- } else {
251
- builder.createIntentCallback(createIntentCallback)
252
- }
253
- builder
254
- .confirmCustomPaymentMethodCallback(this)
255
- .build(activity)
256
- } else {
257
- PaymentSheet.FlowController
258
- .Builder(
259
- resultCallback = paymentResultCallback,
260
- paymentOptionResultCallback = paymentOptionCallback,
261
- ).confirmCustomPaymentMethodCallback(this)
262
- .build(activity)
263
- }
264
- }
265
- } else {
266
- if (paymentSheet == null) {
267
- paymentSheet =
268
- if (intentConfiguration != null) {
269
- val builder = PaymentSheet.Builder(paymentResultCallback)
270
- if (useConfirmationTokenCallback) {
271
- builder.createIntentCallback(createConfirmationTokenCallback)
272
- } else {
273
- builder.createIntentCallback(createIntentCallback)
274
- }
275
- @SuppressLint("RestrictedApi")
276
- builder
277
- .confirmCustomPaymentMethodCallback(this)
278
- .build(activity, signal)
279
- } else {
280
- @SuppressLint("RestrictedApi")
281
- PaymentSheet
282
- .Builder(paymentResultCallback)
283
- .confirmCustomPaymentMethodCallback(this)
284
- .build(activity, signal)
285
- }
286
- }
287
- }
288
93
  configure(arguments, initPromise)
289
94
  }
290
95
 
291
96
  override fun onDestroy() {
97
+ super.onDestroy()
292
98
  flowController = null
293
99
  paymentSheet = null
294
100
  }
@@ -380,15 +186,211 @@ class PaymentSheetManager(
380
186
 
381
187
  paymentSheetConfiguration = configurationBuilder.build()
382
188
  if (args.getBooleanOr("customFlow", false)) {
189
+ lastConfigureWasCustomFlow = true
190
+ if (flowController == null) {
191
+ initFlowController(args, promise)
192
+ }
383
193
  configureFlowController(promise)
384
194
  } else {
195
+ lastConfigureWasCustomFlow = false
196
+ if (paymentSheet == null) {
197
+ initPaymentSheet(args, promise)
198
+ }
385
199
  promise.resolve(Arguments.createMap())
386
200
  }
387
201
  }
388
202
 
203
+ private fun initPaymentSheet(
204
+ args: ReadableMap,
205
+ promise: Promise,
206
+ ) {
207
+ val activity = getCurrentActivityOrResolveWithError(promise) ?: return
208
+ val intentConfigMap = args.getMap("intentConfiguration")
209
+ val useConfirmationTokenCallback = intentConfigMap?.hasKey("confirmationTokenConfirmHandler") == true
210
+ paymentSheet =
211
+ if (intentConfiguration != null) {
212
+ val builder = PaymentSheet.Builder(buildPaymentSheetResultCallback())
213
+ if (useConfirmationTokenCallback) {
214
+ builder.createIntentCallback(buildCreateConfirmationTokenCallback())
215
+ } else {
216
+ builder.createIntentCallback(buildIntentCreationCallback())
217
+ }
218
+ @SuppressLint("RestrictedApi")
219
+ builder
220
+ .confirmCustomPaymentMethodCallback(this)
221
+ .build(activity, signal)
222
+ } else {
223
+ @SuppressLint("RestrictedApi")
224
+ PaymentSheet
225
+ .Builder(buildPaymentSheetResultCallback())
226
+ .confirmCustomPaymentMethodCallback(this)
227
+ .build(activity, signal)
228
+ }
229
+ }
230
+
231
+ private fun initFlowController(
232
+ args: ReadableMap,
233
+ promise: Promise,
234
+ ) {
235
+ val activity = getCurrentActivityOrResolveWithError(promise) ?: return
236
+ val intentConfigMap = args.getMap("intentConfiguration")
237
+ val useConfirmationTokenCallback =
238
+ intentConfigMap?.hasKey("confirmationTokenConfirmHandler") == true
239
+ flowController =
240
+ if (intentConfiguration != null) {
241
+ val builder =
242
+ PaymentSheet.FlowController
243
+ .Builder(
244
+ resultCallback = buildPaymentSheetResultCallback(),
245
+ paymentOptionResultCallback = buildPaymentOptionCallback(),
246
+ )
247
+ if (useConfirmationTokenCallback) {
248
+ builder.createIntentCallback(buildCreateConfirmationTokenCallback())
249
+ } else {
250
+ builder.createIntentCallback(buildIntentCreationCallback())
251
+ }
252
+ builder.confirmCustomPaymentMethodCallback(this)
253
+ builder.build(activity)
254
+ } else {
255
+ PaymentSheet.FlowController
256
+ .Builder(
257
+ resultCallback = buildPaymentSheetResultCallback(),
258
+ paymentOptionResultCallback = buildPaymentOptionCallback(),
259
+ ).confirmCustomPaymentMethodCallback(this)
260
+ .build(activity)
261
+ }
262
+ }
263
+
264
+ private fun buildCreateConfirmationTokenCallback(): CreateIntentWithConfirmationTokenCallback {
265
+ return CreateIntentWithConfirmationTokenCallback { confirmationToken ->
266
+ val stripeSdkModule: StripeSdkModule? = context.getNativeModule(StripeSdkModule::class.java)
267
+ val params =
268
+ Arguments.createMap().apply {
269
+ putMap("confirmationToken", mapFromConfirmationToken(confirmationToken))
270
+ }
271
+
272
+ stripeSdkModule?.eventEmitter?.emitOnConfirmationTokenHandlerCallback(params)
273
+
274
+ val resultFromJavascript = paymentSheetConfirmationTokenCreationCallback.await()
275
+ // reset the completable
276
+ paymentSheetConfirmationTokenCreationCallback = CompletableDeferred<ReadableMap>()
277
+
278
+ return@CreateIntentWithConfirmationTokenCallback resultFromJavascript.getString("clientSecret")?.let {
279
+ CreateIntentResult.Success(clientSecret = it)
280
+ }
281
+ ?: run {
282
+ val errorMap = resultFromJavascript.getMap("error")
283
+ CreateIntentResult.Failure(
284
+ cause = Exception(errorMap?.getString("message")),
285
+ displayMessage = errorMap?.getString("localizedMessage"),
286
+ )
287
+ }
288
+ }
289
+ }
290
+
291
+ private fun buildIntentCreationCallback(): CreateIntentCallback {
292
+ return CreateIntentCallback { paymentMethod, shouldSavePaymentMethod ->
293
+ val stripeSdkModule: StripeSdkModule? = context.getNativeModule(StripeSdkModule::class.java)
294
+ val params =
295
+ Arguments.createMap().apply {
296
+ putMap("paymentMethod", mapFromPaymentMethod(paymentMethod))
297
+ putBoolean("shouldSavePaymentMethod", shouldSavePaymentMethod)
298
+ }
299
+
300
+ stripeSdkModule?.eventEmitter?.emitOnConfirmHandlerCallback(params)
301
+
302
+ val resultFromJavascript = paymentSheetIntentCreationCallback.await()
303
+ // reset the completable
304
+ paymentSheetIntentCreationCallback = CompletableDeferred<ReadableMap>()
305
+
306
+ return@CreateIntentCallback resultFromJavascript.getString("clientSecret")?.let {
307
+ CreateIntentResult.Success(clientSecret = it)
308
+ }
309
+ ?: run {
310
+ val errorMap = resultFromJavascript.getMap("error")
311
+ CreateIntentResult.Failure(
312
+ cause = Exception(errorMap?.getString("message")),
313
+ displayMessage = errorMap?.getString("localizedMessage"),
314
+ )
315
+ }
316
+ }
317
+ }
318
+
319
+ private fun buildPaymentSheetResultCallback(): PaymentSheetResultCallback =
320
+ PaymentSheetResultCallback { paymentResult ->
321
+ if (paymentSheetTimedOut) {
322
+ paymentSheetTimedOut = false
323
+ resolvePaymentResult(
324
+ createError(PaymentSheetErrorType.Timeout.toString(), "The payment has timed out"),
325
+ )
326
+ } else {
327
+ when (paymentResult) {
328
+ is PaymentSheetResult.Canceled -> {
329
+ resolvePaymentResult(
330
+ createError(
331
+ PaymentSheetErrorType.Canceled.toString(),
332
+ "The payment flow has been canceled",
333
+ ),
334
+ )
335
+ }
336
+
337
+ is PaymentSheetResult.Failed -> {
338
+ resolvePaymentResult(
339
+ createError(PaymentSheetErrorType.Failed.toString(), paymentResult.error),
340
+ )
341
+ }
342
+
343
+ is PaymentSheetResult.Completed -> {
344
+ resolvePaymentResult(Arguments.createMap())
345
+ }
346
+ }
347
+ }
348
+ }
349
+
350
+ private fun buildPaymentOptionCallback(): PaymentOptionResultCallback {
351
+ return PaymentOptionResultCallback { paymentOptionResult ->
352
+ paymentOptionResult.paymentOption?.let { paymentOption ->
353
+ // Convert drawable to bitmap asynchronously to avoid shared state issues
354
+ CoroutineScope(Dispatchers.Default).launch {
355
+ val imageString =
356
+ try {
357
+ convertDrawableToBase64(paymentOption.icon())
358
+ } catch (e: Exception) {
359
+ val result =
360
+ createError(
361
+ PaymentSheetErrorType.Failed.toString(),
362
+ "Failed to process payment option image: ${e.message}",
363
+ )
364
+ resolvePresentPromise(result)
365
+ return@launch
366
+ }
367
+
368
+ val option: WritableMap = Arguments.createMap()
369
+ option.putString("label", paymentOption.label)
370
+ option.putString("image", imageString)
371
+ val additionalFields: Map<String, Any> = mapOf("didCancel" to paymentOptionResult.didCancel)
372
+ val result = createResult("paymentOption", option, additionalFields)
373
+ resolvePresentPromise(result)
374
+ }
375
+ } ?: run {
376
+ val result =
377
+ if (paymentSheetTimedOut) {
378
+ paymentSheetTimedOut = false
379
+ createError(PaymentSheetErrorType.Timeout.toString(), "The payment has timed out")
380
+ } else {
381
+ createError(
382
+ PaymentSheetErrorType.Canceled.toString(),
383
+ "The payment option selection flow has been canceled",
384
+ )
385
+ }
386
+ resolvePresentPromise(result)
387
+ }
388
+ }
389
+ }
390
+
389
391
  override fun onPresent() {
390
392
  keepJsAwake = KeepJsAwakeTask(context).apply { start() }
391
- if (paymentSheet != null) {
393
+ if (lastConfigureWasCustomFlow == false) {
392
394
  if (!paymentIntentClientSecret.isNullOrEmpty()) {
393
395
  paymentSheet?.presentWithPaymentIntent(
394
396
  paymentIntentClientSecret!!,
@@ -402,7 +404,7 @@ class PaymentSheetManager(
402
404
  configuration = paymentSheetConfiguration,
403
405
  )
404
406
  }
405
- } else if (flowController != null) {
407
+ } else if (lastConfigureWasCustomFlow == true && flowController != null) {
406
408
  flowController?.presentPaymentOptions()
407
409
  } else {
408
410
  promise?.resolve(createMissingInitError())
@@ -258,7 +258,9 @@ class StripeSdkModule(
258
258
  promise: Promise,
259
259
  ) {
260
260
  if (paymentSheetManager != null) {
261
- paymentSheetManager?.configure(params, promise)
261
+ UiThreadUtil.runOnUiThread {
262
+ paymentSheetManager?.configure(params, promise)
263
+ }
262
264
  } else {
263
265
  paymentSheetManager =
264
266
  PaymentSheetManager(reactApplicationContext, params, promise).also {
@@ -2,6 +2,7 @@ package com.reactnativestripesdk.pushprovisioning
2
2
 
3
3
  import android.annotation.SuppressLint
4
4
  import android.content.res.ColorStateList
5
+ import android.graphics.Bitmap
5
6
  import android.graphics.drawable.Drawable
6
7
  import android.graphics.drawable.RippleDrawable
7
8
  import android.view.MotionEvent
@@ -12,10 +13,9 @@ import androidx.core.graphics.toColorInt
12
13
  import androidx.core.net.toUri
13
14
  import com.facebook.common.executors.UiThreadImmediateExecutorService
14
15
  import com.facebook.common.references.CloseableReference
15
- import com.facebook.datasource.BaseDataSubscriber
16
16
  import com.facebook.datasource.DataSource
17
17
  import com.facebook.drawee.backends.pipeline.Fresco
18
- import com.facebook.imagepipeline.image.CloseableBitmap
18
+ import com.facebook.imagepipeline.datasource.BaseBitmapReferenceDataSubscriber
19
19
  import com.facebook.imagepipeline.image.CloseableImage
20
20
  import com.facebook.imagepipeline.request.ImageRequestBuilder
21
21
  import com.facebook.react.bridge.ReadableMap
@@ -36,6 +36,7 @@ class AddToWalletButtonView(
36
36
 
37
37
  private var loadedSource: String? = null
38
38
  private var currentDataSource: DataSource<CloseableReference<CloseableImage>>? = null
39
+ private var currentBitmapReference: CloseableReference<Bitmap>? = null
39
40
 
40
41
  init {
41
42
  scaleType = ScaleType.CENTER_CROP
@@ -118,20 +119,14 @@ class AddToWalletButtonView(
118
119
  currentDataSource = dataSource
119
120
 
120
121
  dataSource.subscribe(
121
- object : BaseDataSubscriber<CloseableReference<CloseableImage>>() {
122
- override fun onNewResultImpl(dataSource: DataSource<CloseableReference<CloseableImage>>) {
123
- if (!dataSource.isFinished) return
124
- val imageRef = dataSource.result ?: return
125
-
126
- try {
127
- val image = imageRef.get()
128
- if (image is CloseableBitmap) {
129
- val drawable = image.underlyingBitmap.toDrawable(resources)
130
- setImageWithRipple(drawable)
131
- }
132
- } finally {
133
- CloseableReference.closeSafely(imageRef)
134
- }
122
+ object : BaseBitmapReferenceDataSubscriber() {
123
+ override fun onNewResultImpl(bitmapReference: CloseableReference<Bitmap>?) {
124
+ val image = bitmapReference?.get() ?: return
125
+
126
+ currentBitmapReference = bitmapReference.cloneOrNull()
127
+
128
+ val drawable = image.toDrawable(resources)
129
+ setImageWithRipple(drawable)
135
130
  }
136
131
 
137
132
  override fun onFailureImpl(dataSource: DataSource<CloseableReference<CloseableImage>>) {
@@ -165,6 +160,12 @@ class AddToWalletButtonView(
165
160
 
166
161
  private fun cancelCurrentRequest() {
167
162
  currentDataSource?.close()
163
+
164
+ currentBitmapReference?.let {
165
+ CloseableReference.closeSafely(it)
166
+ }
167
+
168
+ currentBitmapReference = null
168
169
  currentDataSource = null
169
170
  }
170
171
 
package/ios/Mappers.swift CHANGED
@@ -1178,6 +1178,8 @@ class Mappers {
1178
1178
  let lightPrimaryHex = lightColors?["primary"] as? String
1179
1179
  let darkSelectedBorderHex = darkColors?["borderSelected"] as? String
1180
1180
  let lightSelectedBorderHex = lightColors?["borderSelected"] as? String
1181
+ let darkContentOnPrimaryHex = darkColors?["contentOnPrimary"] as? String
1182
+ let lightContentOnPrimaryHex = lightColors?["contentOnPrimary"] as? String
1181
1183
 
1182
1184
  let darkPrimary = darkPrimaryHex.flatMap { UIColor(hexString: $0) }
1183
1185
  let lightPrimary = lightPrimaryHex.flatMap { UIColor(hexString: $0) }
@@ -1185,6 +1187,9 @@ class Mappers {
1185
1187
  let darkSelectedBorder = darkSelectedBorderHex.flatMap { UIColor(hexString: $0) }
1186
1188
  let lightSelectedBorder = lightSelectedBorderHex.flatMap { UIColor(hexString: $0) }
1187
1189
 
1190
+ let darkContentOnPrimary = darkContentOnPrimaryHex.flatMap { UIColor(hexString: $0) }
1191
+ let lightContentOnPrimary = lightContentOnPrimaryHex.flatMap { UIColor(hexString: $0) }
1192
+
1188
1193
  let primary: UIColor? = if let darkPrimary, let lightPrimary {
1189
1194
  UIColor { trait in
1190
1195
  trait.userInterfaceStyle == .dark ? darkPrimary : lightPrimary
@@ -1201,8 +1206,16 @@ class Mappers {
1201
1206
  darkSelectedBorder ?? lightSelectedBorder
1202
1207
  }
1203
1208
 
1204
- let colors: LinkAppearance.Colors? = if primary != nil || selectedBorder != nil {
1205
- .init(primary: primary, selectedBorder: selectedBorder)
1209
+ let contentOnPrimary: UIColor? = if let darkContentOnPrimary, let lightContentOnPrimary {
1210
+ UIColor { trait in
1211
+ trait.userInterfaceStyle == .dark ? darkContentOnPrimary : lightContentOnPrimary
1212
+ }
1213
+ } else {
1214
+ darkContentOnPrimary ?? lightContentOnPrimary
1215
+ }
1216
+
1217
+ let colors: LinkAppearance.Colors? = if primary != nil || selectedBorder != nil || contentOnPrimary != nil {
1218
+ .init(primary: primary, contentOnPrimary: contentOnPrimary, selectedBorder: selectedBorder)
1206
1219
  } else {
1207
1220
  nil
1208
1221
  }
@@ -1,2 +1,2 @@
1
- var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.AddToWalletButton=AddToWalletButton;var _objectWithoutProperties2=_interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));var _react=_interopRequireDefault(require("react"));var _NativeAddToWalletButton=_interopRequireDefault(require("../specs/NativeAddToWalletButton"));var _jsxRuntime=require("react/jsx-runtime");var _jsxFileName="/Users/davidestes/stripe/stripe-react-native/src/components/AddToWalletButton.tsx";var _excluded=["onComplete"];function AddToWalletButton(_ref){var onComplete=_ref.onComplete,props=(0,_objectWithoutProperties2.default)(_ref,_excluded);return(0,_jsxRuntime.jsx)(_NativeAddToWalletButton.default,Object.assign({},props,{onCompleteAction:function onCompleteAction(value){return onComplete(value.nativeEvent);}}));}
1
+ var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.AddToWalletButton=AddToWalletButton;var _objectWithoutProperties2=_interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));var _react=_interopRequireDefault(require("react"));var _NativeAddToWalletButton=_interopRequireDefault(require("../specs/NativeAddToWalletButton"));var _jsxRuntime=require("react/jsx-runtime");var _jsxFileName="/Users/samer/stripe/stripe-react-native/src/components/AddToWalletButton.tsx";var _excluded=["onComplete"];function AddToWalletButton(_ref){var onComplete=_ref.onComplete,props=(0,_objectWithoutProperties2.default)(_ref,_excluded);return(0,_jsxRuntime.jsx)(_NativeAddToWalletButton.default,Object.assign({},props,{onCompleteAction:function onCompleteAction(value){return onComplete(value.nativeEvent);}}));}
2
2
  //# sourceMappingURL=AddToWalletButton.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["_react","_interopRequireDefault","require","_NativeAddToWalletButton","_jsxRuntime","_jsxFileName","_excluded","AddToWalletButton","_ref","onComplete","props","_objectWithoutProperties2","default","jsx","Object","assign","onCompleteAction","value","nativeEvent"],"sourceRoot":"../../../src","sources":["components/AddToWalletButton.tsx"],"mappings":"wSAAA,IAAAA,MAAA,CAAAC,sBAAA,CAAAC,OAAA,WAcA,IAAAC,wBAAA,CAAAF,sBAAA,CAAAC,OAAA,sCAAuE,IAAAE,WAAA,CAAAF,OAAA,0BAAAG,YAAA,yFAAAC,SAAA,gBAgEhE,QAAS,CAAAC,iBAAiBA,CAAAC,IAAA,CAAkC,IAA/B,CAAAC,UAAU,CAAAD,IAAA,CAAVC,UAAU,CAAKC,KAAK,IAAAC,yBAAA,CAAAC,OAAA,EAAAJ,IAAA,CAAAF,SAAA,EACtD,MACE,GAAAF,WAAA,CAAAS,GAAA,EAACV,wBAAA,CAAAS,OAAuB,CAAAE,MAAA,CAAAC,MAAA,IAClBL,KAAK,EACTM,gBAAgB,CAAE,QAAlB,CAAAA,gBAAgBA,CACdC,KAEE,QACC,CAAAR,UAAU,CAACQ,KAAK,CAACC,WAAW,CAAC,EAAC,EACpC,CAAC,CAEN","ignoreList":[]}
1
+ {"version":3,"names":["_react","_interopRequireDefault","require","_NativeAddToWalletButton","_jsxRuntime","_jsxFileName","_excluded","AddToWalletButton","_ref","onComplete","props","_objectWithoutProperties2","default","jsx","Object","assign","onCompleteAction","value","nativeEvent"],"sourceRoot":"../../../src","sources":["components/AddToWalletButton.tsx"],"mappings":"wSAAA,IAAAA,MAAA,CAAAC,sBAAA,CAAAC,OAAA,WAcA,IAAAC,wBAAA,CAAAF,sBAAA,CAAAC,OAAA,sCAAuE,IAAAE,WAAA,CAAAF,OAAA,0BAAAG,YAAA,oFAAAC,SAAA,gBAgEhE,QAAS,CAAAC,iBAAiBA,CAAAC,IAAA,CAAkC,IAA/B,CAAAC,UAAU,CAAAD,IAAA,CAAVC,UAAU,CAAKC,KAAK,IAAAC,yBAAA,CAAAC,OAAA,EAAAJ,IAAA,CAAAF,SAAA,EACtD,MACE,GAAAF,WAAA,CAAAS,GAAA,EAACV,wBAAA,CAAAS,OAAuB,CAAAE,MAAA,CAAAC,MAAA,IAClBL,KAAK,EACTM,gBAAgB,CAAE,QAAlB,CAAAA,gBAAgBA,CACdC,KAEE,QACC,CAAAR,UAAU,CAACQ,KAAK,CAACC,WAAW,CAAC,EAAC,EACpC,CAAC,CAEN","ignoreList":[]}