diff --git a/example/lib/screens/card_payments/no_webhook_payment_screen.dart b/example/lib/screens/card_payments/no_webhook_payment_screen.dart index 23f0b9cd2..e6b8ae45f 100644 --- a/example/lib/screens/card_payments/no_webhook_payment_screen.dart +++ b/example/lib/screens/card_payments/no_webhook_payment_screen.dart @@ -39,6 +39,7 @@ class _NoWebhookPaymentScreenState extends State { padding: EdgeInsets.symmetric(horizontal: 16), children: [ CardField( + preferredNetworks: [CardBrand.Amex], controller: controller, ), SizedBox(height: 20), diff --git a/example/lib/screens/card_payments/webhook_payment_screen.dart b/example/lib/screens/card_payments/webhook_payment_screen.dart index 1c9c3e23e..89842025a 100644 --- a/example/lib/screens/card_payments/webhook_payment_screen.dart +++ b/example/lib/screens/card_payments/webhook_payment_screen.dart @@ -37,6 +37,7 @@ class _WebhookPaymentScreenState extends State { ), SizedBox(height: 20), CardField( + preferredNetworks: [CardBrand.Amex], enablePostalCode: true, countryCode: 'US', postalCodeHintText: 'Enter the us postal code', diff --git a/example/lib/screens/payment_sheet/payment_sheet_screen.dart b/example/lib/screens/payment_sheet/payment_sheet_screen.dart index b82e6ffc5..485d405e1 100644 --- a/example/lib/screens/payment_sheet/payment_sheet_screen.dart +++ b/example/lib/screens/payment_sheet/payment_sheet_screen.dart @@ -90,6 +90,7 @@ class _PaymentSheetScreenState extends State { // Main params paymentIntentClientSecret: data['paymentIntent'], merchantDisplayName: 'Flutter Stripe Store Demo', + preferredNetworks: [CardBrand.Amex], // Customer params customerId: data['customer'], customerEphemeralKeySecret: data['ephemeralKey'], diff --git a/packages/stripe/lib/src/widgets/card_field.dart b/packages/stripe/lib/src/widgets/card_field.dart index 82e9d7562..bae08eb60 100644 --- a/packages/stripe/lib/src/widgets/card_field.dart +++ b/packages/stripe/lib/src/widgets/card_field.dart @@ -30,6 +30,7 @@ class CardField extends StatefulWidget { this.cvcHintText, this.postalCodeHintText, this.controller, + this.preferredNetworks, this.androidPlatformViewRenderType = AndroidPlatformViewRenderType.expensiveAndroidView, }) : super(key: key); @@ -104,6 +105,10 @@ class CardField extends StatefulWidget { /// Default is `false`. final bool dangerouslyUpdateFullCardDetails; + /// The list of preferred networks that should be used to process payments made with a co-branded card. + /// This value will only be used if your user hasn't selected a network themselves. + final List? preferredNetworks; + /// Type of platformview used for rendering on Android. /// /// This is an advanced option and changing this should be tested on multiple android devices. @@ -185,6 +190,7 @@ class _CardFieldState extends State { child: _MethodChannelCardField( controller: controller, disabled: widget.disabled, + preferredNetworks: widget.preferredNetworks, height: platformCardHeight, androidPlatformViewRenderType: widget.androidPlatformViewRenderType, @@ -287,6 +293,7 @@ class _MethodChannelCardField extends StatefulWidget { double? height = kCardFieldDefaultHeight, BoxConstraints? constraints, required this.focusNode, + this.preferredNetworks, this.dangerouslyGetFullCardDetails = false, this.dangerouslyUpdateFullCardDetails = false, this.autofocus = false, @@ -311,6 +318,7 @@ class _MethodChannelCardField extends StatefulWidget { final bool dangerouslyGetFullCardDetails; final bool dangerouslyUpdateFullCardDetails; final AndroidPlatformViewRenderType androidPlatformViewRenderType; + final List? preferredNetworks; // This is used in the platform side to register the view. static const _viewType = 'flutter.stripe/card_field'; @@ -399,6 +407,8 @@ class _MethodChannelCardFieldState extends State<_MethodChannelCardField> 'placeholder': placeholder.toJson(), 'postalCodeEnabled': widget.enablePostalCode, 'countryCode': widget.countryCode, + 'preferredNetworks': + widget.preferredNetworks?.map((e) => e.brandValue).toList(), 'dangerouslyGetFullCardDetails': widget.dangerouslyGetFullCardDetails, if (widget.dangerouslyUpdateFullCardDetails && controller.initalDetails != null) diff --git a/packages/stripe/lib/src/widgets/card_form_field.dart b/packages/stripe/lib/src/widgets/card_form_field.dart index b3554fd69..9362ff58b 100644 --- a/packages/stripe/lib/src/widgets/card_form_field.dart +++ b/packages/stripe/lib/src/widgets/card_form_field.dart @@ -1,5 +1,5 @@ -import 'dart:developer'; import 'dart:developer' as dev; +import 'dart:developer'; import 'dart:io'; import 'package:flutter/foundation.dart'; @@ -30,6 +30,7 @@ class CardFormField extends StatefulWidget { this.dangerouslyUpdateFullCardDetails = false, this.disabled = false, this.controller, + this.preferredNetworks, }) : super(key: key); /// Callback that will be executed when a specific field gets focus. @@ -86,6 +87,10 @@ class CardFormField extends StatefulWidget { /// Default is `false`. final bool disabled; + /// The list of preferred networks that should be used to process payments made with a co-branded card. + /// This value will only be used if your user hasn't selected a network themselves. + final List? preferredNetworks; + @override // ignore: library_private_types_in_public_api _CardFormFieldState createState() => _CardFormFieldState(); @@ -196,6 +201,7 @@ class _CardFormFieldState extends State { disabled: widget.disabled, onFocus: widget.onFocus, countryCode: widget.countryCode, + preferredNetworks: widget.preferredNetworks, ); } @@ -220,6 +226,7 @@ class _MethodChannelCardFormField extends StatefulWidget { this.dangerouslyUpdateFullCardDetails = false, this.autofocus = false, this.disabled = false, + this.preferredNetworks, this.countryCode, }) : assert(constraints == null || constraints.debugAssertIsValid()), constraints = (width != null || height != null) @@ -240,6 +247,7 @@ class _MethodChannelCardFormField extends StatefulWidget { final bool dangerouslyGetFullCardDetails; final bool dangerouslyUpdateFullCardDetails; final String? countryCode; + final List? preferredNetworks; // This is used in the platform side to register the view. static const _viewType = 'flutter.stripe/card_form_field'; @@ -308,6 +316,8 @@ class _MethodChannelCardFormFieldState controller._initalDetails != null) 'cardDetails': controller._initalDetails?.toJson(), 'autofocus': widget.autofocus, + 'preferredNetworks': + widget.preferredNetworks?.map((e) => e.brandValue).toList(), 'disabled': widget.disabled, 'defaultValues': { 'countryCode': widget.countryCode, diff --git a/packages/stripe_android/android/build.gradle b/packages/stripe_android/android/build.gradle index 9d9cd4456..0e33bbe51 100644 --- a/packages/stripe_android/android/build.gradle +++ b/packages/stripe_android/android/build.gradle @@ -3,7 +3,7 @@ version '1.0-SNAPSHOT' buildscript { ext.kotlin_version = '1.8.0' - ext.stripe_version = '20.34.+' + ext.stripe_version = '20.37.+' repositories { google() diff --git a/packages/stripe_android/android/src/main/kotlin/com/facebook/react/bridge/ReadableArray.java b/packages/stripe_android/android/src/main/kotlin/com/facebook/react/bridge/ReadableArray.java index 99ebb7f15..4d97f3336 100644 --- a/packages/stripe_android/android/src/main/kotlin/com/facebook/react/bridge/ReadableArray.java +++ b/packages/stripe_android/android/src/main/kotlin/com/facebook/react/bridge/ReadableArray.java @@ -7,6 +7,7 @@ import java.lang.reflect.Array; import java.util.ArrayList; +import java.util.List; /** * Created by FFuF, Jonas Bark on 2019-10-02. @@ -20,6 +21,12 @@ public ReadableArray(JSONArray array) { this.array = array; } + public ReadableArray(@NotNull List array) { + this.array = new JSONArray(); + array.addAll(array); + } + + public String getString(int index) { try { return array.getString(index); diff --git a/packages/stripe_android/android/src/main/kotlin/com/flutter/stripe/StripeSdkCardFormPlatformView.kt b/packages/stripe_android/android/src/main/kotlin/com/flutter/stripe/StripeSdkCardFormPlatformView.kt index c7a16a116..ad2773378 100644 --- a/packages/stripe_android/android/src/main/kotlin/com/flutter/stripe/StripeSdkCardFormPlatformView.kt +++ b/packages/stripe_android/android/src/main/kotlin/com/flutter/stripe/StripeSdkCardFormPlatformView.kt @@ -1,11 +1,13 @@ package com.flutter.stripe +import android.annotation.SuppressLint import android.content.Context import android.text.InputType import android.util.Log import android.view.View import android.view.inputmethod.InputMethodManager import androidx.annotation.NonNull +import com.facebook.react.bridge.ReadableArray import com.facebook.react.bridge.ReadableMap import com.facebook.react.uimanager.ThemedReactContext import com.reactnativestripesdk.* @@ -18,6 +20,7 @@ import io.flutter.plugin.common.MethodChannel import io.flutter.plugin.platform.PlatformView +@SuppressLint("RestrictedApi") class StripeSdkCardFormPlatformView( private val context: Context, private val channel: MethodChannel, @@ -51,6 +54,9 @@ class StripeSdkCardFormPlatformView( if (creationParams?.containsKey("disabled") == true) { cardFormViewManager.setDisabled(cardView, creationParams["disabled"] as Boolean) } + if (creationParams?.containsKey("preferredNetworks") == true) { + cardFormViewManager.setPreferredNetworks(cardView, ReadableArray(creationParams["preferredNetworks"] as List)) + } if (creationParams?.containsKey("cardDetails") == true) { val value = ReadableMap(creationParams["cardDetails"] as Map) diff --git a/packages/stripe_android/android/src/main/kotlin/com/flutter/stripe/StripeSdkCardPlatformView.kt b/packages/stripe_android/android/src/main/kotlin/com/flutter/stripe/StripeSdkCardPlatformView.kt index ba4e9adad..3d8d47797 100644 --- a/packages/stripe_android/android/src/main/kotlin/com/flutter/stripe/StripeSdkCardPlatformView.kt +++ b/packages/stripe_android/android/src/main/kotlin/com/flutter/stripe/StripeSdkCardPlatformView.kt @@ -4,6 +4,7 @@ import android.content.Context import android.view.View import android.view.inputmethod.InputMethodManager import androidx.annotation.NonNull +import com.facebook.react.bridge.ReadableArray import com.facebook.react.bridge.ReadableMap import com.facebook.react.uimanager.ThemedReactContext import com.reactnativestripesdk.* @@ -46,6 +47,9 @@ class StripeSdkCardPlatformView( if (creationParams?.containsKey("disabled") == true) { stripeSdkCardViewManager.setDisabled(cardView, creationParams["disabled"] as Boolean) } + if (creationParams?.containsKey("preferredNetworks") == true) { + stripeSdkCardViewManager.setPreferredNetworks(cardView, ReadableArray(creationParams["preferredNetworks"] as List)) + } if (creationParams?.containsKey("dangerouslyGetFullCardDetails") == true) { stripeSdkCardViewManager.setDangerouslyGetFullCardDetails(cardView, creationParams["dangerouslyGetFullCardDetails"] as Boolean) } diff --git a/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/CardFieldView.kt b/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/CardFieldView.kt index 4475bd170..fb782ee65 100644 --- a/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/CardFieldView.kt +++ b/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/CardFieldView.kt @@ -1,5 +1,6 @@ package com.reactnativestripesdk +import android.annotation.SuppressLint import android.content.res.ColorStateList import android.graphics.Color import android.os.Build @@ -167,10 +168,11 @@ class CardFieldView(context: ThemedReactContext) : FrameLayout(context) { private fun setCardBrandTint(color: Int) { try { - cardInputWidgetBinding.cardBrandView::class.java.getDeclaredField("tintColorInt").let { internalTintColor -> - internalTintColor.isAccessible = true - internalTintColor.set(cardInputWidgetBinding.cardBrandView, color) - } + cardInputWidgetBinding.cardBrandView::class.java + .getDeclaredMethod("setTintColorInt\$payments_core_release", Int::class.java) + .let { + it(cardInputWidgetBinding.cardBrandView, color) + } } catch (e: Exception) { Log.e( "StripeReactNative", @@ -205,7 +207,7 @@ class CardFieldView(context: ThemedReactContext) : FrameLayout(context) { fun setPostalCodeEnabled(isEnabled: Boolean) { mCardWidget.postalCodeEnabled = isEnabled - if (isEnabled === false) { + if (isEnabled == false) { mCardWidget.postalCodeRequired = false } } @@ -214,10 +216,15 @@ class CardFieldView(context: ThemedReactContext) : FrameLayout(context) { mCardWidget.isEnabled = !isDisabled } + fun setPreferredNetworks(preferredNetworks: ArrayList?) { + mCardWidget.setPreferredNetworks(mapToPreferredNetworks(preferredNetworks)) + } + /** * We can reliable assume that setPostalCodeEnabled is called before * setCountryCode because of the order of the props in CardField.tsx */ + @SuppressLint("RestrictedApi") fun setCountryCode(countryString: String?) { if (mCardWidget.postalCodeEnabled) { val countryCode = CountryCode.create(value = countryString ?: LocaleListCompat.getAdjustedDefault()[0]?.country ?: "US") @@ -355,6 +362,7 @@ class CardFieldView(context: ThemedReactContext) : FrameLayout(context) { ) } + @SuppressLint("RestrictedApi") private fun createPostalCodeInputFilter(countryCode: CountryCode): InputFilter { return InputFilter { charSequence, start, end, _, _, _ -> for (i in start until end) { diff --git a/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/CardFieldViewManager.kt b/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/CardFieldViewManager.kt index dcc2e911a..6f870f52e 100644 --- a/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/CardFieldViewManager.kt +++ b/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/CardFieldViewManager.kt @@ -64,6 +64,12 @@ class CardFieldViewManager : SimpleViewManager() { view.setDisabled(isDisabled) } + @ReactProp(name = "preferredNetworks") + fun setPreferredNetworks(view: CardFieldView, preferredNetworks: ReadableArray?) { + val networks = preferredNetworks?.toArrayList()?.filterIsInstance()?.let { ArrayList(it) } + view.setPreferredNetworks(networks) + } + override fun createViewInstance(reactContext: ThemedReactContext): CardFieldView { val stripeSdkModule: StripeSdkModule? = reactContext.getNativeModule(StripeSdkModule::class.java) val view = CardFieldView(reactContext) diff --git a/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/CardFormView.kt b/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/CardFormView.kt index beed8ed30..12807c472 100644 --- a/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/CardFormView.kt +++ b/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/CardFormView.kt @@ -1,5 +1,6 @@ package com.reactnativestripesdk +import android.annotation.SuppressLint import android.content.res.ColorStateList import android.graphics.Color import android.os.Build @@ -64,6 +65,11 @@ class CardFormView(context: ThemedReactContext) : FrameLayout(context) { cardForm.isEnabled = !isDisabled } + fun setPreferredNetworks(preferredNetworks: ArrayList?) { + cardForm.setPreferredNetworks(mapToPreferredNetworks(preferredNetworks)) + } + + @SuppressLint("RestrictedApi") private fun setCountry(countryString: String?) { if (countryString != null) { cardFormViewBinding.countryLayout.setSelectedCountryCode(CountryCode(countryString)) @@ -124,6 +130,7 @@ class CardFormView(context: ThemedReactContext) : FrameLayout(context) { CardFocusEvent(id, currentFocusedField)) } + @SuppressLint("RestrictedApi") fun setCardStyle(value: ReadableMap) { val backgroundColor = getValOr(value, "backgroundColor", null) val textColor = getValOr(value, "textColor", null) @@ -289,6 +296,7 @@ class CardFormView(context: ThemedReactContext) : FrameLayout(context) { ) } + @SuppressLint("RestrictedApi") private fun createPostalCodeInputFilter(): InputFilter { return InputFilter { charSequence, start, end, _, _, _ -> if (cardFormViewBinding.countryLayout.getSelectedCountryCode() == CountryCode.US) { diff --git a/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/CardFormViewManager.kt b/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/CardFormViewManager.kt index 45000acc9..24d6f7bba 100644 --- a/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/CardFormViewManager.kt +++ b/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/CardFormViewManager.kt @@ -61,6 +61,12 @@ class CardFormViewManager : SimpleViewManager() { view.setDisabled(isDisabled) } + @ReactProp(name = "preferredNetworks") + fun setPreferredNetworks(view: CardFormView, preferredNetworks: ReadableArray?) { + val networks = preferredNetworks?.toArrayList()?.filterIsInstance()?.let { ArrayList(it) } + view.setPreferredNetworks(networks) + } + override fun createViewInstance(reactContext: ThemedReactContext): CardFormView { val stripeSdkModule: StripeSdkModule? = reactContext.getNativeModule(StripeSdkModule::class.java) val view = CardFormView(reactContext) diff --git a/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/GooglePayButtonView.kt b/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/GooglePayButtonView.kt index 20f7bbc0e..fcdfe0cd0 100644 --- a/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/GooglePayButtonView.kt +++ b/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/GooglePayButtonView.kt @@ -1,5 +1,6 @@ package com.reactnativestripesdk +import android.annotation.SuppressLint import android.util.Log import android.view.View import android.widget.FrameLayout @@ -41,6 +42,7 @@ class GooglePayButtonView(private val context: ThemedReactContext) : FrameLayout return googlePayButton } + @SuppressLint("RestrictedApi") private fun buildButtonOptions(): ButtonOptions { val allowedPaymentMethods = JSONArray().put( GooglePayJsonFactory(context).createCardPaymentMethod( diff --git a/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/PaymentSheetFragment.kt b/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/PaymentSheetFragment.kt index b6da5681e..75fabe128 100644 --- a/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/PaymentSheetFragment.kt +++ b/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/PaymentSheetFragment.kt @@ -194,7 +194,8 @@ class PaymentSheetFragment( appearance = appearance, shippingDetails = shippingDetails, primaryButtonLabel = primaryButtonLabel, - billingDetailsCollectionConfiguration = billingDetailsConfig + billingDetailsCollectionConfiguration = billingDetailsConfig, + preferredNetworks = mapToPreferredNetworks(arguments?.getIntegerArrayList("preferredNetworks")) ) if (arguments?.getBoolean("customFlow") == true) { @@ -342,6 +343,17 @@ class PaymentSheetFragment( companion object { internal const val TAG = "payment_sheet_launch_fragment" + private val mapIntToButtonType = mapOf( + 1 to PaymentSheet.GooglePayConfiguration.ButtonType.Buy, + 6 to PaymentSheet.GooglePayConfiguration.ButtonType.Book, + 5 to PaymentSheet.GooglePayConfiguration.ButtonType.Checkout, + 4 to PaymentSheet.GooglePayConfiguration.ButtonType.Donate, + 11 to PaymentSheet.GooglePayConfiguration.ButtonType.Order, + 1000 to PaymentSheet.GooglePayConfiguration.ButtonType.Pay, + 7 to PaymentSheet.GooglePayConfiguration.ButtonType.Subscribe, + 1001 to PaymentSheet.GooglePayConfiguration.ButtonType.Plain, + ) + internal fun createMissingInitError(): WritableMap { return createError(PaymentSheetErrorType.Failed.toString(), "No payment sheet has been initialized yet. You must call `initPaymentSheet` before `presentPaymentSheet`.") } @@ -356,13 +368,16 @@ class PaymentSheetFragment( val testEnv = params.getBoolean("testEnv") val amount = params.getString("amount")?.toLongOrNull() val label = params.getString("label") + val buttonType = mapIntToButtonType.get(params.getInt("buttonType")) ?: PaymentSheet.GooglePayConfiguration.ButtonType.Pay + return PaymentSheet.GooglePayConfiguration( environment = if (testEnv) PaymentSheet.GooglePayConfiguration.Environment.Test else PaymentSheet.GooglePayConfiguration.Environment.Production, countryCode = countryCode, currencyCode = currencyCode, amount = amount, - label = label + label = label, + buttonType = buttonType ) } diff --git a/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/customersheet/CustomerSheetFragment.kt b/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/customersheet/CustomerSheetFragment.kt index f70fb99e7..78ea3402f 100644 --- a/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/customersheet/CustomerSheetFragment.kt +++ b/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/customersheet/CustomerSheetFragment.kt @@ -84,11 +84,11 @@ class CustomerSheetFragment : Fragment() { return } - val configuration = CustomerSheet.Configuration.builder() + val configuration = CustomerSheet.Configuration.builder(merchantDisplayName ?: "") .appearance(appearance) .googlePayEnabled(googlePayEnabled) - .merchantDisplayName(merchantDisplayName) .headerTextForSelectionScreen(headerTextForSelectionScreen) + .preferredNetworks(mapToPreferredNetworks(arguments?.getIntegerArrayList("preferredNetworks"))) billingDetailsBundle?.let { configuration.defaultBillingDetails(createDefaultBillingDetails(billingDetailsBundle)) diff --git a/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/utils/Mappers.kt b/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/utils/Mappers.kt index f06fb4038..6b91a18ca 100644 --- a/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/utils/Mappers.kt +++ b/packages/stripe_android/android/src/main/kotlin/com/reactnativestripesdk/utils/Mappers.kt @@ -1,5 +1,6 @@ package com.reactnativestripesdk.utils +import android.annotation.SuppressLint import android.os.Bundle import android.util.Log import com.facebook.react.bridge.* @@ -447,6 +448,7 @@ internal fun mapFromPaymentIntentResult(paymentIntent: PaymentIntent): WritableM return map } +@SuppressLint("RestrictedApi") internal fun mapFromMicrodepositType(type: MicrodepositType): String { return when (type) { MicrodepositType.AMOUNTS -> "amounts" @@ -455,6 +457,7 @@ internal fun mapFromMicrodepositType(type: MicrodepositType): String { } } +@SuppressLint("RestrictedApi") internal fun mapNextAction(type: NextActionType?, data: NextActionData?): WritableNativeMap? { val nextActionMap = WritableNativeMap() when (type) { @@ -909,7 +912,7 @@ internal fun mapFromShippingContact(googlePayResult: GooglePayResult): WritableM googlePayResult.shippingInformation?.phone?.let { map.putString("phoneNumber", it) } ?: run { - map.putString("phoneNumber", googlePayResult?.phoneNumber) + map.putString("phoneNumber", googlePayResult.phoneNumber) } val postalAddress = WritableNativeMap() postalAddress.putString("city", googlePayResult.shippingInformation?.address?.city) @@ -926,3 +929,25 @@ internal fun mapFromShippingContact(googlePayResult: GooglePayResult): WritableM map.putMap("postalAddress", postalAddress) return map } + +internal fun mapToPreferredNetworks(networksAsInts: ArrayList?): List { + if (networksAsInts == null) { + return emptyList() + } + + val intToCardBrand = mapOf( + 0 to CardBrand.JCB, + 1 to CardBrand.AmericanExpress, + 2 to CardBrand.CartesBancaires, + 3 to CardBrand.DinersClub, + 4 to CardBrand.Discover, + 5 to CardBrand.MasterCard, + 6 to CardBrand.UnionPay, + 7 to CardBrand.Visa, + 8 to CardBrand.Unknown, + ) + + return networksAsInts.mapNotNull { + intToCardBrand[it] + } +} diff --git a/packages/stripe_ios/ios/Classes/CardFieldFactory.swift b/packages/stripe_ios/ios/Classes/CardFieldFactory.swift index c0864c950..e85f0c682 100644 --- a/packages/stripe_ios/ios/Classes/CardFieldFactory.swift +++ b/packages/stripe_ios/ios/Classes/CardFieldFactory.swift @@ -137,6 +137,10 @@ class CardFieldPlatformView: NSObject, FlutterPlatformView, STPPaymentCardTextFi cardField.disabled = disabled } + if let preferredNetworks = arguments["preferredNetworks"] as? Array{ + cardField.preferredNetworks = preferredNetworks + } + if let cardDetails = arguments["cardDetails"] as? NSDictionary { cardField.dangerouslyUpdateCardDetails(params: cardDetails) } diff --git a/packages/stripe_ios/ios/Classes/CardFormFactory.swift b/packages/stripe_ios/ios/Classes/CardFormFactory.swift index 9cc50b829..d8f430104 100644 --- a/packages/stripe_ios/ios/Classes/CardFormFactory.swift +++ b/packages/stripe_ios/ios/Classes/CardFormFactory.swift @@ -104,7 +104,10 @@ class CardFormPlatformView : NSObject, FlutterPlatformView { if let dangerouslyGetFullCardDetails = arguments["dangerouslyGetFullCardDetails"] as? Bool{ cardForm.dangerouslyGetFullCardDetails = dangerouslyGetFullCardDetails } - + + if let preferredNetworks = arguments["preferredNetworks"] as? Array{ + cardForm.preferredNetworks = preferredNetworks + } if let disabled = arguments["disabled"] as? Bool{ cardForm.disabled = disabled } diff --git a/packages/stripe_ios/ios/Classes/Stripe Sdk/CardFieldView.swift b/packages/stripe_ios/ios/Classes/Stripe Sdk/CardFieldView.swift index 742c754e5..ebcb0677e 100644 --- a/packages/stripe_ios/ios/Classes/Stripe Sdk/CardFieldView.swift +++ b/packages/stripe_ios/ios/Classes/Stripe Sdk/CardFieldView.swift @@ -30,6 +30,14 @@ class CardFieldView: UIView, STPPaymentCardTextFieldDelegate { } } + @objc var preferredNetworks: Array? { + didSet { + if let preferredNetworks = preferredNetworks { + cardField.preferredNetworks = preferredNetworks.map(Mappers.intToCardBrand).compactMap { $0 } + } + } + } + @objc var placeholders: NSDictionary = NSDictionary() { didSet { if let numberPlaceholder = placeholders["number"] as? String { diff --git a/packages/stripe_ios/ios/Classes/Stripe Sdk/CardFormView.swift b/packages/stripe_ios/ios/Classes/Stripe Sdk/CardFormView.swift index 5d68322fb..49cff21ea 100644 --- a/packages/stripe_ios/ios/Classes/Stripe Sdk/CardFormView.swift +++ b/packages/stripe_ios/ios/Classes/Stripe Sdk/CardFormView.swift @@ -11,6 +11,13 @@ class CardFormView: UIView, STPCardFormViewDelegate { @objc var onFormComplete: RCTDirectEventBlock? @objc var autofocus: Bool = false @objc var disabled: Bool = false + @objc var preferredNetworks: Array? { + didSet { + if let preferredNetworks = preferredNetworks { + cardForm?.preferredNetworks = preferredNetworks.map(Mappers.intToCardBrand).compactMap { $0 } + } + } + } override func didSetProps(_ changedProps: [String]!) { if let cardForm = self.cardForm { diff --git a/packages/stripe_ios/ios/Classes/Stripe Sdk/CustomerSheet/CustomerSheetUtils.swift b/packages/stripe_ios/ios/Classes/Stripe Sdk/CustomerSheet/CustomerSheetUtils.swift index 2e72d2d3b..d764cd9d0 100644 --- a/packages/stripe_ios/ios/Classes/Stripe Sdk/CustomerSheet/CustomerSheetUtils.swift +++ b/packages/stripe_ios/ios/Classes/Stripe Sdk/CustomerSheet/CustomerSheetUtils.swift @@ -18,7 +18,8 @@ class CustomerSheetUtils { applePayEnabled: Bool?, merchantDisplayName: String?, billingDetailsCollectionConfiguration: NSDictionary?, - defaultBillingDetails: NSDictionary? + defaultBillingDetails: NSDictionary?, + preferredNetworks: Array? ) -> CustomerSheet.Configuration { var config = CustomerSheet.Configuration() config.appearance = appearance @@ -30,6 +31,9 @@ class CustomerSheetUtils { if let merchantDisplayName = merchantDisplayName { config.merchantDisplayName = merchantDisplayName } + if let preferredNetworks = preferredNetworks { + config.preferredNetworks = preferredNetworks.map(Mappers.intToCardBrand).compactMap { $0 } + } if let billingConfigParams = billingDetailsCollectionConfiguration { config.billingDetailsCollectionConfiguration.name = StripeSdk.mapToCollectionMode(str: billingConfigParams["name"] as? String) config.billingDetailsCollectionConfiguration.phone = StripeSdk.mapToCollectionMode(str: billingConfigParams["phone"] as? String) diff --git a/packages/stripe_ios/ios/Classes/Stripe Sdk/Mappers.swift b/packages/stripe_ios/ios/Classes/Stripe Sdk/Mappers.swift index 0f6218419..1909f776c 100644 --- a/packages/stripe_ios/ios/Classes/Stripe Sdk/Mappers.swift +++ b/packages/stripe_ios/ios/Classes/Stripe Sdk/Mappers.swift @@ -1025,4 +1025,29 @@ class Mappers { default: return STPPaymentMethodUSBankAccountType.checking } } + + class func intToCardBrand(int: Int) -> STPCardBrand? { + switch int { + case 0: + return STPCardBrand.JCB + case 1: + return STPCardBrand.amex + case 2: + return STPCardBrand.cartesBancaires + case 3: + return STPCardBrand.dinersClub + case 4: + return STPCardBrand.discover + case 5: + return STPCardBrand.mastercard + case 6: + return STPCardBrand.unionPay + case 7: + return STPCardBrand.visa + case 8: + return STPCardBrand.unknown + default: + return nil + } + } } diff --git a/packages/stripe_ios/ios/Classes/Stripe Sdk/StripeSdk+CustomerSheet.swift b/packages/stripe_ios/ios/Classes/Stripe Sdk/StripeSdk+CustomerSheet.swift index 2afc2d1ff..a616c9801 100644 --- a/packages/stripe_ios/ios/Classes/Stripe Sdk/StripeSdk+CustomerSheet.swift +++ b/packages/stripe_ios/ios/Classes/Stripe Sdk/StripeSdk+CustomerSheet.swift @@ -22,7 +22,9 @@ extension StripeSdk { applePayEnabled: params["applePayEnabled"] as? Bool, merchantDisplayName: params["merchantDisplayName"] as? String, billingDetailsCollectionConfiguration: params["billingDetailsCollectionConfiguration"] as? NSDictionary, - defaultBillingDetails: params["defaultBillingDetails"] as? NSDictionary) + defaultBillingDetails: params["defaultBillingDetails"] as? NSDictionary, + preferredNetworks: params["preferredNetworks"] as? Array + ) } catch { resolve( Errors.createError(ErrorType.Failed, error.localizedDescription) diff --git a/packages/stripe_ios/ios/Classes/Stripe Sdk/StripeSdk+PaymentSheet.swift b/packages/stripe_ios/ios/Classes/Stripe Sdk/StripeSdk+PaymentSheet.swift index b7dd3b1ff..c39247aef 100644 --- a/packages/stripe_ios/ios/Classes/Stripe Sdk/StripeSdk+PaymentSheet.swift +++ b/packages/stripe_ios/ios/Classes/Stripe Sdk/StripeSdk+PaymentSheet.swift @@ -99,6 +99,10 @@ extension StripeSdk { } } + if let preferredNetworksAsInts = params["preferredNetworks"] as? Array { + configuration.preferredNetworks = preferredNetworksAsInts.map(Mappers.intToCardBrand).compactMap { $0 } + } + return (nil, configuration) } diff --git a/packages/stripe_ios/ios/stripe_ios.podspec b/packages/stripe_ios/ios/stripe_ios.podspec index 46a5e7c83..9877ebd44 100644 --- a/packages/stripe_ios/ios/stripe_ios.podspec +++ b/packages/stripe_ios/ios/stripe_ios.podspec @@ -2,7 +2,7 @@ # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html. # Run `pod lib lint stripe_ios.podspec' to validate before publishing. # -stripe_version = '~> 23.18.0' +stripe_version = '~> 23.22.0' Pod::Spec.new do |s| s.name = 'stripe_ios' s.version = '0.0.1' diff --git a/packages/stripe_platform_interface/lib/src/models/card_brand.dart b/packages/stripe_platform_interface/lib/src/models/card_brand.dart new file mode 100644 index 000000000..84c970c75 --- /dev/null +++ b/packages/stripe_platform_interface/lib/src/models/card_brand.dart @@ -0,0 +1,36 @@ +// ignore_for_file: constant_identifier_names + +/// The card brand. +/// This is used to declare the preferred network in the UI +enum CardBrand { + /// JCB cards + JCB(0), + + /// American Express cards + Amex(1), + + /// Cartes Bancaires + CartesBancaires(2), + + /// Diners Club cards + DinersClub(3), + + /// Discover cards + Discover(4), + + /// Mastercard cards + Mastercard(5), + + /// UnionPay cards + UnionPay(6), + + /// Visa cards + Visa(7), + + /// Unknown or not supported + Unknown(8); + + const CardBrand(this.brandValue); + + final int brandValue; +} diff --git a/packages/stripe_platform_interface/lib/src/models/customer_sheet.dart b/packages/stripe_platform_interface/lib/src/models/customer_sheet.dart index e11cad2c5..c5869c9d4 100644 --- a/packages/stripe_platform_interface/lib/src/models/customer_sheet.dart +++ b/packages/stripe_platform_interface/lib/src/models/customer_sheet.dart @@ -53,6 +53,10 @@ class CustomerSheetInitParams with _$CustomerSheetInitParams { /// Whether to show Google Pay as an option. Defaults to `false`. @Default(true) bool googlePayEnabled, + + /// The list of preferred networks that should be used to process payments made with a co-branded card. + /// This value will only be used if your user hasn't selected a network themselves. + @JsonKey(toJson: _cardBrandListToJson) List? preferredNetworks, }) = _CustomerSheetInitParams; factory CustomerSheetInitParams.fromJson(Map json) => @@ -119,3 +123,10 @@ enum CustomerSheetPresentationStyle { */ customerAdapter?: CustomerAdapter; */ + +List _cardBrandListToJson(List? list) { + if (list == null) { + return []; + } + return list.map((e) => e.brandValue).toList(); +} diff --git a/packages/stripe_platform_interface/lib/src/models/customer_sheet.freezed.dart b/packages/stripe_platform_interface/lib/src/models/customer_sheet.freezed.dart index 7b04b5299..10cd88281 100644 --- a/packages/stripe_platform_interface/lib/src/models/customer_sheet.freezed.dart +++ b/packages/stripe_platform_interface/lib/src/models/customer_sheet.freezed.dart @@ -68,6 +68,11 @@ mixin _$CustomerSheetInitParams { /// Whether to show Google Pay as an option. Defaults to `false`. bool get googlePayEnabled => throw _privateConstructorUsedError; + /// The list of preferred networks that should be used to process payments made with a co-branded card. + /// This value will only be used if your user hasn't selected a network themselves. + @JsonKey(toJson: _cardBrandListToJson) + List? get preferredNetworks => throw _privateConstructorUsedError; + Map toJson() => throw _privateConstructorUsedError; @JsonKey(ignore: true) $CustomerSheetInitParamsCopyWith get copyWith => @@ -94,7 +99,9 @@ abstract class $CustomerSheetInitParamsCopyWith<$Res> { String? returnURL, String? removeSavedPaymentMethodMessage, bool applePayEnabled, - bool googlePayEnabled}); + bool googlePayEnabled, + @JsonKey(toJson: _cardBrandListToJson) + List? preferredNetworks}); $PaymentSheetAppearanceCopyWith<$Res>? get appearance; $BillingDetailsCopyWith<$Res>? get defaultBillingDetails; @@ -129,6 +136,7 @@ class _$CustomerSheetInitParamsCopyWithImpl<$Res, Object? removeSavedPaymentMethodMessage = freezed, Object? applePayEnabled = null, Object? googlePayEnabled = null, + Object? preferredNetworks = freezed, }) { return _then(_value.copyWith( style: freezed == style @@ -185,6 +193,10 @@ class _$CustomerSheetInitParamsCopyWithImpl<$Res, ? _value.googlePayEnabled : googlePayEnabled // ignore: cast_nullable_to_non_nullable as bool, + preferredNetworks: freezed == preferredNetworks + ? _value.preferredNetworks + : preferredNetworks // ignore: cast_nullable_to_non_nullable + as List?, ) as $Val); } @@ -252,7 +264,9 @@ abstract class _$$CustomerSheetInitParamsImplCopyWith<$Res> String? returnURL, String? removeSavedPaymentMethodMessage, bool applePayEnabled, - bool googlePayEnabled}); + bool googlePayEnabled, + @JsonKey(toJson: _cardBrandListToJson) + List? preferredNetworks}); @override $PaymentSheetAppearanceCopyWith<$Res>? get appearance; @@ -289,6 +303,7 @@ class __$$CustomerSheetInitParamsImplCopyWithImpl<$Res> Object? removeSavedPaymentMethodMessage = freezed, Object? applePayEnabled = null, Object? googlePayEnabled = null, + Object? preferredNetworks = freezed, }) { return _then(_$CustomerSheetInitParamsImpl( style: freezed == style @@ -345,6 +360,10 @@ class __$$CustomerSheetInitParamsImplCopyWithImpl<$Res> ? _value.googlePayEnabled : googlePayEnabled // ignore: cast_nullable_to_non_nullable as bool, + preferredNetworks: freezed == preferredNetworks + ? _value._preferredNetworks + : preferredNetworks // ignore: cast_nullable_to_non_nullable + as List?, )); } } @@ -366,7 +385,10 @@ class _$CustomerSheetInitParamsImpl implements _CustomerSheetInitParams { this.returnURL, this.removeSavedPaymentMethodMessage, this.applePayEnabled = true, - this.googlePayEnabled = true}); + this.googlePayEnabled = true, + @JsonKey(toJson: _cardBrandListToJson) + final List? preferredNetworks}) + : _preferredNetworks = preferredNetworks; factory _$CustomerSheetInitParamsImpl.fromJson(Map json) => _$$CustomerSheetInitParamsImplFromJson(json); @@ -429,9 +451,26 @@ class _$CustomerSheetInitParamsImpl implements _CustomerSheetInitParams { @JsonKey() final bool googlePayEnabled; + /// The list of preferred networks that should be used to process payments made with a co-branded card. + /// This value will only be used if your user hasn't selected a network themselves. + final List? _preferredNetworks; + + /// The list of preferred networks that should be used to process payments made with a co-branded card. + /// This value will only be used if your user hasn't selected a network themselves. + @override + @JsonKey(toJson: _cardBrandListToJson) + List? get preferredNetworks { + final value = _preferredNetworks; + if (value == null) return null; + if (_preferredNetworks is EqualUnmodifiableListView) + return _preferredNetworks; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + @override String toString() { - return 'CustomerSheetInitParams(style: $style, appearance: $appearance, setupIntentClientSecret: $setupIntentClientSecret, customerId: $customerId, customerEphemeralKeySecret: $customerEphemeralKeySecret, merchantDisplayName: $merchantDisplayName, headerTextForSelectionScreen: $headerTextForSelectionScreen, defaultBillingDetails: $defaultBillingDetails, billingDetailsCollectionConfiguration: $billingDetailsCollectionConfiguration, returnURL: $returnURL, removeSavedPaymentMethodMessage: $removeSavedPaymentMethodMessage, applePayEnabled: $applePayEnabled, googlePayEnabled: $googlePayEnabled)'; + return 'CustomerSheetInitParams(style: $style, appearance: $appearance, setupIntentClientSecret: $setupIntentClientSecret, customerId: $customerId, customerEphemeralKeySecret: $customerEphemeralKeySecret, merchantDisplayName: $merchantDisplayName, headerTextForSelectionScreen: $headerTextForSelectionScreen, defaultBillingDetails: $defaultBillingDetails, billingDetailsCollectionConfiguration: $billingDetailsCollectionConfiguration, returnURL: $returnURL, removeSavedPaymentMethodMessage: $removeSavedPaymentMethodMessage, applePayEnabled: $applePayEnabled, googlePayEnabled: $googlePayEnabled, preferredNetworks: $preferredNetworks)'; } @override @@ -442,7 +481,8 @@ class _$CustomerSheetInitParamsImpl implements _CustomerSheetInitParams { (identical(other.style, style) || other.style == style) && (identical(other.appearance, appearance) || other.appearance == appearance) && - (identical(other.setupIntentClientSecret, setupIntentClientSecret) || + (identical( + other.setupIntentClientSecret, setupIntentClientSecret) || other.setupIntentClientSecret == setupIntentClientSecret) && (identical(other.customerId, customerId) || other.customerId == customerId) && @@ -451,8 +491,7 @@ class _$CustomerSheetInitParamsImpl implements _CustomerSheetInitParams { customerEphemeralKeySecret) && (identical(other.merchantDisplayName, merchantDisplayName) || other.merchantDisplayName == merchantDisplayName) && - (identical(other.headerTextForSelectionScreen, - headerTextForSelectionScreen) || + (identical(other.headerTextForSelectionScreen, headerTextForSelectionScreen) || other.headerTextForSelectionScreen == headerTextForSelectionScreen) && (identical(other.defaultBillingDetails, defaultBillingDetails) || @@ -470,7 +509,9 @@ class _$CustomerSheetInitParamsImpl implements _CustomerSheetInitParams { (identical(other.applePayEnabled, applePayEnabled) || other.applePayEnabled == applePayEnabled) && (identical(other.googlePayEnabled, googlePayEnabled) || - other.googlePayEnabled == googlePayEnabled)); + other.googlePayEnabled == googlePayEnabled) && + const DeepCollectionEquality() + .equals(other._preferredNetworks, _preferredNetworks)); } @JsonKey(ignore: true) @@ -489,7 +530,8 @@ class _$CustomerSheetInitParamsImpl implements _CustomerSheetInitParams { returnURL, removeSavedPaymentMethodMessage, applePayEnabled, - googlePayEnabled); + googlePayEnabled, + const DeepCollectionEquality().hash(_preferredNetworks)); @JsonKey(ignore: true) @override @@ -521,7 +563,10 @@ abstract class _CustomerSheetInitParams implements CustomerSheetInitParams { final String? returnURL, final String? removeSavedPaymentMethodMessage, final bool applePayEnabled, - final bool googlePayEnabled}) = _$CustomerSheetInitParamsImpl; + final bool googlePayEnabled, + @JsonKey(toJson: _cardBrandListToJson) + final List? + preferredNetworks}) = _$CustomerSheetInitParamsImpl; factory _CustomerSheetInitParams.fromJson(Map json) = _$CustomerSheetInitParamsImpl.fromJson; @@ -583,6 +628,12 @@ abstract class _CustomerSheetInitParams implements CustomerSheetInitParams { /// Whether to show Google Pay as an option. Defaults to `false`. bool get googlePayEnabled; @override + + /// The list of preferred networks that should be used to process payments made with a co-branded card. + /// This value will only be used if your user hasn't selected a network themselves. + @JsonKey(toJson: _cardBrandListToJson) + List? get preferredNetworks; + @override @JsonKey(ignore: true) _$$CustomerSheetInitParamsImplCopyWith<_$CustomerSheetInitParamsImpl> get copyWith => throw _privateConstructorUsedError; diff --git a/packages/stripe_platform_interface/lib/src/models/customer_sheet.g.dart b/packages/stripe_platform_interface/lib/src/models/customer_sheet.g.dart index ad7f6b133..819878538 100644 --- a/packages/stripe_platform_interface/lib/src/models/customer_sheet.g.dart +++ b/packages/stripe_platform_interface/lib/src/models/customer_sheet.g.dart @@ -35,6 +35,9 @@ _$CustomerSheetInitParamsImpl _$$CustomerSheetInitParamsImplFromJson( json['removeSavedPaymentMethodMessage'] as String?, applePayEnabled: json['applePayEnabled'] as bool? ?? true, googlePayEnabled: json['googlePayEnabled'] as bool? ?? true, + preferredNetworks: (json['preferredNetworks'] as List?) + ?.map((e) => $enumDecode(_$CardBrandEnumMap, e)) + .toList(), ); Map _$$CustomerSheetInitParamsImplToJson( @@ -55,6 +58,7 @@ Map _$$CustomerSheetInitParamsImplToJson( instance.removeSavedPaymentMethodMessage, 'applePayEnabled': instance.applePayEnabled, 'googlePayEnabled': instance.googlePayEnabled, + 'preferredNetworks': _cardBrandListToJson(instance.preferredNetworks), }; const _$ThemeModeEnumMap = { @@ -63,6 +67,18 @@ const _$ThemeModeEnumMap = { ThemeMode.dark: 'dark', }; +const _$CardBrandEnumMap = { + CardBrand.JCB: 'JCB', + CardBrand.Amex: 'Amex', + CardBrand.CartesBancaires: 'CartesBancaires', + CardBrand.DinersClub: 'DinersClub', + CardBrand.Discover: 'Discover', + CardBrand.Mastercard: 'Mastercard', + CardBrand.UnionPay: 'UnionPay', + CardBrand.Visa: 'Visa', + CardBrand.Unknown: 'Unknown', +}; + _$CustomerSheetPresentParamsImpl _$$CustomerSheetPresentParamsImplFromJson( Map json) => _$CustomerSheetPresentParamsImpl( diff --git a/packages/stripe_platform_interface/lib/src/models/payment_sheet.dart b/packages/stripe_platform_interface/lib/src/models/payment_sheet.dart index 8c52ad87d..61c17b258 100644 --- a/packages/stripe_platform_interface/lib/src/models/payment_sheet.dart +++ b/packages/stripe_platform_interface/lib/src/models/payment_sheet.dart @@ -90,6 +90,10 @@ class SetupPaymentSheetParameters with _$SetupPaymentSheetParameters { /// Optional configuration to display a custom message when a saved payment method is removed. iOS only. String? removeSavedPaymentMethodMessage, + + /// The list of preferred networks that should be used to process payments made with a co-branded card. + /// This value will only be used if your user hasn't selected a network themselves. + @JsonKey(toJson: _cardBrandListToJson) List? preferredNetworks, }) = _SetupParameters; factory SetupPaymentSheetParameters.fromJson(Map json) => @@ -187,6 +191,9 @@ class PaymentSheetGooglePay with _$PaymentSheetGooglePay { /// An optional amount to display for setup intents. Google Pay may or may not display this amount depending on its own internal logic. Defaults to 0 if none is provided. String? amount, + + /// The Google Pay button type to use. Set to "Pay" by default. + PlatformButtonType? buttonType, }) = _PaymentSheetGooglePay; factory PaymentSheetGooglePay.fromJson(Map json) => @@ -541,3 +548,10 @@ typedef ConfirmHandler = void Function( PaymentMethod result, bool shouldSavePaymentMethod, ); + +List _cardBrandListToJson(List? list) { + if (list == null) { + return []; + } + return list.map((e) => e.brandValue).toList(); +} diff --git a/packages/stripe_platform_interface/lib/src/models/payment_sheet.freezed.dart b/packages/stripe_platform_interface/lib/src/models/payment_sheet.freezed.dart index e81c31736..cdd4273fd 100644 --- a/packages/stripe_platform_interface/lib/src/models/payment_sheet.freezed.dart +++ b/packages/stripe_platform_interface/lib/src/models/payment_sheet.freezed.dart @@ -101,6 +101,11 @@ mixin _$SetupPaymentSheetParameters { String? get removeSavedPaymentMethodMessage => throw _privateConstructorUsedError; + /// The list of preferred networks that should be used to process payments made with a co-branded card. + /// This value will only be used if your user hasn't selected a network themselves. + @JsonKey(toJson: _cardBrandListToJson) + List? get preferredNetworks => throw _privateConstructorUsedError; + Map toJson() => throw _privateConstructorUsedError; @JsonKey(ignore: true) $SetupPaymentSheetParametersCopyWith @@ -133,7 +138,9 @@ abstract class $SetupPaymentSheetParametersCopyWith<$Res> { String? returnURL, BillingDetailsCollectionConfiguration? billingDetailsCollectionConfiguration, - String? removeSavedPaymentMethodMessage}); + String? removeSavedPaymentMethodMessage, + @JsonKey(toJson: _cardBrandListToJson) + List? preferredNetworks}); $IntentConfigurationCopyWith<$Res>? get intentConfiguration; $PaymentSheetApplePayCopyWith<$Res>? get applePay; @@ -175,6 +182,7 @@ class _$SetupPaymentSheetParametersCopyWithImpl<$Res, Object? returnURL = freezed, Object? billingDetailsCollectionConfiguration = freezed, Object? removeSavedPaymentMethodMessage = freezed, + Object? preferredNetworks = freezed, }) { return _then(_value.copyWith( customFlow: null == customFlow @@ -247,6 +255,10 @@ class _$SetupPaymentSheetParametersCopyWithImpl<$Res, ? _value.removeSavedPaymentMethodMessage : removeSavedPaymentMethodMessage // ignore: cast_nullable_to_non_nullable as String?, + preferredNetworks: freezed == preferredNetworks + ? _value.preferredNetworks + : preferredNetworks // ignore: cast_nullable_to_non_nullable + as List?, ) as $Val); } @@ -353,7 +365,9 @@ abstract class _$$SetupParametersImplCopyWith<$Res> String? returnURL, BillingDetailsCollectionConfiguration? billingDetailsCollectionConfiguration, - String? removeSavedPaymentMethodMessage}); + String? removeSavedPaymentMethodMessage, + @JsonKey(toJson: _cardBrandListToJson) + List? preferredNetworks}); @override $IntentConfigurationCopyWith<$Res>? get intentConfiguration; @@ -398,6 +412,7 @@ class __$$SetupParametersImplCopyWithImpl<$Res> Object? returnURL = freezed, Object? billingDetailsCollectionConfiguration = freezed, Object? removeSavedPaymentMethodMessage = freezed, + Object? preferredNetworks = freezed, }) { return _then(_$SetupParametersImpl( customFlow: null == customFlow @@ -470,6 +485,10 @@ class __$$SetupParametersImplCopyWithImpl<$Res> ? _value.removeSavedPaymentMethodMessage : removeSavedPaymentMethodMessage // ignore: cast_nullable_to_non_nullable as String?, + preferredNetworks: freezed == preferredNetworks + ? _value._preferredNetworks + : preferredNetworks // ignore: cast_nullable_to_non_nullable + as List?, )); } } @@ -495,7 +514,10 @@ class _$SetupParametersImpl implements _SetupParameters { @JsonKey(name: 'defaultBillingDetails') this.billingDetails, this.returnURL, this.billingDetailsCollectionConfiguration, - this.removeSavedPaymentMethodMessage}); + this.removeSavedPaymentMethodMessage, + @JsonKey(toJson: _cardBrandListToJson) + final List? preferredNetworks}) + : _preferredNetworks = preferredNetworks; factory _$SetupParametersImpl.fromJson(Map json) => _$$SetupParametersImplFromJson(json); @@ -596,9 +618,26 @@ class _$SetupParametersImpl implements _SetupParameters { @override final String? removeSavedPaymentMethodMessage; + /// The list of preferred networks that should be used to process payments made with a co-branded card. + /// This value will only be used if your user hasn't selected a network themselves. + final List? _preferredNetworks; + + /// The list of preferred networks that should be used to process payments made with a co-branded card. + /// This value will only be used if your user hasn't selected a network themselves. + @override + @JsonKey(toJson: _cardBrandListToJson) + List? get preferredNetworks { + final value = _preferredNetworks; + if (value == null) return null; + if (_preferredNetworks is EqualUnmodifiableListView) + return _preferredNetworks; + // ignore: implicit_dynamic_type + return EqualUnmodifiableListView(value); + } + @override String toString() { - return 'SetupPaymentSheetParameters(customFlow: $customFlow, customerId: $customerId, primaryButtonLabel: $primaryButtonLabel, customerEphemeralKeySecret: $customerEphemeralKeySecret, paymentIntentClientSecret: $paymentIntentClientSecret, setupIntentClientSecret: $setupIntentClientSecret, intentConfiguration: $intentConfiguration, merchantDisplayName: $merchantDisplayName, applePay: $applePay, style: $style, googlePay: $googlePay, allowsDelayedPaymentMethods: $allowsDelayedPaymentMethods, appearance: $appearance, billingDetails: $billingDetails, returnURL: $returnURL, billingDetailsCollectionConfiguration: $billingDetailsCollectionConfiguration, removeSavedPaymentMethodMessage: $removeSavedPaymentMethodMessage)'; + return 'SetupPaymentSheetParameters(customFlow: $customFlow, customerId: $customerId, primaryButtonLabel: $primaryButtonLabel, customerEphemeralKeySecret: $customerEphemeralKeySecret, paymentIntentClientSecret: $paymentIntentClientSecret, setupIntentClientSecret: $setupIntentClientSecret, intentConfiguration: $intentConfiguration, merchantDisplayName: $merchantDisplayName, applePay: $applePay, style: $style, googlePay: $googlePay, allowsDelayedPaymentMethods: $allowsDelayedPaymentMethods, appearance: $appearance, billingDetails: $billingDetails, returnURL: $returnURL, billingDetailsCollectionConfiguration: $billingDetailsCollectionConfiguration, removeSavedPaymentMethodMessage: $removeSavedPaymentMethodMessage, preferredNetworks: $preferredNetworks)'; } @override @@ -643,7 +682,9 @@ class _$SetupParametersImpl implements _SetupParameters { billingDetailsCollectionConfiguration) && (identical(other.removeSavedPaymentMethodMessage, removeSavedPaymentMethodMessage) || other.removeSavedPaymentMethodMessage == - removeSavedPaymentMethodMessage)); + removeSavedPaymentMethodMessage) && + const DeepCollectionEquality() + .equals(other._preferredNetworks, _preferredNetworks)); } @JsonKey(ignore: true) @@ -666,7 +707,8 @@ class _$SetupParametersImpl implements _SetupParameters { billingDetails, returnURL, billingDetailsCollectionConfiguration, - removeSavedPaymentMethodMessage); + removeSavedPaymentMethodMessage, + const DeepCollectionEquality().hash(_preferredNetworks)); @JsonKey(ignore: true) @override @@ -703,7 +745,9 @@ abstract class _SetupParameters implements SetupPaymentSheetParameters { final String? returnURL, final BillingDetailsCollectionConfiguration? billingDetailsCollectionConfiguration, - final String? removeSavedPaymentMethodMessage}) = _$SetupParametersImpl; + final String? removeSavedPaymentMethodMessage, + @JsonKey(toJson: _cardBrandListToJson) + final List? preferredNetworks}) = _$SetupParametersImpl; factory _SetupParameters.fromJson(Map json) = _$SetupParametersImpl.fromJson; @@ -803,6 +847,12 @@ abstract class _SetupParameters implements SetupPaymentSheetParameters { /// Optional configuration to display a custom message when a saved payment method is removed. iOS only. String? get removeSavedPaymentMethodMessage; @override + + /// The list of preferred networks that should be used to process payments made with a co-branded card. + /// This value will only be used if your user hasn't selected a network themselves. + @JsonKey(toJson: _cardBrandListToJson) + List? get preferredNetworks; + @override @JsonKey(ignore: true) _$$SetupParametersImplCopyWith<_$SetupParametersImpl> get copyWith => throw _privateConstructorUsedError; @@ -1600,6 +1650,9 @@ mixin _$PaymentSheetGooglePay { /// An optional amount to display for setup intents. Google Pay may or may not display this amount depending on its own internal logic. Defaults to 0 if none is provided. String? get amount => throw _privateConstructorUsedError; + /// The Google Pay button type to use. Set to "Pay" by default. + PlatformButtonType? get buttonType => throw _privateConstructorUsedError; + Map toJson() => throw _privateConstructorUsedError; @JsonKey(ignore: true) $PaymentSheetGooglePayCopyWith get copyWith => @@ -1617,7 +1670,8 @@ abstract class $PaymentSheetGooglePayCopyWith<$Res> { String? currencyCode, bool testEnv, String? label, - String? amount}); + String? amount, + PlatformButtonType? buttonType}); } /// @nodoc @@ -1639,6 +1693,7 @@ class _$PaymentSheetGooglePayCopyWithImpl<$Res, Object? testEnv = null, Object? label = freezed, Object? amount = freezed, + Object? buttonType = freezed, }) { return _then(_value.copyWith( merchantCountryCode: null == merchantCountryCode @@ -1661,6 +1716,10 @@ class _$PaymentSheetGooglePayCopyWithImpl<$Res, ? _value.amount : amount // ignore: cast_nullable_to_non_nullable as String?, + buttonType: freezed == buttonType + ? _value.buttonType + : buttonType // ignore: cast_nullable_to_non_nullable + as PlatformButtonType?, ) as $Val); } } @@ -1679,7 +1738,8 @@ abstract class _$$PaymentSheetGooglePayImplCopyWith<$Res> String? currencyCode, bool testEnv, String? label, - String? amount}); + String? amount, + PlatformButtonType? buttonType}); } /// @nodoc @@ -1699,6 +1759,7 @@ class __$$PaymentSheetGooglePayImplCopyWithImpl<$Res> Object? testEnv = null, Object? label = freezed, Object? amount = freezed, + Object? buttonType = freezed, }) { return _then(_$PaymentSheetGooglePayImpl( merchantCountryCode: null == merchantCountryCode @@ -1721,6 +1782,10 @@ class __$$PaymentSheetGooglePayImplCopyWithImpl<$Res> ? _value.amount : amount // ignore: cast_nullable_to_non_nullable as String?, + buttonType: freezed == buttonType + ? _value.buttonType + : buttonType // ignore: cast_nullable_to_non_nullable + as PlatformButtonType?, )); } } @@ -1734,7 +1799,8 @@ class _$PaymentSheetGooglePayImpl implements _PaymentSheetGooglePay { this.currencyCode, this.testEnv = false, this.label, - this.amount}); + this.amount, + this.buttonType}); factory _$PaymentSheetGooglePayImpl.fromJson(Map json) => _$$PaymentSheetGooglePayImplFromJson(json); @@ -1760,9 +1826,13 @@ class _$PaymentSheetGooglePayImpl implements _PaymentSheetGooglePay { @override final String? amount; + /// The Google Pay button type to use. Set to "Pay" by default. + @override + final PlatformButtonType? buttonType; + @override String toString() { - return 'PaymentSheetGooglePay(merchantCountryCode: $merchantCountryCode, currencyCode: $currencyCode, testEnv: $testEnv, label: $label, amount: $amount)'; + return 'PaymentSheetGooglePay(merchantCountryCode: $merchantCountryCode, currencyCode: $currencyCode, testEnv: $testEnv, label: $label, amount: $amount, buttonType: $buttonType)'; } @override @@ -1776,13 +1846,15 @@ class _$PaymentSheetGooglePayImpl implements _PaymentSheetGooglePay { other.currencyCode == currencyCode) && (identical(other.testEnv, testEnv) || other.testEnv == testEnv) && (identical(other.label, label) || other.label == label) && - (identical(other.amount, amount) || other.amount == amount)); + (identical(other.amount, amount) || other.amount == amount) && + (identical(other.buttonType, buttonType) || + other.buttonType == buttonType)); } @JsonKey(ignore: true) @override - int get hashCode => Object.hash( - runtimeType, merchantCountryCode, currencyCode, testEnv, label, amount); + int get hashCode => Object.hash(runtimeType, merchantCountryCode, + currencyCode, testEnv, label, amount, buttonType); @JsonKey(ignore: true) @override @@ -1805,7 +1877,8 @@ abstract class _PaymentSheetGooglePay implements PaymentSheetGooglePay { final String? currencyCode, final bool testEnv, final String? label, - final String? amount}) = _$PaymentSheetGooglePayImpl; + final String? amount, + final PlatformButtonType? buttonType}) = _$PaymentSheetGooglePayImpl; factory _PaymentSheetGooglePay.fromJson(Map json) = _$PaymentSheetGooglePayImpl.fromJson; @@ -1831,6 +1904,10 @@ abstract class _PaymentSheetGooglePay implements PaymentSheetGooglePay { /// An optional amount to display for setup intents. Google Pay may or may not display this amount depending on its own internal logic. Defaults to 0 if none is provided. String? get amount; @override + + /// The Google Pay button type to use. Set to "Pay" by default. + PlatformButtonType? get buttonType; + @override @JsonKey(ignore: true) _$$PaymentSheetGooglePayImplCopyWith<_$PaymentSheetGooglePayImpl> get copyWith => throw _privateConstructorUsedError; diff --git a/packages/stripe_platform_interface/lib/src/models/payment_sheet.g.dart b/packages/stripe_platform_interface/lib/src/models/payment_sheet.g.dart index a19f0a300..11a688302 100644 --- a/packages/stripe_platform_interface/lib/src/models/payment_sheet.g.dart +++ b/packages/stripe_platform_interface/lib/src/models/payment_sheet.g.dart @@ -48,6 +48,9 @@ _$SetupParametersImpl _$$SetupParametersImplFromJson( as Map), removeSavedPaymentMethodMessage: json['removeSavedPaymentMethodMessage'] as String?, + preferredNetworks: (json['preferredNetworks'] as List?) + ?.map((e) => $enumDecode(_$CardBrandEnumMap, e)) + .toList(), ); Map _$$SetupParametersImplToJson( @@ -72,6 +75,7 @@ Map _$$SetupParametersImplToJson( instance.billingDetailsCollectionConfiguration?.toJson(), 'removeSavedPaymentMethodMessage': instance.removeSavedPaymentMethodMessage, + 'preferredNetworks': _cardBrandListToJson(instance.preferredNetworks), }; const _$ThemeModeEnumMap = { @@ -80,6 +84,18 @@ const _$ThemeModeEnumMap = { ThemeMode.dark: 'dark', }; +const _$CardBrandEnumMap = { + CardBrand.JCB: 'JCB', + CardBrand.Amex: 'Amex', + CardBrand.CartesBancaires: 'CartesBancaires', + CardBrand.DinersClub: 'DinersClub', + CardBrand.Discover: 'Discover', + CardBrand.Mastercard: 'Mastercard', + CardBrand.UnionPay: 'UnionPay', + CardBrand.Visa: 'Visa', + CardBrand.Unknown: 'Unknown', +}; + _$IntentConfigurationImpl _$$IntentConfigurationImplFromJson( Map json) => _$IntentConfigurationImpl( @@ -180,6 +196,8 @@ _$PaymentSheetGooglePayImpl _$$PaymentSheetGooglePayImplFromJson( testEnv: json['testEnv'] as bool? ?? false, label: json['label'] as String?, amount: json['amount'] as String?, + buttonType: + $enumDecodeNullable(_$PlatformButtonTypeEnumMap, json['buttonType']), ); Map _$$PaymentSheetGooglePayImplToJson( @@ -190,6 +208,7 @@ Map _$$PaymentSheetGooglePayImplToJson( 'testEnv': instance.testEnv, 'label': instance.label, 'amount': instance.amount, + 'buttonType': _$PlatformButtonTypeEnumMap[instance.buttonType], }; _$PaymentSheetAppearanceImpl _$$PaymentSheetAppearanceImplFromJson( diff --git a/packages/stripe_platform_interface/lib/stripe_platform_interface.dart b/packages/stripe_platform_interface/lib/stripe_platform_interface.dart index f0c4588f5..b2a578c5d 100644 --- a/packages/stripe_platform_interface/lib/stripe_platform_interface.dart +++ b/packages/stripe_platform_interface/lib/stripe_platform_interface.dart @@ -7,6 +7,7 @@ export 'src/models/app_info.dart'; export 'src/models/apple_pay.dart'; export 'src/models/aubecs_form.dart'; export 'src/models/capture_method.dart'; +export 'src/models/card_brand.dart'; export 'src/models/card_details.dart'; export 'src/models/card_field_input.dart'; export 'src/models/create_token_data.dart';