From ccc554401b91774821cc518028fd19fa42df4266 Mon Sep 17 00:00:00 2001 From: Yuki Date: Wed, 5 Nov 2025 13:51:07 -0800 Subject: [PATCH 1/8] Update iOS SDK to 25.0.0 --- CHANGELOG.md | 5 +- example/ios/Podfile.lock | 112 +++++++++++++-------------- ios/Mappers.swift | 6 +- ios/PaymentMethodFactory.swift | 17 ---- ios/StripeSdkImpl+PaymentSheet.swift | 23 ++++-- stripe-react-native.podspec | 2 +- 6 files changed, 77 insertions(+), 88 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d00b2257c0..e2990f85bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,10 +3,11 @@ ## 0.56.0 - 2025-11-06 **Changes** -- CustomerSession is now generally available. The `customerSessionClientSecret` parameter is no longer experimental. -- ConfirmationTokens are now generally available. The `confirmationTokenConfirmHandler` parameter and `ConfirmationToken.Result` type are no longer experimental. +- [Added] CustomerSession is now generally available. The `customerSessionClientSecret` parameter is no longer experimental. +- [Added] ConfirmationTokens are now generally available. The `confirmationTokenConfirmHandler` parameter and `ConfirmationToken.Result` type are no longer experimental. - [Added] Added support for `CustomerSession` to CustomerSheet. The CustomerSession object grants the SDK temporary access to the Customer and provides additional configuration options. These configuration options allow you to customize the behavior of CustomerSheet. A complete list of features exposed on the CustomerSession are [in our API docs](https://docs.corp.stripe.com/api/customer_sessions/create#create_customer_session-components-customer_sheet). * [Added] Added support for `onBehalfOf` to CustomerSheet.IntentConfiguration. This parameter makes CustomerSheet use a connected account to determine the payment method that users see and whether CardBrandChoice is enabled. For more information, see the [SetupIntent docs](https://docs.stripe.com/api/setup_intents/object#setup_intent_object-on_behalf_of). +- [Removed] Removed Giropay. Use alternative payment methods instead. See this page for more information. **Fixes** - Fixed Android crash `IllegalStateException: State must be at least CREATED to move to DESTROYED` when removing payment methods in EmbeddedPaymentElement. The crash occurred when views were destroyed before completing the lifecycle initialization. diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 921b88e14f..fe3fa507fd 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1685,12 +1685,12 @@ PODS: - ReactCommon/turbomodule/core - Yoga - SocketRocket (0.7.1) - - Stripe (24.25.0): - - StripeApplePay (= 24.25.0) - - StripeCore (= 24.25.0) - - StripePayments (= 24.25.0) - - StripePaymentsUI (= 24.25.0) - - StripeUICore (= 24.25.0) + - Stripe (25.0.0): + - StripeApplePay (= 25.0.0) + - StripeCore (= 25.0.0) + - StripePayments (= 25.0.0) + - StripePaymentsUI (= 25.0.0) + - StripeUICore (= 25.0.0) - stripe-react-native (0.55.1): - DoubleConversion - glog @@ -1711,13 +1711,13 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - Stripe (~> 24.25.0) + - Stripe (~> 25.0.0) - stripe-react-native/NewArch (= 0.55.1) - - StripeApplePay (~> 24.25.0) - - StripeFinancialConnections (~> 24.25.0) - - StripePayments (~> 24.25.0) - - StripePaymentSheet (~> 24.25.0) - - StripePaymentsUI (~> 24.25.0) + - StripeApplePay (~> 25.0.0) + - StripeFinancialConnections (~> 25.0.0) + - StripePayments (~> 25.0.0) + - StripePaymentSheet (~> 25.0.0) + - StripePaymentsUI (~> 25.0.0) - Yoga - stripe-react-native/NewArch (0.55.1): - DoubleConversion @@ -1739,12 +1739,12 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - Stripe (~> 24.25.0) - - StripeApplePay (~> 24.25.0) - - StripeFinancialConnections (~> 24.25.0) - - StripePayments (~> 24.25.0) - - StripePaymentSheet (~> 24.25.0) - - StripePaymentsUI (~> 24.25.0) + - Stripe (~> 25.0.0) + - StripeApplePay (~> 25.0.0) + - StripeFinancialConnections (~> 25.0.0) + - StripePayments (~> 25.0.0) + - StripePaymentSheet (~> 25.0.0) + - StripePaymentsUI (~> 25.0.0) - Yoga - stripe-react-native/Tests (0.55.1): - DoubleConversion @@ -1766,35 +1766,35 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - Stripe (~> 24.25.0) - - StripeApplePay (~> 24.25.0) - - StripeFinancialConnections (~> 24.25.0) - - StripePayments (~> 24.25.0) - - StripePaymentSheet (~> 24.25.0) - - StripePaymentsUI (~> 24.25.0) + - Stripe (~> 25.0.0) + - StripeApplePay (~> 25.0.0) + - StripeFinancialConnections (~> 25.0.0) + - StripePayments (~> 25.0.0) + - StripePaymentSheet (~> 25.0.0) + - StripePaymentsUI (~> 25.0.0) - Yoga - - StripeApplePay (24.25.0): - - StripeCore (= 24.25.0) - - StripeCore (24.25.0) - - StripeFinancialConnections (24.25.0): - - StripeCore (= 24.25.0) - - StripeUICore (= 24.25.0) - - StripePayments (24.25.0): - - StripeCore (= 24.25.0) - - StripePayments/Stripe3DS2 (= 24.25.0) - - StripePayments/Stripe3DS2 (24.25.0): - - StripeCore (= 24.25.0) - - StripePaymentSheet (24.25.0): - - StripeApplePay (= 24.25.0) - - StripeCore (= 24.25.0) - - StripePayments (= 24.25.0) - - StripePaymentsUI (= 24.25.0) - - StripePaymentsUI (24.25.0): - - StripeCore (= 24.25.0) - - StripePayments (= 24.25.0) - - StripeUICore (= 24.25.0) - - StripeUICore (24.25.0): - - StripeCore (= 24.25.0) + - StripeApplePay (25.0.0): + - StripeCore (= 25.0.0) + - StripeCore (25.0.0) + - StripeFinancialConnections (25.0.0): + - StripeCore (= 25.0.0) + - StripeUICore (= 25.0.0) + - StripePayments (25.0.0): + - StripeCore (= 25.0.0) + - StripePayments/Stripe3DS2 (= 25.0.0) + - StripePayments/Stripe3DS2 (25.0.0): + - StripeCore (= 25.0.0) + - StripePaymentSheet (25.0.0): + - StripeApplePay (= 25.0.0) + - StripeCore (= 25.0.0) + - StripePayments (= 25.0.0) + - StripePaymentsUI (= 25.0.0) + - StripePaymentsUI (25.0.0): + - StripeCore (= 25.0.0) + - StripePayments (= 25.0.0) + - StripeUICore (= 25.0.0) + - StripeUICore (25.0.0): + - StripeCore (= 25.0.0) - Yoga (0.0.0) DEPENDENCIES: @@ -2109,16 +2109,16 @@ SPEC CHECKSUMS: RNCPicker: cfb51a08c6e10357d9a65832e791825b0747b483 RNScreens: 0d4cb9afe052607ad0aa71f645a88bb7c7f2e64c SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 - Stripe: fe028a764ff6cc0b4884ffd1e3adfda8263d331b - stripe-react-native: b086f8960568c57183c8c3cddaa8d0a85d7c86b0 - StripeApplePay: b2477e350368474b33f2d6325f7de53794d2f859 - StripeCore: b3f991ef10e45ab2fa841e0a732825d795b2379e - StripeFinancialConnections: 92079b12dfe6453ab296ecc9e4cdf2b069015345 - StripePayments: 57e26426162008338436b9df0f4a96a125fa4f9e - StripePaymentSheet: 048eff784e164a79c2e5f3e13e5b1dbe2130a812 - StripePaymentsUI: c15edfc7d7a8ac6d8547af5a990517aa9ccfdbb0 - StripeUICore: 55ebd4a7a2c12600645526bfdd6e5bd8ea1c5335 - Yoga: 9b7fb56e7b08cde60e2153344fa6afbd88e5d99f + Stripe: 319b0923b2d03e7f07805db481b6656b19e159db + stripe-react-native: 3b354280a2aa9e93f1c3b8049775537c01bff978 + StripeApplePay: 09bbe6a24d2cd4c37b2422fdd6e18f2be9f37e02 + StripeCore: a671e360dc0ede1275e98a8c5b6e0b694509c611 + StripeFinancialConnections: ca68c5d0fb5fbfc53c9eee572997080c3b7e6b7f + StripePayments: f1fbddb747c62dca90810e69fecfaca45f31b667 + StripePaymentSheet: 645a5787595c667c5ea6de8c47a809003e837a99 + StripePaymentsUI: 719d201ab61087c974ed44cbd0d43c30d9276688 + StripeUICore: a8f8f38daf0eddb8f6c43ac9d7f051290af9bf2a + Yoga: afd04ff05ebe0121a00c468a8a3c8080221cb14c PODFILE CHECKSUM: a2ed964678852d4cc306ff4add3e4fa90be77ea6 diff --git a/ios/Mappers.swift b/ios/Mappers.swift index 26ded9c5d7..e367afd50e 100644 --- a/ios/Mappers.swift +++ b/ios/Mappers.swift @@ -286,7 +286,6 @@ class Mappers { case STPPaymentMethodType.SEPADebit: return "SepaDebit" case STPPaymentMethodType.AUBECSDebit: return "AuBecsDebit" case STPPaymentMethodType.bacsDebit: return "BacsDebit" - case STPPaymentMethodType.giropay: return "Giropay" case STPPaymentMethodType.przelewy24: return "P24" case STPPaymentMethodType.EPS: return "Eps" case STPPaymentMethodType.bancontact: return "Bancontact" @@ -319,7 +318,6 @@ class Mappers { case "SepaDebit": return STPPaymentMethodType.SEPADebit case "AuBecsDebit": return STPPaymentMethodType.AUBECSDebit case "BacsDebit": return STPPaymentMethodType.bacsDebit - case "Giropay": return STPPaymentMethodType.giropay case "P24": return STPPaymentMethodType.przelewy24 case "Eps": return STPPaymentMethodType.EPS case "Bancontact": return STPPaymentMethodType.bancontact @@ -666,7 +664,7 @@ class Mappers { "accountType": mapFromUSBankAccountType(type: paymentMethod.usBankAccount?.accountType), "last4": paymentMethod.usBankAccount?.last4 ?? NSNull(), "bankName": paymentMethod.usBankAccount?.bankName ?? NSNull(), - "linkedAccount": paymentMethod.usBankAccount?.linkedAccount ?? NSNull(), + "linkedAccount": paymentMethod.usBankAccount?.financialConnectionsAccount ?? NSNull(), "fingerprint": paymentMethod.usBankAccount?.fingerprint ?? NSNull(), "preferredNetworks": paymentMethod.usBankAccount?.networks?.preferred ?? NSNull(), "supportedNetworks": paymentMethod.usBankAccount?.networks?.supported ?? NSNull(), @@ -839,7 +837,7 @@ class Mappers { let types = setupIntent.paymentMethodTypes.map { - mapPaymentMethodType(type: STPPaymentMethodType.init(rawValue: Int(truncating: $0))!) + mapPaymentMethodType(type: $0) } intent.setValue(types, forKey: "paymentMethodTypes") diff --git a/ios/PaymentMethodFactory.swift b/ios/PaymentMethodFactory.swift index 2e67abf848..3f4e86109e 100644 --- a/ios/PaymentMethodFactory.swift +++ b/ios/PaymentMethodFactory.swift @@ -39,8 +39,6 @@ class PaymentMethodFactory { return try createBilliePaymentMethodParams() case STPPaymentMethodType.SEPADebit: return try createSepaPaymentMethodParams() - case STPPaymentMethodType.giropay: - return try createGiropayPaymentMethodParams() case STPPaymentMethodType.EPS: return try createEPSPaymentMethodParams() case STPPaymentMethodType.grabPay: @@ -96,8 +94,6 @@ class PaymentMethodFactory { return nil case STPPaymentMethodType.OXXO: return nil - case STPPaymentMethodType.giropay: - return nil case STPPaymentMethodType.grabPay: return nil case STPPaymentMethodType.przelewy24: @@ -303,16 +299,6 @@ class PaymentMethodFactory { return STPPaymentMethodParams(oxxo: params, billingDetails: billingDetails, metadata: metadata) } - private func createGiropayPaymentMethodParams() throws -> STPPaymentMethodParams { - let params = STPPaymentMethodGiropayParams() - - guard let billingDetails = billingDetailsParams else { - throw PaymentMethodError.giropayPaymentMissingParams - } - - return STPPaymentMethodParams(giropay: params, billingDetails: billingDetails, metadata: metadata) - } - private func createEPSPaymentMethodParams() throws -> STPPaymentMethodParams { let params = STPPaymentMethodEPSParams() @@ -419,7 +405,6 @@ enum PaymentMethodError: Error { case bancontactPaymentMissingParams case billiePaymentMissingParams case sepaPaymentMissingParams - case giropayPaymentMissingParams case p24PaymentMissingParams case afterpayClearpayPaymentMissingParams // Klarna no longer requires email and country in billing details @@ -434,8 +419,6 @@ extension PaymentMethodError: LocalizedError { switch self { case .cardPaymentMissingParams: return NSLocalizedString("Card details not complete", comment: "Create payment error") - case .giropayPaymentMissingParams: - return NSLocalizedString("You must provide billing details", comment: "Create payment error") case .idealPaymentMissingParams: return NSLocalizedString("You must provide bank name", comment: "Create payment error") case .p24PaymentMissingParams: diff --git a/ios/StripeSdkImpl+PaymentSheet.swift b/ios/StripeSdkImpl+PaymentSheet.swift index 200c2f2dcd..c38ce91400 100644 --- a/ios/StripeSdkImpl+PaymentSheet.swift +++ b/ios/StripeSdkImpl+PaymentSheet.swift @@ -396,6 +396,20 @@ extension StripeSdkImpl { if (applePayParams["request"] == nil) { return nil } + let authorizationResultHandler: PaymentSheet.ApplePayConfiguration.Handlers.AuthorizationResultHandler? = { + guard applePayParams.object(forKey: "setOrderTracking") != nil else { + return nil + } + return { result in + await withCheckedContinuation { continuation in + // Set the handler first: this will be called from JS land after we `emitOnOrderTrackingCallback()`. + self.orderTrackingHandler = (result, { result in + continuation.resume(returning: result) + }) + self.emitter?.emitOnOrderTrackingCallback() + } + } + }() return PaymentSheet.ApplePayConfiguration.Handlers(paymentRequestHandler: { request in do { try request.configureRequestType(requestParams: applePayParams) @@ -404,14 +418,7 @@ extension StripeSdkImpl { RCTMakeAndLogError(error.localizedDescription, nil, nil) } return request - }, authorizationResultHandler: { result, completion in - if applePayParams.object(forKey: "setOrderTracking") != nil { - self.orderTrackingHandler = (result, completion) - self.emitter?.emitOnOrderTrackingCallback() - } else { - completion(result) - } - }) + }, authorizationResultHandler: authorizationResultHandler) } internal static func mapToCollectionMode(str: String?) -> PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode { diff --git a/stripe-react-native.podspec b/stripe-react-native.podspec index 1b0867e450..707d7f456f 100644 --- a/stripe-react-native.podspec +++ b/stripe-react-native.podspec @@ -2,7 +2,7 @@ require 'json' package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) # Keep stripe_version in sync with https://github.com/stripe/stripe-identity-react-native/blob/main/stripe-identity-react-native.podspec -stripe_version = '~> 24.25.0' +stripe_version = '~> 25.0.0' fabric_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == '1' From 66b9176ccf760d8d281dbe29b55bc08e065351e3 Mon Sep 17 00:00:00 2001 From: Yuki Date: Thu, 6 Nov 2025 19:36:00 -0800 Subject: [PATCH 2/8] [TEMP] TODO DELETE THIS - make example prefer maven local --- example/android/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/example/android/build.gradle b/example/android/build.gradle index 41aff0712a..312df5c7b4 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -24,6 +24,7 @@ buildscript { allprojects { repositories { + mavenLocal() maven { // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm url({ From ec4cb067c20fdd59f241a5af627ee8f7607652f0 Mon Sep 17 00:00:00 2001 From: Yuki Date: Thu, 6 Nov 2025 16:27:26 -0800 Subject: [PATCH 3/8] Update Android --- android/gradle.properties | 2 +- .../PaymentSheetAppearanceTest.kt | 607 +++++++++++++++ .../addresssheet/AddressSheetViewTest.kt | 22 +- .../com/reactnativestripesdk/CardFieldView.kt | 6 +- .../com/reactnativestripesdk/CardFormView.kt | 14 +- .../PaymentMethodCreateParamsFactory.kt | 11 - .../PaymentSheetAppearance.kt | 695 ++++++++---------- .../PaymentSheetManager.kt | 2 - .../reactnativestripesdk/StripeSdkModule.kt | 3 - .../customersheet/CustomerSheetManager.kt | 3 +- .../ReactNativeCustomerSessionProvider.kt | 2 - .../reactnativestripesdk/utils/Extensions.kt | 3 + .../com/reactnativestripesdk/utils/Mappers.kt | 2 - 13 files changed, 947 insertions(+), 425 deletions(-) create mode 100644 android/src/androidTest/java/com/reactnativestripesdk/PaymentSheetAppearanceTest.kt diff --git a/android/gradle.properties b/android/gradle.properties index 2165398abb..ec72adad2c 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -3,4 +3,4 @@ StripeSdk_compileSdkVersion=30 StripeSdk_targetSdkVersion=28 StripeSdk_minSdkVersion=21 # Keep StripeSdk_stripeVersion in sync with https://github.com/stripe/stripe-identity-react-native/blob/main/android/gradle.properties -StripeSdk_stripeVersion=21.29.+ +StripeSdk_stripeVersion=22.0.+ diff --git a/android/src/androidTest/java/com/reactnativestripesdk/PaymentSheetAppearanceTest.kt b/android/src/androidTest/java/com/reactnativestripesdk/PaymentSheetAppearanceTest.kt new file mode 100644 index 0000000000..b84f8d96fa --- /dev/null +++ b/android/src/androidTest/java/com/reactnativestripesdk/PaymentSheetAppearanceTest.kt @@ -0,0 +1,607 @@ +package com.reactnativestripesdk + +import android.graphics.Color +import androidx.test.core.app.ApplicationProvider +import com.facebook.react.bridge.BridgeReactContext +import com.facebook.react.bridge.JavaOnlyMap +import com.facebook.react.bridge.ReadableMap +import com.facebook.react.soloader.OpenSourceMergedSoMapping +import com.facebook.soloader.SoLoader +import com.stripe.android.paymentsheet.PaymentSheet +import org.json.JSONObject +import org.junit.Assert.assertEquals +import org.junit.Before +import org.junit.Test + +class PaymentSheetAppearanceTest { + private val context = + BridgeReactContext( + ApplicationProvider.getApplicationContext(), + ) + + @Before + fun setup() { + SoLoader.init(context, OpenSourceMergedSoMapping) + } + + @Test + fun testFullAppearanceConfiguration() { + val json = """ + { + "colors": { + "primary": "#123456", + "background": "#123456", + "componentBackground": "#123456", + "componentBorder": "#123456", + "componentDivider": "#123456", + "componentText": "#123456", + "primaryText": "#123456", + "secondaryText": "#123456", + "placeholderText": "#123456", + "icon": "#123456", + "error": "#123456" + }, + "shapes": { + "borderRadius": 42.0, + "borderWidth": 42.0 + }, + "font": { + "scale": 42.0 + }, + "primaryButton": { + "colors": { + "background": "#123456", + "text": "#123456", + "border": "#123456", + "successBackgroundColor": "#123456", + "successTextColor": "#123456" + }, + "shapes": { + "borderRadius": 42.0, + "borderWidth": 42.0, + "height": 42.0 + } + }, + "formInsetValues": { + "left": 42.0, + "top": 42.0, + "right": 42.0, + "bottom": 42.0 + } + } + """.trimIndent() + + val map = jsonToMap(json) + val appearanceFromJson = buildPaymentSheetAppearance(map, context) + + // Build expected appearance manually + val testColor = Color.parseColor("#123456") + + val colorsBuilder = PaymentSheet.Colors.Builder() + colorsBuilder.primary(testColor) + colorsBuilder.surface(testColor) + colorsBuilder.component(testColor) + colorsBuilder.componentBorder(testColor) + colorsBuilder.componentDivider(testColor) + colorsBuilder.onComponent(testColor) + colorsBuilder.onSurface(testColor) + colorsBuilder.subtitle(testColor) + colorsBuilder.placeholderText(testColor) + colorsBuilder.appBarIcon(testColor) + colorsBuilder.error(testColor) + + val shapesBuilder = PaymentSheet.Shapes.Builder() + shapesBuilder.cornerRadiusDp(42.0f) + shapesBuilder.borderStrokeWidthDp(42.0f) + + val typographyBuilder = PaymentSheet.Typography.Builder() + typographyBuilder.sizeScaleFactor(42.0f) + + val primaryButtonColorsBuilder = PaymentSheet.PrimaryButtonColors.Builder() + primaryButtonColorsBuilder.background(testColor) + primaryButtonColorsBuilder.onBackground(testColor) + primaryButtonColorsBuilder.border(testColor) + primaryButtonColorsBuilder.successBackgroundColor(testColor) + primaryButtonColorsBuilder.onSuccessBackgroundColor(testColor) + + val primaryButton = PaymentSheet.PrimaryButton( + colorsLight = primaryButtonColorsBuilder.buildLight(), + colorsDark = primaryButtonColorsBuilder.buildDark(), + shape = PaymentSheet.PrimaryButtonShape( + cornerRadiusDp = 42.0f, + borderStrokeWidthDp = 42.0f, + heightDp = 42.0f + ), + typography = PaymentSheet.PrimaryButtonTypography() + ) + + val appearanceBuilder = PaymentSheet.Appearance.Builder() + appearanceBuilder.typography(typographyBuilder.build()) + appearanceBuilder.colorsLight(colorsBuilder.buildLight()) + appearanceBuilder.colorsDark(colorsBuilder.buildDark()) + appearanceBuilder.shapes(shapesBuilder.build()) + appearanceBuilder.primaryButton(primaryButton) + appearanceBuilder.formInsetValues( + PaymentSheet.Insets( + startDp = 42.0f, + topDp = 42.0f, + endDp = 42.0f, + bottomDp = 42.0f + ) + ) + + val expectedAppearance = appearanceBuilder.build() + + assertEquals(expectedAppearance, appearanceFromJson) + } + + @Test + fun testPartialAppearanceConfiguration() { + val json = """ + { + "colors": { + "primary": "#123456", + "componentBackground": "#123456", + "componentDivider": "#123456", + "primaryText": "#123456", + "placeholderText": "#123456", + "error": "#123456" + }, + "shapes": { + "borderRadius": 42.0 + }, + "primaryButton": { + "colors": { + "background": "#123456", + "border": "#123456" + }, + "shapes": { + "borderRadius": 42.0, + "height": 42.0 + } + } + } + """.trimIndent() + + val map = jsonToMap(json) + val appearanceFromJson = buildPaymentSheetAppearance(map, context) + + // Build expected appearance manually (only setting the properties that are in JSON) + val testColor = Color.parseColor("#123456") + + val colorsBuilder = PaymentSheet.Colors.Builder() + colorsBuilder.primary(testColor) + colorsBuilder.component(testColor) + colorsBuilder.componentDivider(testColor) + colorsBuilder.onSurface(testColor) + colorsBuilder.placeholderText(testColor) + colorsBuilder.error(testColor) + + val shapesBuilder = PaymentSheet.Shapes.Builder() + shapesBuilder.cornerRadiusDp(42.0f) + + val primaryButtonColorsBuilder = PaymentSheet.PrimaryButtonColors.Builder() + primaryButtonColorsBuilder.background(testColor) + primaryButtonColorsBuilder.border(testColor) + + val primaryButton = PaymentSheet.PrimaryButton( + colorsLight = primaryButtonColorsBuilder.buildLight(), + colorsDark = primaryButtonColorsBuilder.buildDark(), + shape = PaymentSheet.PrimaryButtonShape( + cornerRadiusDp = 42.0f, + borderStrokeWidthDp = null, + heightDp = 42.0f + ), + typography = PaymentSheet.PrimaryButtonTypography() + ) + + val appearanceBuilder = PaymentSheet.Appearance.Builder() + appearanceBuilder.typography(PaymentSheet.Typography.Builder().build()) + appearanceBuilder.colorsLight(colorsBuilder.buildLight()) + appearanceBuilder.colorsDark(colorsBuilder.buildDark()) + appearanceBuilder.shapes(shapesBuilder.build()) + appearanceBuilder.primaryButton(primaryButton) + + val expectedAppearance = appearanceBuilder.build() + + assertEquals(expectedAppearance, appearanceFromJson) + } + + @Test + fun testFullEmbeddedAppearance_FlatWithRadio() { + val json = """ + { + "embeddedPaymentElement": { + "row": { + "style": "flatWithRadio", + "additionalInsets": 42.0, + "flat": { + "separatorThickness": 42.0, + "topSeparatorEnabled": true, + "bottomSeparatorEnabled": true, + "separatorColor": "#123456", + "separatorInsets": { + "left": 42.0, + "right": 42.0 + }, + "radio": { + "selectedColor": "#123456", + "unselectedColor": "#123456" + } + } + } + } + } + """.trimIndent() + + val map = jsonToMap(json) + val appearanceFromJson = buildPaymentSheetAppearance(map, context) + + val testColor = Color.parseColor("#123456") + + val flatRadioColorsBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithRadio.Colors.Builder() + flatRadioColorsBuilder.separatorColor(testColor) + flatRadioColorsBuilder.selectedColor(testColor) + flatRadioColorsBuilder.unselectedColor(testColor) + + val flatRadioBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithRadio.Builder() + flatRadioBuilder.separatorThicknessDp(42.0f) + flatRadioBuilder.startSeparatorInsetDp(42.0f) + flatRadioBuilder.endSeparatorInsetDp(42.0f) + flatRadioBuilder.topSeparatorEnabled(true) + flatRadioBuilder.bottomSeparatorEnabled(true) + flatRadioBuilder.additionalVerticalInsetsDp(42.0f) + flatRadioBuilder.colorsLight(flatRadioColorsBuilder.buildLight()) + flatRadioBuilder.colorsDark(flatRadioColorsBuilder.buildDark()) + + val embeddedBuilder = PaymentSheet.Appearance.Embedded.Builder() + embeddedBuilder.rowStyle(flatRadioBuilder.build()) + + val appearanceBuilder = PaymentSheet.Appearance.Builder() + appearanceBuilder.embeddedAppearance(embeddedBuilder.build()) + + val expectedAppearance = appearanceBuilder.build() + + assertEquals(expectedAppearance, appearanceFromJson) + } + + @Test + fun testPartialEmbeddedAppearance_FlatWithRadio() { + val json = """ + { + "embeddedPaymentElement": { + "row": { + "style": "flatWithRadio", + "flat": { + "separatorThickness": 42.0, + "topSeparatorEnabled": false, + "separatorColor": "#123456", + "radio": { + "selectedColor": "#123456" + } + } + } + } + } + """.trimIndent() + + val map = jsonToMap(json) + val appearanceFromJson = buildPaymentSheetAppearance(map, context) + + val testColor = Color.parseColor("#123456") + + val flatRadioColorsBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithRadio.Colors.Builder() + flatRadioColorsBuilder.separatorColor(testColor) + flatRadioColorsBuilder.selectedColor(testColor) + + val flatRadioBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithRadio.Builder() + flatRadioBuilder.separatorThicknessDp(42.0f) + flatRadioBuilder.topSeparatorEnabled(false) + flatRadioBuilder.colorsLight(flatRadioColorsBuilder.buildLight()) + flatRadioBuilder.colorsDark(flatRadioColorsBuilder.buildDark()) + + val embeddedBuilder = PaymentSheet.Appearance.Embedded.Builder() + embeddedBuilder.rowStyle(flatRadioBuilder.build()) + + val appearanceBuilder = PaymentSheet.Appearance.Builder() + appearanceBuilder.embeddedAppearance(embeddedBuilder.build()) + + val expectedAppearance = appearanceBuilder.build() + + assertEquals(expectedAppearance, appearanceFromJson) + } + + @Test + fun testFullEmbeddedAppearance_FlatWithCheckmark() { + val json = """ + { + "embeddedPaymentElement": { + "row": { + "style": "flatWithCheckmark", + "additionalInsets": 42.0, + "flat": { + "separatorThickness": 42.0, + "topSeparatorEnabled": true, + "bottomSeparatorEnabled": true, + "separatorColor": "#123456", + "separatorInsets": { + "left": 42.0, + "right": 42.0 + }, + "checkmark": { + "color": "#123456", + "inset": 42.0 + } + } + } + } + } + """.trimIndent() + + val map = jsonToMap(json) + val appearanceFromJson = buildPaymentSheetAppearance(map, context) + + val testColor = Color.parseColor("#123456") + + val flatCheckmarkColorsBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark.Colors.Builder() + flatCheckmarkColorsBuilder.separatorColor(testColor) + flatCheckmarkColorsBuilder.checkmarkColor(testColor) + + val flatCheckmarkBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark.Builder() + flatCheckmarkBuilder.separatorThicknessDp(42.0f) + flatCheckmarkBuilder.startSeparatorInsetDp(42.0f) + flatCheckmarkBuilder.endSeparatorInsetDp(42.0f) + flatCheckmarkBuilder.topSeparatorEnabled(true) + flatCheckmarkBuilder.bottomSeparatorEnabled(true) + flatCheckmarkBuilder.checkmarkInsetDp(42.0f) + flatCheckmarkBuilder.additionalVerticalInsetsDp(42.0f) + flatCheckmarkBuilder.colorsLight(flatCheckmarkColorsBuilder.buildLight()) + flatCheckmarkBuilder.colorsDark(flatCheckmarkColorsBuilder.buildDark()) + + val embeddedBuilder = PaymentSheet.Appearance.Embedded.Builder() + embeddedBuilder.rowStyle(flatCheckmarkBuilder.build()) + + val appearanceBuilder = PaymentSheet.Appearance.Builder() + appearanceBuilder.embeddedAppearance(embeddedBuilder.build()) + + val expectedAppearance = appearanceBuilder.build() + + assertEquals(expectedAppearance, appearanceFromJson) + } + + @Test + fun testPartialEmbeddedAppearance_FlatWithCheckmark() { + val json = """ + { + "embeddedPaymentElement": { + "row": { + "style": "flatWithCheckmark", + "flat": { + "separatorThickness": 42.0, + "bottomSeparatorEnabled": false, + "separatorColor": "#123456", + "checkmark": { + "color": "#123456" + } + } + } + } + } + """.trimIndent() + + val map = jsonToMap(json) + val appearanceFromJson = buildPaymentSheetAppearance(map, context) + + val testColor = Color.parseColor("#123456") + + val flatCheckmarkColorsBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark.Colors.Builder() + flatCheckmarkColorsBuilder.separatorColor(testColor) + flatCheckmarkColorsBuilder.checkmarkColor(testColor) + + val flatCheckmarkBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark.Builder() + flatCheckmarkBuilder.separatorThicknessDp(42.0f) + flatCheckmarkBuilder.bottomSeparatorEnabled(false) + flatCheckmarkBuilder.colorsLight(flatCheckmarkColorsBuilder.buildLight()) + flatCheckmarkBuilder.colorsDark(flatCheckmarkColorsBuilder.buildDark()) + + val embeddedBuilder = PaymentSheet.Appearance.Embedded.Builder() + embeddedBuilder.rowStyle(flatCheckmarkBuilder.build()) + + val appearanceBuilder = PaymentSheet.Appearance.Builder() + appearanceBuilder.embeddedAppearance(embeddedBuilder.build()) + + val expectedAppearance = appearanceBuilder.build() + + assertEquals(expectedAppearance, appearanceFromJson) + } + + @Test + fun testFullEmbeddedAppearance_FlatWithDisclosure() { + val json = """ + { + "embeddedPaymentElement": { + "row": { + "style": "flatWithDisclosure", + "additionalInsets": 42.0, + "flat": { + "separatorThickness": 42.0, + "topSeparatorEnabled": true, + "bottomSeparatorEnabled": true, + "separatorColor": "#123456", + "separatorInsets": { + "left": 42.0, + "right": 42.0 + }, + "disclosure": { + "color": "#123456" + } + } + } + } + } + """.trimIndent() + + val map = jsonToMap(json) + val appearanceFromJson = buildPaymentSheetAppearance(map, context) + + val testColor = Color.parseColor("#123456") + + val flatDisclosureColorsBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithDisclosure.Colors.Builder() + flatDisclosureColorsBuilder.separatorColor(testColor) + flatDisclosureColorsBuilder.disclosureColor(testColor) + + val flatDisclosureBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithDisclosure.Builder() + flatDisclosureBuilder.separatorThicknessDp(42.0f) + flatDisclosureBuilder.startSeparatorInsetDp(42.0f) + flatDisclosureBuilder.endSeparatorInsetDp(42.0f) + flatDisclosureBuilder.topSeparatorEnabled(true) + flatDisclosureBuilder.bottomSeparatorEnabled(true) + flatDisclosureBuilder.additionalVerticalInsetsDp(42.0f) + flatDisclosureBuilder.colorsLight(flatDisclosureColorsBuilder.buildLight()) + flatDisclosureBuilder.colorsDark(flatDisclosureColorsBuilder.buildDark()) + + val embeddedBuilder = PaymentSheet.Appearance.Embedded.Builder() + embeddedBuilder.rowStyle(flatDisclosureBuilder.build()) + + val appearanceBuilder = PaymentSheet.Appearance.Builder() + appearanceBuilder.embeddedAppearance(embeddedBuilder.build()) + + val expectedAppearance = appearanceBuilder.build() + + assertEquals(expectedAppearance, appearanceFromJson) + } + + @Test + fun testPartialEmbeddedAppearance_FlatWithDisclosure() { + val json = """ + { + "embeddedPaymentElement": { + "row": { + "style": "flatWithDisclosure", + "flat": { + "separatorThickness": 42.0, + "separatorColor": "#123456", + "disclosure": { + "color": "#123456" + } + } + } + } + } + """.trimIndent() + + val map = jsonToMap(json) + val appearanceFromJson = buildPaymentSheetAppearance(map, context) + + val testColor = Color.parseColor("#123456") + + val flatDisclosureColorsBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithDisclosure.Colors.Builder() + flatDisclosureColorsBuilder.separatorColor(testColor) + flatDisclosureColorsBuilder.disclosureColor(testColor) + + val flatDisclosureBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithDisclosure.Builder() + flatDisclosureBuilder.separatorThicknessDp(42.0f) + flatDisclosureBuilder.colorsLight(flatDisclosureColorsBuilder.buildLight()) + flatDisclosureBuilder.colorsDark(flatDisclosureColorsBuilder.buildDark()) + + val embeddedBuilder = PaymentSheet.Appearance.Embedded.Builder() + embeddedBuilder.rowStyle(flatDisclosureBuilder.build()) + + val appearanceBuilder = PaymentSheet.Appearance.Builder() + appearanceBuilder.embeddedAppearance(embeddedBuilder.build()) + + val expectedAppearance = appearanceBuilder.build() + + assertEquals(expectedAppearance, appearanceFromJson) + } + + @Test + fun testFullEmbeddedAppearance_FloatingButton() { + val json = """ + { + "embeddedPaymentElement": { + "row": { + "style": "floatingButton", + "additionalInsets": 42.0, + "floating": { + "spacing": 42.0 + } + } + } + } + """.trimIndent() + + val map = jsonToMap(json) + val appearanceFromJson = buildPaymentSheetAppearance(map, context) + + val floatingButtonBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FloatingButton.Builder() + floatingButtonBuilder.additionalInsetsDp(42.0f) + floatingButtonBuilder.spacingDp(42.0f) + + val embeddedBuilder = PaymentSheet.Appearance.Embedded.Builder() + embeddedBuilder.rowStyle(floatingButtonBuilder.build()) + + val appearanceBuilder = PaymentSheet.Appearance.Builder() + appearanceBuilder.embeddedAppearance(embeddedBuilder.build()) + + val expectedAppearance = appearanceBuilder.build() + + assertEquals(expectedAppearance, appearanceFromJson) + } + + @Test + fun testPartialEmbeddedAppearance_FloatingButton() { + val json = """ + { + "embeddedPaymentElement": { + "row": { + "style": "floatingButton", + "floating": { + "spacing": 42.0 + } + } + } + } + """.trimIndent() + + val map = jsonToMap(json) + val appearanceFromJson = buildPaymentSheetAppearance(map, context) + + val floatingButtonBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FloatingButton.Builder() + floatingButtonBuilder.spacingDp(42.0f) + + val embeddedBuilder = PaymentSheet.Appearance.Embedded.Builder() + embeddedBuilder.rowStyle(floatingButtonBuilder.build()) + + val appearanceBuilder = PaymentSheet.Appearance.Builder() + appearanceBuilder.embeddedAppearance(embeddedBuilder.build()) + + val expectedAppearance = appearanceBuilder.build() + + assertEquals(expectedAppearance, appearanceFromJson) + } + + private fun jsonToMap(json: String): ReadableMap { + val jsonObject = JSONObject(json) + return jsonObjectToMap(jsonObject) + } + + private fun jsonObjectToMap(jsonObject: JSONObject): ReadableMap { + val map = JavaOnlyMap() + val keys = jsonObject.keys() + while (keys.hasNext()) { + val key = keys.next() + val value = jsonObject.get(key) + when (value) { + is JSONObject -> map.putMap(key, jsonObjectToMap(value)) + is String -> map.putString(key, value) + is Int -> map.putInt(key, value) + is Double -> map.putDouble(key, value) + is Boolean -> map.putBoolean(key, value) + is Long -> map.putDouble(key, value.toDouble()) + JSONObject.NULL -> {} // skip null values + } + } + return map + } +} diff --git a/android/src/androidTest/java/com/reactnativestripesdk/addresssheet/AddressSheetViewTest.kt b/android/src/androidTest/java/com/reactnativestripesdk/addresssheet/AddressSheetViewTest.kt index 66176bbdc0..041a64772f 100644 --- a/android/src/androidTest/java/com/reactnativestripesdk/addresssheet/AddressSheetViewTest.kt +++ b/android/src/androidTest/java/com/reactnativestripesdk/addresssheet/AddressSheetViewTest.kt @@ -11,6 +11,7 @@ import com.stripe.android.paymentsheet.addresselement.AddressLauncher import org.junit.Assert import org.junit.Before import org.junit.Test +import kotlin.math.exp class AddressSheetViewTest { private val testCity = "testCity" @@ -122,13 +123,8 @@ class AddressSheetViewTest { @Test fun buildAdditionalFieldsConfiguration_Default() { val result = AddressSheetView.buildAdditionalFieldsConfiguration(WritableNativeMap()) - - Assert.assertEquals( - result.phone, - AddressLauncher.AdditionalFieldsConfiguration.FieldConfiguration.HIDDEN, - ) - - Assert.assertNull(result.checkboxLabel) + val expected = AddressLauncher.AdditionalFieldsConfiguration() + Assert.assertEquals(result, expected) } @Test @@ -141,16 +137,8 @@ class AddressSheetViewTest { } val received = AddressSheetView.buildAdditionalFieldsConfiguration(params) - - Assert.assertEquals( - received.phone, - AddressLauncher.AdditionalFieldsConfiguration.FieldConfiguration.REQUIRED, - ) - - Assert.assertEquals( - received.checkboxLabel, - label, - ) + val expected = AddressLauncher.AdditionalFieldsConfiguration(AddressLauncher.AdditionalFieldsConfiguration.FieldConfiguration.REQUIRED, label) + Assert.assertEquals(received, expected) } @Test diff --git a/android/src/main/java/com/reactnativestripesdk/CardFieldView.kt b/android/src/main/java/com/reactnativestripesdk/CardFieldView.kt index 9b21da7209..6c8252b007 100644 --- a/android/src/main/java/com/reactnativestripesdk/CardFieldView.kt +++ b/android/src/main/java/com/reactnativestripesdk/CardFieldView.kt @@ -282,9 +282,9 @@ class CardFieldView( cardAddress = null } - mCardWidget.cardParams?.let { - cardDetails["brand"] = mapCardBrand(it.brand) - cardDetails["last4"] = it.last4 + mCardWidget.paymentMethodCreateParams?.let { + cardDetails["brand"] = mapCardBrand(mCardWidget.brand) + cardDetails["last4"] = it.cardLast4() } ?: run { cardDetails["brand"] = null cardDetails["last4"] = null diff --git a/android/src/main/java/com/reactnativestripesdk/CardFormView.kt b/android/src/main/java/com/reactnativestripesdk/CardFormView.kt index 4ca7b09039..10b76fe642 100644 --- a/android/src/main/java/com/reactnativestripesdk/CardFormView.kt +++ b/android/src/main/java/com/reactnativestripesdk/CardFormView.kt @@ -245,16 +245,16 @@ class CardFormView( private fun setListeners() { cardForm.setCardValidCallback { isValid, _ -> if (isValid) { - cardForm.cardParams?.let { + cardForm.paymentMethodCreateParams?.let { val cardParamsMap = it.toParamMap()["card"] as HashMap<*, *> val cardDetails: MutableMap = mutableMapOf( "expiryMonth" to cardParamsMap["exp_month"] as Int, "expiryYear" to cardParamsMap["exp_year"] as Int, - "last4" to it.last4, - "brand" to mapCardBrand(it.brand), - "postalCode" to (it.address?.postalCode ?: ""), - "country" to (it.address?.country ?: ""), + "last4" to (it.cardLast4() ?: ""), + "brand" to mapCardBrand(cardForm.brand), + "postalCode" to (it.billingDetails?.address?.postalCode ?: ""), + "country" to (it.billingDetails?.address?.country ?: ""), ) if (dangerouslyGetFullCardDetails) { @@ -277,8 +277,8 @@ class CardFormView( cardAddress = Address .Builder() - .setPostalCode(it.address?.postalCode) - .setCountry(it.address?.country) + .setPostalCode(it.billingDetails?.address?.postalCode) + .setCountry(it.billingDetails?.address?.country) .build() cardFormViewBinding.cardMultilineWidget.paymentMethodCard?.let { params -> diff --git a/android/src/main/java/com/reactnativestripesdk/PaymentMethodCreateParamsFactory.kt b/android/src/main/java/com/reactnativestripesdk/PaymentMethodCreateParamsFactory.kt index 42852b835f..83dd7834e0 100644 --- a/android/src/main/java/com/reactnativestripesdk/PaymentMethodCreateParamsFactory.kt +++ b/android/src/main/java/com/reactnativestripesdk/PaymentMethodCreateParamsFactory.kt @@ -42,7 +42,6 @@ class PaymentMethodCreateParamsFactory( PaymentMethod.Type.Billie -> createBillieParams() PaymentMethod.Type.SepaDebit -> createSepaParams() PaymentMethod.Type.Oxxo -> createOXXOParams() - PaymentMethod.Type.Giropay -> createGiropayParams() PaymentMethod.Type.Eps -> createEPSParams() PaymentMethod.Type.GrabPay -> createGrabPayParams() PaymentMethod.Type.P24 -> createP24Params() @@ -131,15 +130,6 @@ class PaymentMethodCreateParamsFactory( throw PaymentMethodCreateParamsException("You must provide billing details") } - @Throws(PaymentMethodCreateParamsException::class) - private fun createGiropayParams(): PaymentMethodCreateParams { - billingDetailsParams?.let { - return PaymentMethodCreateParams.createGiropay(billingDetails = it, metadata = metadataParams) - } - - throw PaymentMethodCreateParamsException("You must provide billing details") - } - @Throws(PaymentMethodCreateParamsException::class) private fun createEPSParams(): PaymentMethodCreateParams { billingDetailsParams?.let { @@ -265,7 +255,6 @@ class PaymentMethodCreateParamsFactory( PaymentMethod.Type.Billie, PaymentMethod.Type.SepaDebit, PaymentMethod.Type.Oxxo, - PaymentMethod.Type.Giropay, PaymentMethod.Type.Eps, PaymentMethod.Type.GrabPay, PaymentMethod.Type.P24, diff --git a/android/src/main/java/com/reactnativestripesdk/PaymentSheetAppearance.kt b/android/src/main/java/com/reactnativestripesdk/PaymentSheetAppearance.kt index add2c6785f..edd22a0f58 100644 --- a/android/src/main/java/com/reactnativestripesdk/PaymentSheetAppearance.kt +++ b/android/src/main/java/com/reactnativestripesdk/PaymentSheetAppearance.kt @@ -8,8 +8,8 @@ import com.facebook.react.bridge.Arguments import com.facebook.react.bridge.ReadableMap import com.facebook.react.bridge.ReadableType import com.reactnativestripesdk.utils.PaymentSheetAppearanceException -import com.reactnativestripesdk.utils.getBooleanOr import com.reactnativestripesdk.utils.getDoubleOrNull +import com.reactnativestripesdk.utils.getBooleanOrNull import com.reactnativestripesdk.utils.getFloatOr import com.reactnativestripesdk.utils.getFloatOrNull import com.stripe.android.paymentelement.AppearanceAPIAdditionsPreview @@ -29,38 +29,23 @@ fun buildPaymentSheetAppearance( val embeddedAppearance = buildEmbeddedAppearance( userParams?.getMap(PaymentSheetAppearanceKeys.EMBEDDED_PAYMENT_ELEMENT), - lightColorParams, context, ) - embeddedAppearance?.let { - return PaymentSheet.Appearance( - typography = buildTypography(userParams?.getMap(PaymentSheetAppearanceKeys.FONT), context), - colorsLight = buildColors(lightColorParams, PaymentSheet.Colors.defaultLight), - colorsDark = buildColors(darkColorParams, PaymentSheet.Colors.defaultDark), - shapes = buildShapes(userParams?.getMap(PaymentSheetAppearanceKeys.SHAPES)), - primaryButton = - buildPrimaryButton( - userParams?.getMap(PaymentSheetAppearanceKeys.PRIMARY_BUTTON), - context, - ), - embeddedAppearance = embeddedAppearance, - formInsetValues = buildFormInsets(insetParams), + val builder = PaymentSheet.Appearance.Builder() + builder.typography(buildTypography(userParams?.getMap(PaymentSheetAppearanceKeys.FONT), context)) + builder.colorsLight(buildColorsBuilder(lightColorParams).buildLight()) + builder.colorsDark(buildColorsBuilder(darkColorParams).buildDark()) + builder.shapes(buildShapes(userParams?.getMap(PaymentSheetAppearanceKeys.SHAPES))) + builder.primaryButton( + buildPrimaryButton( + userParams?.getMap(PaymentSheetAppearanceKeys.PRIMARY_BUTTON), + context, ) - } - - return PaymentSheet.Appearance( - typography = buildTypography(userParams?.getMap(PaymentSheetAppearanceKeys.FONT), context), - colorsLight = buildColors(lightColorParams, PaymentSheet.Colors.defaultLight), - colorsDark = buildColors(darkColorParams, PaymentSheet.Colors.defaultDark), - shapes = buildShapes(userParams?.getMap(PaymentSheetAppearanceKeys.SHAPES)), - primaryButton = - buildPrimaryButton( - userParams?.getMap(PaymentSheetAppearanceKeys.PRIMARY_BUTTON), - context, - ), - formInsetValues = buildFormInsets(insetParams), ) + builder.embeddedAppearance(embeddedAppearance) + builder.formInsetValues(buildFormInsets(insetParams)) + return builder.build() } @OptIn(AppearanceAPIAdditionsPreview::class) @@ -73,114 +58,98 @@ private fun buildTypography( getFontResId( fontParams, PaymentSheetAppearanceKeys.FAMILY, - PaymentSheet.Typography.default.fontResId, context, ) - return PaymentSheet.Typography.default.copy( - sizeScaleFactor = scale?.toFloat() ?: PaymentSheet.Typography.default.sizeScaleFactor, - fontResId = resId, - ) + val builder = PaymentSheet.Typography.Builder() + scale?.let { + builder.sizeScaleFactor(it.toFloat()) + } + resId?.let { + builder.fontResId(it) + } + return builder.build() } @Throws(PaymentSheetAppearanceException::class) -private fun colorFromHexOrDefault( +private fun colorFromHex( hexString: String?, - default: Int, -): Int { +): Int? { return hexString?.trim()?.replace("#", "")?.let { if (it.length == 6 || it.length == 8) { - return Color.parseColor("#$it") + Color.parseColor("#$it") } else { throw PaymentSheetAppearanceException( "Failed to set Payment Sheet appearance. Expected hex string of length 6 or 8, but received: $it", ) } } - ?: run { - return default - } } -private fun buildColors( +private fun buildColorsBuilder( colorParams: ReadableMap?, - default: PaymentSheet.Colors, -): PaymentSheet.Colors { - if (colorParams == null) { - return default +): PaymentSheet.Colors.Builder { + val builder = PaymentSheet.Colors.Builder() + + colorFromHex(colorParams?.getString(PaymentSheetAppearanceKeys.PRIMARY))?.let { + builder.primary(it) } - return default.copy( - primary = - colorFromHexOrDefault( - colorParams.getString(PaymentSheetAppearanceKeys.PRIMARY), - default.primary, - ), - surface = - colorFromHexOrDefault( - colorParams.getString(PaymentSheetAppearanceKeys.BACKGROUND), - default.surface, - ), - component = - colorFromHexOrDefault( - colorParams.getString(PaymentSheetAppearanceKeys.COMPONENT_BACKGROUND), - default.component, - ), - componentBorder = - colorFromHexOrDefault( - colorParams.getString(PaymentSheetAppearanceKeys.COMPONENT_BORDER), - default.componentBorder, - ), - componentDivider = - colorFromHexOrDefault( - colorParams.getString(PaymentSheetAppearanceKeys.COMPONENT_DIVIDER), - default.componentDivider, - ), - onComponent = - colorFromHexOrDefault( - colorParams.getString(PaymentSheetAppearanceKeys.COMPONENT_TEXT), - default.onComponent, - ), - onSurface = - colorFromHexOrDefault( - colorParams.getString(PaymentSheetAppearanceKeys.PRIMARY_TEXT), - default.onSurface, - ), - subtitle = - colorFromHexOrDefault( - colorParams.getString(PaymentSheetAppearanceKeys.SECONDARY_TEXT), - default.subtitle, - ), - placeholderText = - colorFromHexOrDefault( - colorParams.getString(PaymentSheetAppearanceKeys.PLACEHOLDER_TEXT), - default.placeholderText, - ), - appBarIcon = - colorFromHexOrDefault( - colorParams.getString(PaymentSheetAppearanceKeys.ICON), - default.appBarIcon, - ), - error = - colorFromHexOrDefault( - colorParams.getString(PaymentSheetAppearanceKeys.ERROR), - default.error, - ), - ) + colorFromHex(colorParams?.getString(PaymentSheetAppearanceKeys.BACKGROUND))?.let { + builder.surface(it) + } + + colorFromHex(colorParams?.getString(PaymentSheetAppearanceKeys.COMPONENT_BACKGROUND))?.let { + builder.component(it) + } + + colorFromHex(colorParams?.getString(PaymentSheetAppearanceKeys.COMPONENT_BORDER))?.let { + builder.componentBorder(it) + } + + colorFromHex(colorParams?.getString(PaymentSheetAppearanceKeys.COMPONENT_DIVIDER))?.let { + builder.componentDivider(it) + } + + colorFromHex(colorParams?.getString(PaymentSheetAppearanceKeys.COMPONENT_TEXT))?.let { + builder.onComponent(it) + } + + colorFromHex(colorParams?.getString(PaymentSheetAppearanceKeys.PRIMARY_TEXT))?.let { + builder.onSurface(it) + } + + colorFromHex(colorParams?.getString(PaymentSheetAppearanceKeys.SECONDARY_TEXT))?.let { + builder.subtitle(it) + } + + colorFromHex(colorParams?.getString(PaymentSheetAppearanceKeys.PLACEHOLDER_TEXT))?.let { + builder.placeholderText(it) + } + + colorFromHex(colorParams?.getString(PaymentSheetAppearanceKeys.ICON))?.let { + builder.appBarIcon(it) + } + + colorFromHex(colorParams?.getString(PaymentSheetAppearanceKeys.ERROR))?.let { + builder.error(it) + } + + return builder } -private fun buildShapes(shapeParams: ReadableMap?): PaymentSheet.Shapes = - PaymentSheet.Shapes.default.copy( - cornerRadiusDp = - shapeParams.getFloatOr( - PaymentSheetAppearanceKeys.BORDER_RADIUS, - PaymentSheet.Shapes.default.cornerRadiusDp, - ), - borderStrokeWidthDp = - shapeParams.getFloatOr( - PaymentSheetAppearanceKeys.BORDER_WIDTH, - PaymentSheet.Shapes.default.borderStrokeWidthDp, - ), - ) +private fun buildShapes(shapeParams: ReadableMap?): PaymentSheet.Shapes { + val builder = PaymentSheet.Shapes.Builder() + + shapeParams.getFloatOrNull(PaymentSheetAppearanceKeys.BORDER_RADIUS)?.let { + builder.cornerRadiusDp(it) + } + + shapeParams.getFloatOrNull(PaymentSheetAppearanceKeys.BORDER_WIDTH)?.let { + builder.borderStrokeWidthDp(it) + } + + return builder.build() +} private fun buildPrimaryButton( params: ReadableMap?, @@ -198,9 +167,9 @@ private fun buildPrimaryButton( return PaymentSheet.PrimaryButton( colorsLight = - buildPrimaryButtonColors(lightColorParams, PaymentSheet.PrimaryButtonColors.defaultLight, context), + buildPrimaryButtonColors(lightColorParams, context).buildLight(), colorsDark = - buildPrimaryButtonColors(darkColorParams, PaymentSheet.PrimaryButtonColors.defaultDark, context), + buildPrimaryButtonColors(darkColorParams, context).buildDark(), shape = PaymentSheet.PrimaryButtonShape( cornerRadiusDp = @@ -212,7 +181,7 @@ private fun buildPrimaryButton( typography = PaymentSheet.PrimaryButtonTypography( fontResId = - getFontResId(fontParams, PaymentSheetAppearanceKeys.FAMILY, null, context), + getFontResId(fontParams, PaymentSheetAppearanceKeys.FAMILY, context), ), ) } @@ -220,265 +189,248 @@ private fun buildPrimaryButton( @Throws(PaymentSheetAppearanceException::class) private fun buildPrimaryButtonColors( colorParams: ReadableMap, - default: PaymentSheet.PrimaryButtonColors, context: Context, -): PaymentSheet.PrimaryButtonColors = - PaymentSheet.PrimaryButtonColors( - background = - colorParams - .getString(PaymentSheetAppearanceKeys.BACKGROUND) - ?.trim() - ?.replace("#", "") - ?.let { - if (it.length == 6 || it.length == 8) { - Color.parseColor("#$it") - } else { - throw PaymentSheetAppearanceException( - "Failed to set Payment Sheet appearance. Expected hex string of length 6 or 8, but received: $it", - ) - } - } ?: run { null }, - onBackground = - colorFromHexOrDefault( - colorParams.getString(PaymentSheetAppearanceKeys.TEXT), - default.onBackground, - ), - border = - colorFromHexOrDefault( - colorParams.getString(PaymentSheetAppearanceKeys.BORDER), - default.border, - ), - successBackgroundColor = - dynamicColorFromParams( - context, - colorParams, - PaymentSheetAppearanceKeys.SUCCESS_BACKGROUND, - default.successBackgroundColor, - ), - onSuccessBackgroundColor = - dynamicColorFromParams( - context, - colorParams, - PaymentSheetAppearanceKeys.SUCCESS_TEXT, - default.onSuccessBackgroundColor, - ), - ) +): PaymentSheet.PrimaryButtonColors.Builder { + val builder = PaymentSheet.PrimaryButtonColors.Builder() + + // TODO: Why is background a string but successBackgroundColor a "dynamic" color? + // https://stripe.dev/stripe-react-native/api-reference/types/PaymentSheet.PrimaryButtonColorConfig.html + colorFromHex(colorParams.getString(PaymentSheetAppearanceKeys.BACKGROUND))?.let { + builder.background(it) + } + + colorFromHex(colorParams.getString(PaymentSheetAppearanceKeys.TEXT))?.let { + builder.onBackground(it) + } + + colorFromHex(colorParams.getString(PaymentSheetAppearanceKeys.BORDER))?.let { + builder.border(it) + } + + dynamicColorFromParams( + context, + colorParams, + PaymentSheetAppearanceKeys.SUCCESS_BACKGROUND, + )?.let { + builder.successBackgroundColor(it) + } + + dynamicColorFromParams( + context, + colorParams, + PaymentSheetAppearanceKeys.SUCCESS_TEXT, + )?.let { + builder.onSuccessBackgroundColor(it) + } + return builder +} @SuppressLint("RestrictedApi") @Throws(PaymentSheetAppearanceException::class) private fun buildEmbeddedAppearance( embeddedParams: ReadableMap?, - defaultColorsMap: ReadableMap?, context: Context, -): PaymentSheet.Appearance.Embedded? { - if (embeddedParams == null) { - return null - } +): PaymentSheet.Appearance.Embedded { + val embeddedBuilder = PaymentSheet.Appearance.Embedded.Builder() + val rowParams = embeddedParams?.getMap(PaymentSheetAppearanceKeys.ROW) + val styleString = rowParams?.getString(PaymentSheetAppearanceKeys.STYLE) + when (styleString) { + "flatWithRadio" -> { + val flatParams = rowParams.getMap(PaymentSheetAppearanceKeys.FLAT) + val radioParams = flatParams?.getMap(PaymentSheetAppearanceKeys.RADIO) + val separatorInsetsParams = + flatParams?.getMap(PaymentSheetAppearanceKeys.SEPARATOR_INSETS) + + val flatRadioColorsBuilder = + PaymentSheet.Appearance.Embedded.RowStyle.FlatWithRadio.Colors.Builder() - val rowParams = - embeddedParams.getMap(PaymentSheetAppearanceKeys.ROW) - ?: return null - - val defaultColors = buildColors(defaultColorsMap, PaymentSheet.Colors.defaultLight) - - // Default style - val styleString = rowParams.getString(PaymentSheetAppearanceKeys.STYLE) ?: "flatWithRadio" - - val defaultAdditionalInsetsDp = 6.0f - val defaultSeparatorThicknessDp = 1.0f - val defaultSpacingDp = 12.0f - val defaultCheckmarkInsetDp = 0f - - val additionalInsets = rowParams.getFloatOr(PaymentSheetAppearanceKeys.ADDITIONAL_INSETS, defaultAdditionalInsetsDp) - - val rowStyle: PaymentSheet.Appearance.Embedded.RowStyle = - when (styleString) { - "flatWithRadio" -> { - val flatParams = rowParams.getMap(PaymentSheetAppearanceKeys.FLAT) - val radioParams = flatParams?.getMap(PaymentSheetAppearanceKeys.RADIO) - val separatorInsetsParams = flatParams?.getMap(PaymentSheetAppearanceKeys.SEPARATOR_INSETS) - - // Default separator insets specific to FlatWithRadio - val defaultSeparatorStartInsetDp = 30.0f - val defaultSeparatorEndInsetDp = 0.0f - - // Parse dimensions as Floats - val separatorThickness = flatParams.getFloatOr(PaymentSheetAppearanceKeys.SEPARATOR_THICKNESS, defaultSeparatorThicknessDp) - val startSeparatorInset = separatorInsetsParams.getFloatOr(PaymentSheetAppearanceKeys.LEFT, defaultSeparatorStartInsetDp) - val endSeparatorInset = separatorInsetsParams.getFloatOr(PaymentSheetAppearanceKeys.RIGHT, defaultSeparatorEndInsetDp) - - // Parse booleans - val topEnabled = flatParams.getBooleanOr(PaymentSheetAppearanceKeys.TOP_SEPARATOR_ENABLED, true) - val bottomEnabled = flatParams.getBooleanOr(PaymentSheetAppearanceKeys.BOTTOM_SEPARATOR_ENABLED, true) - - // Parse individual colors using default colors - val parsedSeparatorColor = - dynamicColorFromParams( - context, - flatParams, - PaymentSheetAppearanceKeys.SEPARATOR_COLOR, - defaultColors.componentBorder, - ) - - val parsedSelectedColor = - dynamicColorFromParams( - context, - radioParams, - PaymentSheetAppearanceKeys.SELECTED_COLOR, - defaultColors.primary, - ) - - val parsedUnselectedColor = - dynamicColorFromParams( - context, - radioParams, - PaymentSheetAppearanceKeys.UNSELECTED_COLOR, - defaultColors.componentBorder, - ) - - val flatRadioColors = - PaymentSheet.Appearance.Embedded.RowStyle.FlatWithRadio.Colors( - separatorColor = parsedSeparatorColor, - unselectedColor = parsedUnselectedColor, - selectedColor = parsedSelectedColor, - ) - - PaymentSheet.Appearance.Embedded.RowStyle.FlatWithRadio( - separatorThicknessDp = separatorThickness, - startSeparatorInsetDp = startSeparatorInset, - endSeparatorInsetDp = endSeparatorInset, - topSeparatorEnabled = topEnabled, - bottomSeparatorEnabled = bottomEnabled, - additionalVerticalInsetsDp = additionalInsets, - horizontalInsetsDp = 0.0F, // We do not have an iOS equal for this API so it's not configurable in React Native - colorsLight = flatRadioColors, - colorsDark = flatRadioColors, - ) + dynamicColorFromParams( + context, + flatParams, + PaymentSheetAppearanceKeys.SEPARATOR_COLOR + )?.let { + flatRadioColorsBuilder.separatorColor(it) } - "flatWithCheckmark" -> { - val flatParams = rowParams.getMap(PaymentSheetAppearanceKeys.FLAT) - val checkmarkParams = flatParams?.getMap(PaymentSheetAppearanceKeys.CHECKMARK) - val separatorInsetsParams = flatParams?.getMap(PaymentSheetAppearanceKeys.SEPARATOR_INSETS) - - // Default separator insets specific to FlatWithCheckmark and FlatWithDisclosure - val defaultSeparatorStartInsetDp = 0.0f - val defaultSeparatorEndInsetDp = 0.0f - - // Parse dimensions as Floats - val separatorThickness = flatParams.getFloatOr(PaymentSheetAppearanceKeys.SEPARATOR_THICKNESS, defaultSeparatorThicknessDp) - val startSeparatorInset = separatorInsetsParams.getFloatOr(PaymentSheetAppearanceKeys.LEFT, defaultSeparatorStartInsetDp) - val endSeparatorInset = separatorInsetsParams.getFloatOr(PaymentSheetAppearanceKeys.RIGHT, defaultSeparatorEndInsetDp) - val checkmarkInset = checkmarkParams.getFloatOr(PaymentSheetAppearanceKeys.CHECKMARK_INSET, defaultCheckmarkInsetDp) - - // Parse booleans - val topEnabled = flatParams.getBooleanOr(PaymentSheetAppearanceKeys.TOP_SEPARATOR_ENABLED, true) - val bottomEnabled = flatParams.getBooleanOr(PaymentSheetAppearanceKeys.BOTTOM_SEPARATOR_ENABLED, true) - - // Parse individual colors using root defaults - val parsedSeparatorColor = - dynamicColorFromParams( - context, - flatParams, - PaymentSheetAppearanceKeys.SEPARATOR_COLOR, - defaultColors.componentBorder, - ) - - val parsedCheckmarkColor = - dynamicColorFromParams( - context, - checkmarkParams, - PaymentSheetAppearanceKeys.COLOR, - defaultColors.primary, - ) - - // Create the required Colors object - val flatCheckmarkColors = - PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark.Colors( - separatorColor = parsedSeparatorColor, - checkmarkColor = parsedCheckmarkColor, - ) - - PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark( - separatorThicknessDp = separatorThickness, - startSeparatorInsetDp = startSeparatorInset, - endSeparatorInsetDp = endSeparatorInset, - topSeparatorEnabled = topEnabled, - bottomSeparatorEnabled = bottomEnabled, - checkmarkInsetDp = checkmarkInset, - additionalVerticalInsetsDp = additionalInsets, - horizontalInsetsDp = 0.0F, // We do not have an iOS equal for this API so it's not configurable in React Native - colorsLight = flatCheckmarkColors, - colorsDark = flatCheckmarkColors, - ) + + dynamicColorFromParams( + context, + radioParams, + PaymentSheetAppearanceKeys.SELECTED_COLOR + )?.let { + flatRadioColorsBuilder.selectedColor(it) } - "flatWithDisclosure" -> { - val flatParams = rowParams.getMap(PaymentSheetAppearanceKeys.FLAT) - val disclosureParams = flatParams?.getMap(PaymentSheetAppearanceKeys.DISCLOSURE) - val separatorInsetsParams = flatParams?.getMap(PaymentSheetAppearanceKeys.SEPARATOR_INSETS) - - // Default separator insets specific to FlatWithCheckmark and FlatWithDisclosure - val defaultSeparatorStartInsetDp = 0.0f - val defaultSeparatorEndInsetDp = 0.0f - - // Parse dimensions as Floats - val separatorThickness = flatParams.getFloatOr(PaymentSheetAppearanceKeys.SEPARATOR_THICKNESS, defaultSeparatorThicknessDp) - val startSeparatorInset = separatorInsetsParams.getFloatOr(PaymentSheetAppearanceKeys.LEFT, defaultSeparatorStartInsetDp) - val endSeparatorInset = separatorInsetsParams.getFloatOr(PaymentSheetAppearanceKeys.RIGHT, defaultSeparatorEndInsetDp) - - // Parse booleans - val topEnabled = flatParams.getBooleanOr(PaymentSheetAppearanceKeys.TOP_SEPARATOR_ENABLED, true) - val bottomEnabled = flatParams.getBooleanOr(PaymentSheetAppearanceKeys.BOTTOM_SEPARATOR_ENABLED, true) - - val parsedSeparatorColor = - dynamicColorFromParams( - context, - flatParams, - PaymentSheetAppearanceKeys.SEPARATOR_COLOR, - Color.GRAY, - ) - - val parsedDisclosureColor = - dynamicColorFromParams( - context, - disclosureParams, - PaymentSheetAppearanceKeys.COLOR, - defaultColors.componentBorder, // Default to component border color like other elements - ) - - // Create the required Colors object - val flatDisclosureColors = - PaymentSheet.Appearance.Embedded.RowStyle.FlatWithDisclosure.Colors( - separatorColor = parsedSeparatorColor, - disclosureColor = parsedDisclosureColor, - ) - - PaymentSheet.Appearance.Embedded.RowStyle.FlatWithDisclosure - .Builder() - .separatorThicknessDp(separatorThickness) - .startSeparatorInsetDp(startSeparatorInset) - .endSeparatorInsetDp(endSeparatorInset) - .topSeparatorEnabled(topEnabled) - .bottomSeparatorEnabled(bottomEnabled) - .additionalVerticalInsetsDp(additionalInsets) - .horizontalInsetsDp(0.0F) // We do not have an iOS equal for this API so it's not configurable in React Native - .colorsLight(flatDisclosureColors) - .colorsDark(flatDisclosureColors) - .build() + + dynamicColorFromParams( + context, + radioParams, + PaymentSheetAppearanceKeys.UNSELECTED_COLOR + )?.let { + flatRadioColorsBuilder.unselectedColor(it) + } + + val rowStyleBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithRadio.Builder() + + flatParams.getFloatOrNull(PaymentSheetAppearanceKeys.SEPARATOR_THICKNESS)?.let { + rowStyleBuilder.separatorThicknessDp(it) + } + + separatorInsetsParams.getFloatOrNull(PaymentSheetAppearanceKeys.LEFT)?.let { + rowStyleBuilder.startSeparatorInsetDp(it) + } + + separatorInsetsParams.getFloatOrNull(PaymentSheetAppearanceKeys.RIGHT)?.let { + rowStyleBuilder.endSeparatorInsetDp(it) + } + + flatParams.getBooleanOrNull(PaymentSheetAppearanceKeys.TOP_SEPARATOR_ENABLED)?.let { + rowStyleBuilder.topSeparatorEnabled(it) + } + + flatParams.getBooleanOrNull(PaymentSheetAppearanceKeys.BOTTOM_SEPARATOR_ENABLED)?.let { + rowStyleBuilder.bottomSeparatorEnabled(it) + } + + rowParams.getFloatOrNull(PaymentSheetAppearanceKeys.ADDITIONAL_INSETS)?.let { + rowStyleBuilder.additionalVerticalInsetsDp(it) + } + + rowStyleBuilder.colorsLight(flatRadioColorsBuilder.buildLight()) + rowStyleBuilder.colorsDark(flatRadioColorsBuilder.buildDark()) + + embeddedBuilder.rowStyle(rowStyleBuilder.build()) + } + + "flatWithCheckmark" -> { + val flatParams = rowParams?.getMap(PaymentSheetAppearanceKeys.FLAT) + val checkmarkParams = flatParams?.getMap(PaymentSheetAppearanceKeys.CHECKMARK) + val separatorInsetsParams = + flatParams?.getMap(PaymentSheetAppearanceKeys.SEPARATOR_INSETS) + + val flatCheckmarkColorsBuilder = + PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark.Colors.Builder() + + dynamicColorFromParams( + context, + flatParams, + PaymentSheetAppearanceKeys.SEPARATOR_COLOR + )?.let { + flatCheckmarkColorsBuilder.separatorColor(it) + } + + dynamicColorFromParams(context, checkmarkParams, PaymentSheetAppearanceKeys.COLOR)?.let { + flatCheckmarkColorsBuilder.checkmarkColor(it) + } + + val rowStyleBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark.Builder() + + flatParams.getFloatOrNull(PaymentSheetAppearanceKeys.SEPARATOR_THICKNESS)?.let { + rowStyleBuilder.separatorThicknessDp(it) + } + + separatorInsetsParams.getFloatOrNull(PaymentSheetAppearanceKeys.LEFT)?.let { + rowStyleBuilder.startSeparatorInsetDp(it) + } + + separatorInsetsParams.getFloatOrNull(PaymentSheetAppearanceKeys.RIGHT)?.let { + rowStyleBuilder.endSeparatorInsetDp(it) + } + + flatParams.getBooleanOrNull(PaymentSheetAppearanceKeys.TOP_SEPARATOR_ENABLED)?.let { + rowStyleBuilder.topSeparatorEnabled(it) } - "floatingButton" -> { - val floatingParams = rowParams.getMap(PaymentSheetAppearanceKeys.FLOATING) - PaymentSheet.Appearance.Embedded.RowStyle.FloatingButton( - additionalInsetsDp = additionalInsets, - spacingDp = floatingParams.getFloatOr(PaymentSheetAppearanceKeys.SPACING, defaultSpacingDp), - ) + + flatParams.getBooleanOrNull(PaymentSheetAppearanceKeys.BOTTOM_SEPARATOR_ENABLED)?.let { + rowStyleBuilder.bottomSeparatorEnabled(it) } - else -> { - System.err.println("WARN: Unsupported embedded payment element row style received: $styleString. Falling back to default.") - return null + + checkmarkParams.getFloatOrNull(PaymentSheetAppearanceKeys.CHECKMARK_INSET)?.let { + rowStyleBuilder.checkmarkInsetDp(it) } + + rowParams.getFloatOrNull(PaymentSheetAppearanceKeys.ADDITIONAL_INSETS)?.let { + rowStyleBuilder.additionalVerticalInsetsDp(it) + } + + // TODO: The theme is so crazy long, why does each Color thing has the same redundant Theme... + rowStyleBuilder.colorsLight(flatCheckmarkColorsBuilder.buildLight()) + rowStyleBuilder.colorsDark(flatCheckmarkColorsBuilder.buildDark()) + embeddedBuilder.rowStyle(rowStyleBuilder.build()) } - return PaymentSheet.Appearance.Embedded(style = rowStyle) + "flatWithDisclosure" -> { + val flatParams = rowParams?.getMap(PaymentSheetAppearanceKeys.FLAT) + val disclosureParams = flatParams?.getMap(PaymentSheetAppearanceKeys.DISCLOSURE) + val separatorInsetsParams = + flatParams?.getMap(PaymentSheetAppearanceKeys.SEPARATOR_INSETS) + + val flatDisclosureColorsBuilder = + PaymentSheet.Appearance.Embedded.RowStyle.FlatWithDisclosure.Colors.Builder() + + dynamicColorFromParams( + context, + flatParams, + PaymentSheetAppearanceKeys.SEPARATOR_COLOR + )?.let { + flatDisclosureColorsBuilder.separatorColor(it) + } + + dynamicColorFromParams(context, disclosureParams, PaymentSheetAppearanceKeys.COLOR)?.let { + flatDisclosureColorsBuilder.disclosureColor(it) + } + + + val rowStyleBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithDisclosure.Builder() + + flatParams.getFloatOrNull(PaymentSheetAppearanceKeys.SEPARATOR_THICKNESS)?.let { + rowStyleBuilder.separatorThicknessDp(it) + } + + separatorInsetsParams.getFloatOrNull(PaymentSheetAppearanceKeys.LEFT)?.let { + rowStyleBuilder.startSeparatorInsetDp(it) + } + + separatorInsetsParams.getFloatOrNull(PaymentSheetAppearanceKeys.RIGHT)?.let { + rowStyleBuilder.endSeparatorInsetDp(it) + } + + flatParams.getBooleanOrNull(PaymentSheetAppearanceKeys.TOP_SEPARATOR_ENABLED)?.let { + rowStyleBuilder.topSeparatorEnabled(it) + } + + flatParams.getBooleanOrNull(PaymentSheetAppearanceKeys.BOTTOM_SEPARATOR_ENABLED)?.let { + rowStyleBuilder.bottomSeparatorEnabled(it) + } + + rowParams.getFloatOrNull(PaymentSheetAppearanceKeys.ADDITIONAL_INSETS)?.let { + rowStyleBuilder.additionalVerticalInsetsDp(it) + } + + rowStyleBuilder.colorsLight(flatDisclosureColorsBuilder.buildLight()) + rowStyleBuilder.colorsDark(flatDisclosureColorsBuilder.buildDark()) + + embeddedBuilder.rowStyle(rowStyleBuilder.build()) + } + + "floatingButton" -> { + val floatingParams = rowParams.getMap(PaymentSheetAppearanceKeys.FLOATING) + val rowStyleBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FloatingButton.Builder() + + rowParams.getFloatOrNull(PaymentSheetAppearanceKeys.ADDITIONAL_INSETS)?.let { + rowStyleBuilder.additionalInsetsDp(it) + } + + floatingParams.getFloatOrNull(PaymentSheetAppearanceKeys.SPACING)?.let { + rowStyleBuilder.spacingDp(it) + } + + embeddedBuilder.rowStyle(rowStyleBuilder.build()) + } + + else -> { + System.err.println("WARN: Unsupported embedded payment element row style received: $styleString. Falling back to default.") + } + } + return embeddedBuilder.build() } @SuppressLint("RestrictedApi") @@ -502,16 +454,15 @@ private fun buildFormInsets(insetParams: ReadableMap?): PaymentSheet.Insets { * - Single hex string: "#RRGGBB" * - Light/dark object: { "light": "#RRGGBB", "dark": "#RRGGBB" } * For light/dark objects, chooses the appropriate color based on current UI mode. - * Falls back to [defaultColor] if no color is provided. + * Returns null if no color is provided. */ private fun dynamicColorFromParams( context: Context, params: ReadableMap?, key: String, - defaultColor: Int, -): Int { +): Int? { if (params == null) { - return defaultColor + return null } // First check if it's a nested map { "light": "#RRGGBB", "dark": "#RRGGBB" } @@ -531,28 +482,22 @@ private fun dynamicColorFromParams( colorMap?.getString(PaymentSheetAppearanceKeys.LIGHT) } - return colorFromHexOrDefault(hex, defaultColor) + return colorFromHex(hex) } // Check if it's a single color string - params.getString(key)?.let { colorString -> - return colorFromHexOrDefault(colorString, defaultColor) - } - - // no override → just use default - return defaultColor + return colorFromHex(params.getString(key)) } @Throws(PaymentSheetAppearanceException::class) private fun getFontResId( map: ReadableMap?, key: String, - defaultValue: Int?, context: Context, ): Int? { val fontErrorPrefix = "Encountered an error when setting a custom font:" if (map?.hasKey(key) != true) { - return defaultValue + return null } val fontFileName = diff --git a/android/src/main/java/com/reactnativestripesdk/PaymentSheetManager.kt b/android/src/main/java/com/reactnativestripesdk/PaymentSheetManager.kt index aeb6c933aa..47fca67c33 100644 --- a/android/src/main/java/com/reactnativestripesdk/PaymentSheetManager.kt +++ b/android/src/main/java/com/reactnativestripesdk/PaymentSheetManager.kt @@ -51,7 +51,6 @@ import com.stripe.android.paymentelement.ExperimentalCustomPaymentMethodsApi import com.stripe.android.paymentelement.PaymentMethodOptionsSetupFutureUsagePreview import com.stripe.android.paymentsheet.CreateIntentCallback import com.stripe.android.paymentsheet.CreateIntentResult -import com.stripe.android.paymentsheet.ExperimentalCustomerSessionApi import com.stripe.android.paymentsheet.PaymentOptionResultCallback import com.stripe.android.paymentsheet.PaymentSheet import com.stripe.android.paymentsheet.PaymentSheetResult @@ -684,7 +683,6 @@ class PaymentSheetManager( ) } - @OptIn(ExperimentalCustomerSessionApi::class) @Throws(PaymentSheetException::class) internal fun buildCustomerConfiguration(map: ReadableMap?): PaymentSheet.CustomerConfiguration? { val customerId = map?.getString("customerId").orEmpty() diff --git a/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt b/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt index 9e8132cafa..43e9b233a1 100644 --- a/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt +++ b/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt @@ -65,7 +65,6 @@ import com.stripe.android.model.PaymentMethod import com.stripe.android.model.SetupIntent import com.stripe.android.model.Token import com.stripe.android.payments.bankaccount.CollectBankAccountConfiguration -import com.stripe.android.paymentsheet.ExperimentalCustomerSessionApi import com.stripe.android.paymentsheet.PaymentSheet import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CoroutineScope @@ -1247,7 +1246,6 @@ class StripeSdkModule( } } - @OptIn(ExperimentalCustomerSessionApi::class) @ReactMethod override fun clientSecretProviderSetupIntentClientSecretCallback( setupIntentClientSecret: String, @@ -1261,7 +1259,6 @@ class StripeSdkModule( } } - @OptIn(ExperimentalCustomerSessionApi::class) @ReactMethod override fun clientSecretProviderCustomerSessionClientSecretCallback( customerSessionClientSecretJson: ReadableMap, diff --git a/android/src/main/java/com/reactnativestripesdk/customersheet/CustomerSheetManager.kt b/android/src/main/java/com/reactnativestripesdk/customersheet/CustomerSheetManager.kt index 343f701e6d..8f244a1bc7 100644 --- a/android/src/main/java/com/reactnativestripesdk/customersheet/CustomerSheetManager.kt +++ b/android/src/main/java/com/reactnativestripesdk/customersheet/CustomerSheetManager.kt @@ -40,13 +40,12 @@ import com.stripe.android.customersheet.CustomerSheet import com.stripe.android.customersheet.CustomerSheetResult import com.stripe.android.customersheet.PaymentOptionSelection import com.stripe.android.model.PaymentMethod -import com.stripe.android.paymentsheet.ExperimentalCustomerSessionApi import com.stripe.android.paymentsheet.PaymentSheet import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -@OptIn(ReactNativeSdkInternal::class, ExperimentalAllowsRemovalOfLastSavedPaymentMethodApi::class, ExperimentalCustomerSessionApi::class) +@OptIn(ReactNativeSdkInternal::class, ExperimentalAllowsRemovalOfLastSavedPaymentMethodApi::class) class CustomerSheetManager( context: ReactApplicationContext, private var arguments: ReadableMap, diff --git a/android/src/main/java/com/reactnativestripesdk/customersheet/ReactNativeCustomerSessionProvider.kt b/android/src/main/java/com/reactnativestripesdk/customersheet/ReactNativeCustomerSessionProvider.kt index 8084fa9742..f5258441a4 100644 --- a/android/src/main/java/com/reactnativestripesdk/customersheet/ReactNativeCustomerSessionProvider.kt +++ b/android/src/main/java/com/reactnativestripesdk/customersheet/ReactNativeCustomerSessionProvider.kt @@ -2,10 +2,8 @@ package com.reactnativestripesdk import com.facebook.react.bridge.ReactApplicationContext import com.stripe.android.customersheet.CustomerSheet -import com.stripe.android.paymentsheet.ExperimentalCustomerSessionApi import kotlinx.coroutines.CompletableDeferred -@OptIn(ExperimentalCustomerSessionApi::class) class ReactNativeCustomerSessionProvider( val context: ReactApplicationContext, val intentConfiguration: CustomerSheet.IntentConfiguration, diff --git a/android/src/main/java/com/reactnativestripesdk/utils/Extensions.kt b/android/src/main/java/com/reactnativestripesdk/utils/Extensions.kt index fd7710ed2a..2a77e3662a 100644 --- a/android/src/main/java/com/reactnativestripesdk/utils/Extensions.kt +++ b/android/src/main/java/com/reactnativestripesdk/utils/Extensions.kt @@ -48,6 +48,9 @@ fun ReadableMap?.getDoubleOr( fun ReadableMap?.getFloatOrNull(key: String): Float? = if (this?.hasKey(key) == true && this.getType(key) == ReadableType.Number) this.getDouble(key).toFloat() else null +fun ReadableMap?.getBooleanOrNull(key: String): Boolean? = + if (this?.hasKey(key) == true && this.getType(key) == ReadableType.Boolean) this.getBoolean(key) else null + fun ReadableMap?.getFloatOr( key: String, default: Float, diff --git a/android/src/main/java/com/reactnativestripesdk/utils/Mappers.kt b/android/src/main/java/com/reactnativestripesdk/utils/Mappers.kt index 8f1d2e3a06..4967caa0dd 100644 --- a/android/src/main/java/com/reactnativestripesdk/utils/Mappers.kt +++ b/android/src/main/java/com/reactnativestripesdk/utils/Mappers.kt @@ -136,7 +136,6 @@ internal fun mapPaymentMethodType(type: PaymentMethod.Type?): String = PaymentMethod.Type.CardPresent -> "CardPresent" PaymentMethod.Type.Eps -> "Eps" PaymentMethod.Type.Fpx -> "Fpx" - PaymentMethod.Type.Giropay -> "Giropay" PaymentMethod.Type.GrabPay -> "GrabPay" PaymentMethod.Type.Ideal -> "Ideal" PaymentMethod.Type.Netbanking -> "Netbanking" @@ -169,7 +168,6 @@ internal fun mapToPaymentMethodType(type: String?): PaymentMethod.Type? = "CardPresent" -> PaymentMethod.Type.CardPresent "Eps" -> PaymentMethod.Type.Eps "Fpx" -> PaymentMethod.Type.Fpx - "Giropay" -> PaymentMethod.Type.Giropay "GrabPay" -> PaymentMethod.Type.GrabPay "Netbanking" -> PaymentMethod.Type.Netbanking "Oxxo" -> PaymentMethod.Type.Oxxo From 7c12f5858ba1937178becef7f50d787f8aca3ed0 Mon Sep 17 00:00:00 2001 From: Yuki Date: Fri, 7 Nov 2025 15:17:18 -0800 Subject: [PATCH 4/8] update changelog --- CHANGELOG.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2990f85bd..3a2ebc4c99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,18 @@ # CHANGELOG +## x.x.x - x.x.x +**Changes** +- [Changed] Updated Stripe iOS SDK from 24.25.0 to 25.0.0 +- [Changed] Updated Stripe Android SDK from 21.29.+ to 22.0.+ +- [Removed] Removed Giropay. Use alternative payment methods instead. See [this page](https://docs.stripe.com/payments/giropay) for more information. + ## 0.56.0 - 2025-11-06 **Changes** - [Added] CustomerSession is now generally available. The `customerSessionClientSecret` parameter is no longer experimental. - [Added] ConfirmationTokens are now generally available. The `confirmationTokenConfirmHandler` parameter and `ConfirmationToken.Result` type are no longer experimental. -- [Added] Added support for `CustomerSession` to CustomerSheet. The CustomerSession object grants the SDK temporary access to the Customer and provides additional configuration options. These configuration options allow you to customize the behavior of CustomerSheet. A complete list of features exposed on the CustomerSession are [in our API docs](https://docs.corp.stripe.com/api/customer_sessions/create#create_customer_session-components-customer_sheet). +- [Added] Added support for `CustomerSession` to CustomerSheet. The CustomerSession object grants the SDK temporary access to the Customer and provides additional configuration options. These configuration options allow you to customize the behavior of CustomerSheet. A complete list of features exposed on the CustomerSession are [in our API docs](https://docs.corp.stripe.com/api/customer_sessions/create#create_customer_session-components-customer_sheet). * [Added] Added support for `onBehalfOf` to CustomerSheet.IntentConfiguration. This parameter makes CustomerSheet use a connected account to determine the payment method that users see and whether CardBrandChoice is enabled. For more information, see the [SetupIntent docs](https://docs.stripe.com/api/setup_intents/object#setup_intent_object-on_behalf_of). -- [Removed] Removed Giropay. Use alternative payment methods instead. See this page for more information. **Fixes** - Fixed Android crash `IllegalStateException: State must be at least CREATED to move to DESTROYED` when removing payment methods in EmbeddedPaymentElement. The crash occurred when views were destroyed before completing the lifecycle initialization. From eed60afaffc8f030393d94030d70b1c718177e1b Mon Sep 17 00:00:00 2001 From: Yuki Date: Fri, 7 Nov 2025 15:20:43 -0800 Subject: [PATCH 5/8] Revert "[TEMP] TODO DELETE THIS - make example prefer maven local" This reverts commit 66b9176ccf760d8d281dbe29b55bc08e065351e3. --- example/android/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/example/android/build.gradle b/example/android/build.gradle index 312df5c7b4..41aff0712a 100644 --- a/example/android/build.gradle +++ b/example/android/build.gradle @@ -24,7 +24,6 @@ buildscript { allprojects { repositories { - mavenLocal() maven { // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm url({ From 5096aa6280afbdc2935662cecb83ecc0bbb58748 Mon Sep 17 00:00:00 2001 From: Yuki Date: Fri, 7 Nov 2025 21:46:54 -0800 Subject: [PATCH 6/8] lint android and make it part of the pre-commit --- .husky/pre-commit | 2 +- .../PaymentSheetAppearanceTest.kt | 460 ++++++++++-------- .../addresssheet/AddressSheetViewTest.kt | 7 +- .../PaymentSheetAppearance.kt | 51 +- 4 files changed, 285 insertions(+), 235 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index db05b675dc..078411b497 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1 +1 @@ -yarn lint && yarn typescript +yarn lint && yarn typescript && yarn format:android:write diff --git a/android/src/androidTest/java/com/reactnativestripesdk/PaymentSheetAppearanceTest.kt b/android/src/androidTest/java/com/reactnativestripesdk/PaymentSheetAppearanceTest.kt index b84f8d96fa..98835eaa83 100644 --- a/android/src/androidTest/java/com/reactnativestripesdk/PaymentSheetAppearanceTest.kt +++ b/android/src/androidTest/java/com/reactnativestripesdk/PaymentSheetAppearanceTest.kt @@ -26,50 +26,51 @@ class PaymentSheetAppearanceTest { @Test fun testFullAppearanceConfiguration() { - val json = """ - { - "colors": { - "primary": "#123456", - "background": "#123456", - "componentBackground": "#123456", - "componentBorder": "#123456", - "componentDivider": "#123456", - "componentText": "#123456", - "primaryText": "#123456", - "secondaryText": "#123456", - "placeholderText": "#123456", - "icon": "#123456", - "error": "#123456" - }, - "shapes": { - "borderRadius": 42.0, - "borderWidth": 42.0 - }, - "font": { - "scale": 42.0 - }, - "primaryButton": { + val json = + """ + { "colors": { + "primary": "#123456", "background": "#123456", - "text": "#123456", - "border": "#123456", - "successBackgroundColor": "#123456", - "successTextColor": "#123456" + "componentBackground": "#123456", + "componentBorder": "#123456", + "componentDivider": "#123456", + "componentText": "#123456", + "primaryText": "#123456", + "secondaryText": "#123456", + "placeholderText": "#123456", + "icon": "#123456", + "error": "#123456" }, "shapes": { "borderRadius": 42.0, - "borderWidth": 42.0, - "height": 42.0 + "borderWidth": 42.0 + }, + "font": { + "scale": 42.0 + }, + "primaryButton": { + "colors": { + "background": "#123456", + "text": "#123456", + "border": "#123456", + "successBackgroundColor": "#123456", + "successTextColor": "#123456" + }, + "shapes": { + "borderRadius": 42.0, + "borderWidth": 42.0, + "height": 42.0 + } + }, + "formInsetValues": { + "left": 42.0, + "top": 42.0, + "right": 42.0, + "bottom": 42.0 } - }, - "formInsetValues": { - "left": 42.0, - "top": 42.0, - "right": 42.0, - "bottom": 42.0 } - } - """.trimIndent() + """.trimIndent() val map = jsonToMap(json) val appearanceFromJson = buildPaymentSheetAppearance(map, context) @@ -104,16 +105,18 @@ class PaymentSheetAppearanceTest { primaryButtonColorsBuilder.successBackgroundColor(testColor) primaryButtonColorsBuilder.onSuccessBackgroundColor(testColor) - val primaryButton = PaymentSheet.PrimaryButton( - colorsLight = primaryButtonColorsBuilder.buildLight(), - colorsDark = primaryButtonColorsBuilder.buildDark(), - shape = PaymentSheet.PrimaryButtonShape( - cornerRadiusDp = 42.0f, - borderStrokeWidthDp = 42.0f, - heightDp = 42.0f - ), - typography = PaymentSheet.PrimaryButtonTypography() - ) + val primaryButton = + PaymentSheet.PrimaryButton( + colorsLight = primaryButtonColorsBuilder.buildLight(), + colorsDark = primaryButtonColorsBuilder.buildDark(), + shape = + PaymentSheet.PrimaryButtonShape( + cornerRadiusDp = 42.0f, + borderStrokeWidthDp = 42.0f, + heightDp = 42.0f, + ), + typography = PaymentSheet.PrimaryButtonTypography(), + ) val appearanceBuilder = PaymentSheet.Appearance.Builder() appearanceBuilder.typography(typographyBuilder.build()) @@ -126,8 +129,8 @@ class PaymentSheetAppearanceTest { startDp = 42.0f, topDp = 42.0f, endDp = 42.0f, - bottomDp = 42.0f - ) + bottomDp = 42.0f, + ), ) val expectedAppearance = appearanceBuilder.build() @@ -137,31 +140,32 @@ class PaymentSheetAppearanceTest { @Test fun testPartialAppearanceConfiguration() { - val json = """ - { - "colors": { - "primary": "#123456", - "componentBackground": "#123456", - "componentDivider": "#123456", - "primaryText": "#123456", - "placeholderText": "#123456", - "error": "#123456" - }, - "shapes": { - "borderRadius": 42.0 - }, - "primaryButton": { + val json = + """ + { "colors": { - "background": "#123456", - "border": "#123456" + "primary": "#123456", + "componentBackground": "#123456", + "componentDivider": "#123456", + "primaryText": "#123456", + "placeholderText": "#123456", + "error": "#123456" }, "shapes": { - "borderRadius": 42.0, - "height": 42.0 + "borderRadius": 42.0 + }, + "primaryButton": { + "colors": { + "background": "#123456", + "border": "#123456" + }, + "shapes": { + "borderRadius": 42.0, + "height": 42.0 + } } } - } - """.trimIndent() + """.trimIndent() val map = jsonToMap(json) val appearanceFromJson = buildPaymentSheetAppearance(map, context) @@ -184,16 +188,18 @@ class PaymentSheetAppearanceTest { primaryButtonColorsBuilder.background(testColor) primaryButtonColorsBuilder.border(testColor) - val primaryButton = PaymentSheet.PrimaryButton( - colorsLight = primaryButtonColorsBuilder.buildLight(), - colorsDark = primaryButtonColorsBuilder.buildDark(), - shape = PaymentSheet.PrimaryButtonShape( - cornerRadiusDp = 42.0f, - borderStrokeWidthDp = null, - heightDp = 42.0f - ), - typography = PaymentSheet.PrimaryButtonTypography() - ) + val primaryButton = + PaymentSheet.PrimaryButton( + colorsLight = primaryButtonColorsBuilder.buildLight(), + colorsDark = primaryButtonColorsBuilder.buildDark(), + shape = + PaymentSheet.PrimaryButtonShape( + cornerRadiusDp = 42.0f, + borderStrokeWidthDp = null, + heightDp = 42.0f, + ), + typography = PaymentSheet.PrimaryButtonTypography(), + ) val appearanceBuilder = PaymentSheet.Appearance.Builder() appearanceBuilder.typography(PaymentSheet.Typography.Builder().build()) @@ -209,42 +215,47 @@ class PaymentSheetAppearanceTest { @Test fun testFullEmbeddedAppearance_FlatWithRadio() { - val json = """ - { - "embeddedPaymentElement": { - "row": { - "style": "flatWithRadio", - "additionalInsets": 42.0, - "flat": { - "separatorThickness": 42.0, - "topSeparatorEnabled": true, - "bottomSeparatorEnabled": true, - "separatorColor": "#123456", - "separatorInsets": { - "left": 42.0, - "right": 42.0 - }, - "radio": { - "selectedColor": "#123456", - "unselectedColor": "#123456" + val json = + """ + { + "embeddedPaymentElement": { + "row": { + "style": "flatWithRadio", + "additionalInsets": 42.0, + "flat": { + "separatorThickness": 42.0, + "topSeparatorEnabled": true, + "bottomSeparatorEnabled": true, + "separatorColor": "#123456", + "separatorInsets": { + "left": 42.0, + "right": 42.0 + }, + "radio": { + "selectedColor": "#123456", + "unselectedColor": "#123456" + } } } } } - } - """.trimIndent() + """.trimIndent() val map = jsonToMap(json) val appearanceFromJson = buildPaymentSheetAppearance(map, context) val testColor = Color.parseColor("#123456") - val flatRadioColorsBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithRadio.Colors.Builder() + val flatRadioColorsBuilder = + PaymentSheet.Appearance.Embedded.RowStyle.FlatWithRadio.Colors + .Builder() flatRadioColorsBuilder.separatorColor(testColor) flatRadioColorsBuilder.selectedColor(testColor) flatRadioColorsBuilder.unselectedColor(testColor) - val flatRadioBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithRadio.Builder() + val flatRadioBuilder = + PaymentSheet.Appearance.Embedded.RowStyle.FlatWithRadio + .Builder() flatRadioBuilder.separatorThicknessDp(42.0f) flatRadioBuilder.startSeparatorInsetDp(42.0f) flatRadioBuilder.endSeparatorInsetDp(42.0f) @@ -267,34 +278,39 @@ class PaymentSheetAppearanceTest { @Test fun testPartialEmbeddedAppearance_FlatWithRadio() { - val json = """ - { - "embeddedPaymentElement": { - "row": { - "style": "flatWithRadio", - "flat": { - "separatorThickness": 42.0, - "topSeparatorEnabled": false, - "separatorColor": "#123456", - "radio": { - "selectedColor": "#123456" + val json = + """ + { + "embeddedPaymentElement": { + "row": { + "style": "flatWithRadio", + "flat": { + "separatorThickness": 42.0, + "topSeparatorEnabled": false, + "separatorColor": "#123456", + "radio": { + "selectedColor": "#123456" + } } } } } - } - """.trimIndent() + """.trimIndent() val map = jsonToMap(json) val appearanceFromJson = buildPaymentSheetAppearance(map, context) val testColor = Color.parseColor("#123456") - val flatRadioColorsBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithRadio.Colors.Builder() + val flatRadioColorsBuilder = + PaymentSheet.Appearance.Embedded.RowStyle.FlatWithRadio.Colors + .Builder() flatRadioColorsBuilder.separatorColor(testColor) flatRadioColorsBuilder.selectedColor(testColor) - val flatRadioBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithRadio.Builder() + val flatRadioBuilder = + PaymentSheet.Appearance.Embedded.RowStyle.FlatWithRadio + .Builder() flatRadioBuilder.separatorThicknessDp(42.0f) flatRadioBuilder.topSeparatorEnabled(false) flatRadioBuilder.colorsLight(flatRadioColorsBuilder.buildLight()) @@ -313,41 +329,46 @@ class PaymentSheetAppearanceTest { @Test fun testFullEmbeddedAppearance_FlatWithCheckmark() { - val json = """ - { - "embeddedPaymentElement": { - "row": { - "style": "flatWithCheckmark", - "additionalInsets": 42.0, - "flat": { - "separatorThickness": 42.0, - "topSeparatorEnabled": true, - "bottomSeparatorEnabled": true, - "separatorColor": "#123456", - "separatorInsets": { - "left": 42.0, - "right": 42.0 - }, - "checkmark": { - "color": "#123456", - "inset": 42.0 + val json = + """ + { + "embeddedPaymentElement": { + "row": { + "style": "flatWithCheckmark", + "additionalInsets": 42.0, + "flat": { + "separatorThickness": 42.0, + "topSeparatorEnabled": true, + "bottomSeparatorEnabled": true, + "separatorColor": "#123456", + "separatorInsets": { + "left": 42.0, + "right": 42.0 + }, + "checkmark": { + "color": "#123456", + "inset": 42.0 + } } } } } - } - """.trimIndent() + """.trimIndent() val map = jsonToMap(json) val appearanceFromJson = buildPaymentSheetAppearance(map, context) val testColor = Color.parseColor("#123456") - val flatCheckmarkColorsBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark.Colors.Builder() + val flatCheckmarkColorsBuilder = + PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark.Colors + .Builder() flatCheckmarkColorsBuilder.separatorColor(testColor) flatCheckmarkColorsBuilder.checkmarkColor(testColor) - val flatCheckmarkBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark.Builder() + val flatCheckmarkBuilder = + PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark + .Builder() flatCheckmarkBuilder.separatorThicknessDp(42.0f) flatCheckmarkBuilder.startSeparatorInsetDp(42.0f) flatCheckmarkBuilder.endSeparatorInsetDp(42.0f) @@ -371,34 +392,39 @@ class PaymentSheetAppearanceTest { @Test fun testPartialEmbeddedAppearance_FlatWithCheckmark() { - val json = """ - { - "embeddedPaymentElement": { - "row": { - "style": "flatWithCheckmark", - "flat": { - "separatorThickness": 42.0, - "bottomSeparatorEnabled": false, - "separatorColor": "#123456", - "checkmark": { - "color": "#123456" + val json = + """ + { + "embeddedPaymentElement": { + "row": { + "style": "flatWithCheckmark", + "flat": { + "separatorThickness": 42.0, + "bottomSeparatorEnabled": false, + "separatorColor": "#123456", + "checkmark": { + "color": "#123456" + } } } } } - } - """.trimIndent() + """.trimIndent() val map = jsonToMap(json) val appearanceFromJson = buildPaymentSheetAppearance(map, context) val testColor = Color.parseColor("#123456") - val flatCheckmarkColorsBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark.Colors.Builder() + val flatCheckmarkColorsBuilder = + PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark.Colors + .Builder() flatCheckmarkColorsBuilder.separatorColor(testColor) flatCheckmarkColorsBuilder.checkmarkColor(testColor) - val flatCheckmarkBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark.Builder() + val flatCheckmarkBuilder = + PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark + .Builder() flatCheckmarkBuilder.separatorThicknessDp(42.0f) flatCheckmarkBuilder.bottomSeparatorEnabled(false) flatCheckmarkBuilder.colorsLight(flatCheckmarkColorsBuilder.buildLight()) @@ -417,40 +443,45 @@ class PaymentSheetAppearanceTest { @Test fun testFullEmbeddedAppearance_FlatWithDisclosure() { - val json = """ - { - "embeddedPaymentElement": { - "row": { - "style": "flatWithDisclosure", - "additionalInsets": 42.0, - "flat": { - "separatorThickness": 42.0, - "topSeparatorEnabled": true, - "bottomSeparatorEnabled": true, - "separatorColor": "#123456", - "separatorInsets": { - "left": 42.0, - "right": 42.0 - }, - "disclosure": { - "color": "#123456" + val json = + """ + { + "embeddedPaymentElement": { + "row": { + "style": "flatWithDisclosure", + "additionalInsets": 42.0, + "flat": { + "separatorThickness": 42.0, + "topSeparatorEnabled": true, + "bottomSeparatorEnabled": true, + "separatorColor": "#123456", + "separatorInsets": { + "left": 42.0, + "right": 42.0 + }, + "disclosure": { + "color": "#123456" + } } } } } - } - """.trimIndent() + """.trimIndent() val map = jsonToMap(json) val appearanceFromJson = buildPaymentSheetAppearance(map, context) val testColor = Color.parseColor("#123456") - val flatDisclosureColorsBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithDisclosure.Colors.Builder() + val flatDisclosureColorsBuilder = + PaymentSheet.Appearance.Embedded.RowStyle.FlatWithDisclosure.Colors + .Builder() flatDisclosureColorsBuilder.separatorColor(testColor) flatDisclosureColorsBuilder.disclosureColor(testColor) - val flatDisclosureBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithDisclosure.Builder() + val flatDisclosureBuilder = + PaymentSheet.Appearance.Embedded.RowStyle.FlatWithDisclosure + .Builder() flatDisclosureBuilder.separatorThicknessDp(42.0f) flatDisclosureBuilder.startSeparatorInsetDp(42.0f) flatDisclosureBuilder.endSeparatorInsetDp(42.0f) @@ -473,33 +504,38 @@ class PaymentSheetAppearanceTest { @Test fun testPartialEmbeddedAppearance_FlatWithDisclosure() { - val json = """ - { - "embeddedPaymentElement": { - "row": { - "style": "flatWithDisclosure", - "flat": { - "separatorThickness": 42.0, - "separatorColor": "#123456", - "disclosure": { - "color": "#123456" + val json = + """ + { + "embeddedPaymentElement": { + "row": { + "style": "flatWithDisclosure", + "flat": { + "separatorThickness": 42.0, + "separatorColor": "#123456", + "disclosure": { + "color": "#123456" + } } } } } - } - """.trimIndent() + """.trimIndent() val map = jsonToMap(json) val appearanceFromJson = buildPaymentSheetAppearance(map, context) val testColor = Color.parseColor("#123456") - val flatDisclosureColorsBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithDisclosure.Colors.Builder() + val flatDisclosureColorsBuilder = + PaymentSheet.Appearance.Embedded.RowStyle.FlatWithDisclosure.Colors + .Builder() flatDisclosureColorsBuilder.separatorColor(testColor) flatDisclosureColorsBuilder.disclosureColor(testColor) - val flatDisclosureBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithDisclosure.Builder() + val flatDisclosureBuilder = + PaymentSheet.Appearance.Embedded.RowStyle.FlatWithDisclosure + .Builder() flatDisclosureBuilder.separatorThicknessDp(42.0f) flatDisclosureBuilder.colorsLight(flatDisclosureColorsBuilder.buildLight()) flatDisclosureBuilder.colorsDark(flatDisclosureColorsBuilder.buildDark()) @@ -517,24 +553,27 @@ class PaymentSheetAppearanceTest { @Test fun testFullEmbeddedAppearance_FloatingButton() { - val json = """ - { - "embeddedPaymentElement": { - "row": { - "style": "floatingButton", - "additionalInsets": 42.0, - "floating": { - "spacing": 42.0 + val json = + """ + { + "embeddedPaymentElement": { + "row": { + "style": "floatingButton", + "additionalInsets": 42.0, + "floating": { + "spacing": 42.0 + } } } } - } - """.trimIndent() + """.trimIndent() val map = jsonToMap(json) val appearanceFromJson = buildPaymentSheetAppearance(map, context) - val floatingButtonBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FloatingButton.Builder() + val floatingButtonBuilder = + PaymentSheet.Appearance.Embedded.RowStyle.FloatingButton + .Builder() floatingButtonBuilder.additionalInsetsDp(42.0f) floatingButtonBuilder.spacingDp(42.0f) @@ -551,23 +590,26 @@ class PaymentSheetAppearanceTest { @Test fun testPartialEmbeddedAppearance_FloatingButton() { - val json = """ - { - "embeddedPaymentElement": { - "row": { - "style": "floatingButton", - "floating": { - "spacing": 42.0 + val json = + """ + { + "embeddedPaymentElement": { + "row": { + "style": "floatingButton", + "floating": { + "spacing": 42.0 + } } } } - } - """.trimIndent() + """.trimIndent() val map = jsonToMap(json) val appearanceFromJson = buildPaymentSheetAppearance(map, context) - val floatingButtonBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FloatingButton.Builder() + val floatingButtonBuilder = + PaymentSheet.Appearance.Embedded.RowStyle.FloatingButton + .Builder() floatingButtonBuilder.spacingDp(42.0f) val embeddedBuilder = PaymentSheet.Appearance.Embedded.Builder() diff --git a/android/src/androidTest/java/com/reactnativestripesdk/addresssheet/AddressSheetViewTest.kt b/android/src/androidTest/java/com/reactnativestripesdk/addresssheet/AddressSheetViewTest.kt index 041a64772f..4e4dd3ed1d 100644 --- a/android/src/androidTest/java/com/reactnativestripesdk/addresssheet/AddressSheetViewTest.kt +++ b/android/src/androidTest/java/com/reactnativestripesdk/addresssheet/AddressSheetViewTest.kt @@ -11,7 +11,6 @@ import com.stripe.android.paymentsheet.addresselement.AddressLauncher import org.junit.Assert import org.junit.Before import org.junit.Test -import kotlin.math.exp class AddressSheetViewTest { private val testCity = "testCity" @@ -137,7 +136,11 @@ class AddressSheetViewTest { } val received = AddressSheetView.buildAdditionalFieldsConfiguration(params) - val expected = AddressLauncher.AdditionalFieldsConfiguration(AddressLauncher.AdditionalFieldsConfiguration.FieldConfiguration.REQUIRED, label) + val expected = + AddressLauncher.AdditionalFieldsConfiguration( + AddressLauncher.AdditionalFieldsConfiguration.FieldConfiguration.REQUIRED, + label, + ) Assert.assertEquals(received, expected) } diff --git a/android/src/main/java/com/reactnativestripesdk/PaymentSheetAppearance.kt b/android/src/main/java/com/reactnativestripesdk/PaymentSheetAppearance.kt index edd22a0f58..38dbeaf926 100644 --- a/android/src/main/java/com/reactnativestripesdk/PaymentSheetAppearance.kt +++ b/android/src/main/java/com/reactnativestripesdk/PaymentSheetAppearance.kt @@ -8,8 +8,8 @@ import com.facebook.react.bridge.Arguments import com.facebook.react.bridge.ReadableMap import com.facebook.react.bridge.ReadableType import com.reactnativestripesdk.utils.PaymentSheetAppearanceException -import com.reactnativestripesdk.utils.getDoubleOrNull import com.reactnativestripesdk.utils.getBooleanOrNull +import com.reactnativestripesdk.utils.getDoubleOrNull import com.reactnativestripesdk.utils.getFloatOr import com.reactnativestripesdk.utils.getFloatOrNull import com.stripe.android.paymentelement.AppearanceAPIAdditionsPreview @@ -41,7 +41,7 @@ fun buildPaymentSheetAppearance( buildPrimaryButton( userParams?.getMap(PaymentSheetAppearanceKeys.PRIMARY_BUTTON), context, - ) + ), ) builder.embeddedAppearance(embeddedAppearance) builder.formInsetValues(buildFormInsets(insetParams)) @@ -71,10 +71,8 @@ private fun buildTypography( } @Throws(PaymentSheetAppearanceException::class) -private fun colorFromHex( - hexString: String?, -): Int? { - return hexString?.trim()?.replace("#", "")?.let { +private fun colorFromHex(hexString: String?): Int? = + hexString?.trim()?.replace("#", "")?.let { if (it.length == 6 || it.length == 8) { Color.parseColor("#$it") } else { @@ -83,11 +81,8 @@ private fun colorFromHex( ) } } -} -private fun buildColorsBuilder( - colorParams: ReadableMap?, -): PaymentSheet.Colors.Builder { +private fun buildColorsBuilder(colorParams: ReadableMap?): PaymentSheet.Colors.Builder { val builder = PaymentSheet.Colors.Builder() colorFromHex(colorParams?.getString(PaymentSheetAppearanceKeys.PRIMARY))?.let { @@ -242,12 +237,13 @@ private fun buildEmbeddedAppearance( flatParams?.getMap(PaymentSheetAppearanceKeys.SEPARATOR_INSETS) val flatRadioColorsBuilder = - PaymentSheet.Appearance.Embedded.RowStyle.FlatWithRadio.Colors.Builder() + PaymentSheet.Appearance.Embedded.RowStyle.FlatWithRadio.Colors + .Builder() dynamicColorFromParams( context, flatParams, - PaymentSheetAppearanceKeys.SEPARATOR_COLOR + PaymentSheetAppearanceKeys.SEPARATOR_COLOR, )?.let { flatRadioColorsBuilder.separatorColor(it) } @@ -255,7 +251,7 @@ private fun buildEmbeddedAppearance( dynamicColorFromParams( context, radioParams, - PaymentSheetAppearanceKeys.SELECTED_COLOR + PaymentSheetAppearanceKeys.SELECTED_COLOR, )?.let { flatRadioColorsBuilder.selectedColor(it) } @@ -263,12 +259,14 @@ private fun buildEmbeddedAppearance( dynamicColorFromParams( context, radioParams, - PaymentSheetAppearanceKeys.UNSELECTED_COLOR + PaymentSheetAppearanceKeys.UNSELECTED_COLOR, )?.let { flatRadioColorsBuilder.unselectedColor(it) } - val rowStyleBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithRadio.Builder() + val rowStyleBuilder = + PaymentSheet.Appearance.Embedded.RowStyle.FlatWithRadio + .Builder() flatParams.getFloatOrNull(PaymentSheetAppearanceKeys.SEPARATOR_THICKNESS)?.let { rowStyleBuilder.separatorThicknessDp(it) @@ -307,12 +305,13 @@ private fun buildEmbeddedAppearance( flatParams?.getMap(PaymentSheetAppearanceKeys.SEPARATOR_INSETS) val flatCheckmarkColorsBuilder = - PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark.Colors.Builder() + PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark.Colors + .Builder() dynamicColorFromParams( context, flatParams, - PaymentSheetAppearanceKeys.SEPARATOR_COLOR + PaymentSheetAppearanceKeys.SEPARATOR_COLOR, )?.let { flatCheckmarkColorsBuilder.separatorColor(it) } @@ -321,7 +320,9 @@ private fun buildEmbeddedAppearance( flatCheckmarkColorsBuilder.checkmarkColor(it) } - val rowStyleBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark.Builder() + val rowStyleBuilder = + PaymentSheet.Appearance.Embedded.RowStyle.FlatWithCheckmark + .Builder() flatParams.getFloatOrNull(PaymentSheetAppearanceKeys.SEPARATOR_THICKNESS)?.let { rowStyleBuilder.separatorThicknessDp(it) @@ -364,12 +365,13 @@ private fun buildEmbeddedAppearance( flatParams?.getMap(PaymentSheetAppearanceKeys.SEPARATOR_INSETS) val flatDisclosureColorsBuilder = - PaymentSheet.Appearance.Embedded.RowStyle.FlatWithDisclosure.Colors.Builder() + PaymentSheet.Appearance.Embedded.RowStyle.FlatWithDisclosure.Colors + .Builder() dynamicColorFromParams( context, flatParams, - PaymentSheetAppearanceKeys.SEPARATOR_COLOR + PaymentSheetAppearanceKeys.SEPARATOR_COLOR, )?.let { flatDisclosureColorsBuilder.separatorColor(it) } @@ -378,8 +380,9 @@ private fun buildEmbeddedAppearance( flatDisclosureColorsBuilder.disclosureColor(it) } - - val rowStyleBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FlatWithDisclosure.Builder() + val rowStyleBuilder = + PaymentSheet.Appearance.Embedded.RowStyle.FlatWithDisclosure + .Builder() flatParams.getFloatOrNull(PaymentSheetAppearanceKeys.SEPARATOR_THICKNESS)?.let { rowStyleBuilder.separatorThicknessDp(it) @@ -413,7 +416,9 @@ private fun buildEmbeddedAppearance( "floatingButton" -> { val floatingParams = rowParams.getMap(PaymentSheetAppearanceKeys.FLOATING) - val rowStyleBuilder = PaymentSheet.Appearance.Embedded.RowStyle.FloatingButton.Builder() + val rowStyleBuilder = + PaymentSheet.Appearance.Embedded.RowStyle.FloatingButton + .Builder() rowParams.getFloatOrNull(PaymentSheetAppearanceKeys.ADDITIONAL_INSETS)?.let { rowStyleBuilder.additionalInsetsDp(it) From 346a488dd8e89c46f37ad7a16204822435c4da37 Mon Sep 17 00:00:00 2001 From: Yuki Date: Mon, 10 Nov 2025 15:23:20 -0800 Subject: [PATCH 7/8] update with latest --- android/gradle.properties | 2 +- stripe-react-native.podspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/android/gradle.properties b/android/gradle.properties index ec72adad2c..e29ae9141d 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -3,4 +3,4 @@ StripeSdk_compileSdkVersion=30 StripeSdk_targetSdkVersion=28 StripeSdk_minSdkVersion=21 # Keep StripeSdk_stripeVersion in sync with https://github.com/stripe/stripe-identity-react-native/blob/main/android/gradle.properties -StripeSdk_stripeVersion=22.0.+ +StripeSdk_stripeVersion=22.1.+ diff --git a/stripe-react-native.podspec b/stripe-react-native.podspec index 707d7f456f..eb85973b88 100644 --- a/stripe-react-native.podspec +++ b/stripe-react-native.podspec @@ -2,7 +2,7 @@ require 'json' package = JSON.parse(File.read(File.join(__dir__, 'package.json'))) # Keep stripe_version in sync with https://github.com/stripe/stripe-identity-react-native/blob/main/stripe-identity-react-native.podspec -stripe_version = '~> 25.0.0' +stripe_version = '~> 25.0.1' fabric_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == '1' From b227482c33b3d60facea50971d80495976aba8ef Mon Sep 17 00:00:00 2001 From: Yuki Date: Tue, 11 Nov 2025 14:06:32 -0800 Subject: [PATCH 8/8] update example pod --- example/ios/Podfile.lock | 118 +++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 59 deletions(-) diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index fe3fa507fd..ae906aea0a 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1685,13 +1685,13 @@ PODS: - ReactCommon/turbomodule/core - Yoga - SocketRocket (0.7.1) - - Stripe (25.0.0): - - StripeApplePay (= 25.0.0) - - StripeCore (= 25.0.0) - - StripePayments (= 25.0.0) - - StripePaymentsUI (= 25.0.0) - - StripeUICore (= 25.0.0) - - stripe-react-native (0.55.1): + - Stripe (25.0.1): + - StripeApplePay (= 25.0.1) + - StripeCore (= 25.0.1) + - StripePayments (= 25.0.1) + - StripePaymentsUI (= 25.0.1) + - StripeUICore (= 25.0.1) + - stripe-react-native (0.56.0): - DoubleConversion - glog - hermes-engine @@ -1711,15 +1711,15 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - Stripe (~> 25.0.0) - - stripe-react-native/NewArch (= 0.55.1) - - StripeApplePay (~> 25.0.0) - - StripeFinancialConnections (~> 25.0.0) - - StripePayments (~> 25.0.0) - - StripePaymentSheet (~> 25.0.0) - - StripePaymentsUI (~> 25.0.0) + - Stripe (~> 25.0.1) + - stripe-react-native/NewArch (= 0.56.0) + - StripeApplePay (~> 25.0.1) + - StripeFinancialConnections (~> 25.0.1) + - StripePayments (~> 25.0.1) + - StripePaymentSheet (~> 25.0.1) + - StripePaymentsUI (~> 25.0.1) - Yoga - - stripe-react-native/NewArch (0.55.1): + - stripe-react-native/NewArch (0.56.0): - DoubleConversion - glog - hermes-engine @@ -1739,14 +1739,14 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - Stripe (~> 25.0.0) - - StripeApplePay (~> 25.0.0) - - StripeFinancialConnections (~> 25.0.0) - - StripePayments (~> 25.0.0) - - StripePaymentSheet (~> 25.0.0) - - StripePaymentsUI (~> 25.0.0) + - Stripe (~> 25.0.1) + - StripeApplePay (~> 25.0.1) + - StripeFinancialConnections (~> 25.0.1) + - StripePayments (~> 25.0.1) + - StripePaymentSheet (~> 25.0.1) + - StripePaymentsUI (~> 25.0.1) - Yoga - - stripe-react-native/Tests (0.55.1): + - stripe-react-native/Tests (0.56.0): - DoubleConversion - glog - hermes-engine @@ -1766,35 +1766,35 @@ PODS: - ReactCodegen - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - Stripe (~> 25.0.0) - - StripeApplePay (~> 25.0.0) - - StripeFinancialConnections (~> 25.0.0) - - StripePayments (~> 25.0.0) - - StripePaymentSheet (~> 25.0.0) - - StripePaymentsUI (~> 25.0.0) + - Stripe (~> 25.0.1) + - StripeApplePay (~> 25.0.1) + - StripeFinancialConnections (~> 25.0.1) + - StripePayments (~> 25.0.1) + - StripePaymentSheet (~> 25.0.1) + - StripePaymentsUI (~> 25.0.1) - Yoga - - StripeApplePay (25.0.0): - - StripeCore (= 25.0.0) - - StripeCore (25.0.0) - - StripeFinancialConnections (25.0.0): - - StripeCore (= 25.0.0) - - StripeUICore (= 25.0.0) - - StripePayments (25.0.0): - - StripeCore (= 25.0.0) - - StripePayments/Stripe3DS2 (= 25.0.0) - - StripePayments/Stripe3DS2 (25.0.0): - - StripeCore (= 25.0.0) - - StripePaymentSheet (25.0.0): - - StripeApplePay (= 25.0.0) - - StripeCore (= 25.0.0) - - StripePayments (= 25.0.0) - - StripePaymentsUI (= 25.0.0) - - StripePaymentsUI (25.0.0): - - StripeCore (= 25.0.0) - - StripePayments (= 25.0.0) - - StripeUICore (= 25.0.0) - - StripeUICore (25.0.0): - - StripeCore (= 25.0.0) + - StripeApplePay (25.0.1): + - StripeCore (= 25.0.1) + - StripeCore (25.0.1) + - StripeFinancialConnections (25.0.1): + - StripeCore (= 25.0.1) + - StripeUICore (= 25.0.1) + - StripePayments (25.0.1): + - StripeCore (= 25.0.1) + - StripePayments/Stripe3DS2 (= 25.0.1) + - StripePayments/Stripe3DS2 (25.0.1): + - StripeCore (= 25.0.1) + - StripePaymentSheet (25.0.1): + - StripeApplePay (= 25.0.1) + - StripeCore (= 25.0.1) + - StripePayments (= 25.0.1) + - StripePaymentsUI (= 25.0.1) + - StripePaymentsUI (25.0.1): + - StripeCore (= 25.0.1) + - StripePayments (= 25.0.1) + - StripeUICore (= 25.0.1) + - StripeUICore (25.0.1): + - StripeCore (= 25.0.1) - Yoga (0.0.0) DEPENDENCIES: @@ -2109,15 +2109,15 @@ SPEC CHECKSUMS: RNCPicker: cfb51a08c6e10357d9a65832e791825b0747b483 RNScreens: 0d4cb9afe052607ad0aa71f645a88bb7c7f2e64c SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 - Stripe: 319b0923b2d03e7f07805db481b6656b19e159db - stripe-react-native: 3b354280a2aa9e93f1c3b8049775537c01bff978 - StripeApplePay: 09bbe6a24d2cd4c37b2422fdd6e18f2be9f37e02 - StripeCore: a671e360dc0ede1275e98a8c5b6e0b694509c611 - StripeFinancialConnections: ca68c5d0fb5fbfc53c9eee572997080c3b7e6b7f - StripePayments: f1fbddb747c62dca90810e69fecfaca45f31b667 - StripePaymentSheet: 645a5787595c667c5ea6de8c47a809003e837a99 - StripePaymentsUI: 719d201ab61087c974ed44cbd0d43c30d9276688 - StripeUICore: a8f8f38daf0eddb8f6c43ac9d7f051290af9bf2a + Stripe: 4728e3e0dd8df134e4a420ab504e929a93a815f0 + stripe-react-native: e2dac3be3c2668207a7b7700663b852646a0e7d8 + StripeApplePay: 43997281ace138a1c75a8f2d7be11925ea28644c + StripeCore: 457c30e2fd3a7c4b274a5ad53d1ff03661eef2a0 + StripeFinancialConnections: 8c2e326f767fb014b53174b3a5f8592c0a45fa56 + StripePayments: 6955de4298a5265e66f02cffcc7954475ac7f6c8 + StripePaymentSheet: 3f93ce6ea84afde770d3c7e18a9b8f99aed63896 + StripePaymentsUI: 626726a01255a6458c35436f7f6431dacee82684 + StripeUICore: 30f8352fd7a5cf1541b7777a57b3ad1133bf6763 Yoga: afd04ff05ebe0121a00c468a8a3c8080221cb14c PODFILE CHECKSUM: a2ed964678852d4cc306ff4add3e4fa90be77ea6