Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync #1648

Merged
merged 3 commits into from
Feb 26, 2024
Merged

Sync #1648

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
padding: EdgeInsets.symmetric(horizontal: 16),
children: [
CardField(
preferredNetworks: [CardBrand.Amex],

Check warning on line 42 in example/lib/screens/card_payments/no_webhook_payment_screen.dart

View workflow job for this annotation

GitHub Actions / Typo CI

Amex

"Amex" is a typo. Did you mean "Amen"?
controller: controller,
),
SizedBox(height: 20),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
),
SizedBox(height: 20),
CardField(
preferredNetworks: [CardBrand.Amex],

Check warning on line 40 in example/lib/screens/card_payments/webhook_payment_screen.dart

View workflow job for this annotation

GitHub Actions / Typo CI

Amex

"Amex" is a typo. Did you mean "Amen"?
enablePostalCode: true,
countryCode: 'US',
postalCodeHintText: 'Enter the us postal code',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@
// Main params
paymentIntentClientSecret: data['paymentIntent'],
merchantDisplayName: 'Flutter Stripe Store Demo',
preferredNetworks: [CardBrand.Amex],

Check warning on line 93 in example/lib/screens/payment_sheet/payment_sheet_screen.dart

View workflow job for this annotation

GitHub Actions / Typo CI

Amex

"Amex" is a typo. Did you mean "Amen"?
// Customer params
customerId: data['customer'],
customerEphemeralKeySecret: data['ephemeralKey'],
Expand Down
10 changes: 10 additions & 0 deletions packages/stripe/lib/src/widgets/card_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class CardField extends StatefulWidget {
this.cvcHintText,
this.postalCodeHintText,
this.controller,
this.preferredNetworks,
this.androidPlatformViewRenderType =
AndroidPlatformViewRenderType.expensiveAndroidView,
}) : super(key: key);
Expand Down Expand Up @@ -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<CardBrand>? preferredNetworks;

/// Type of platformview used for rendering on Android.
///
/// This is an advanced option and changing this should be tested on multiple android devices.
Expand Down Expand Up @@ -185,6 +190,7 @@ class _CardFieldState extends State<CardField> {
child: _MethodChannelCardField(
controller: controller,
disabled: widget.disabled,
preferredNetworks: widget.preferredNetworks,
height: platformCardHeight,
androidPlatformViewRenderType:
widget.androidPlatformViewRenderType,
Expand Down Expand Up @@ -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,
Expand All @@ -311,6 +318,7 @@ class _MethodChannelCardField extends StatefulWidget {
final bool dangerouslyGetFullCardDetails;
final bool dangerouslyUpdateFullCardDetails;
final AndroidPlatformViewRenderType androidPlatformViewRenderType;
final List<CardBrand>? preferredNetworks;

// This is used in the platform side to register the view.
static const _viewType = 'flutter.stripe/card_field';
Expand Down Expand Up @@ -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)
Expand Down
12 changes: 11 additions & 1 deletion packages/stripe/lib/src/widgets/card_form_field.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'dart:developer';
import 'dart:developer' as dev;
import 'dart:developer';
import 'dart:io';

import 'package:flutter/foundation.dart';
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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<CardBrand>? preferredNetworks;

@override
// ignore: library_private_types_in_public_api
_CardFormFieldState createState() => _CardFormFieldState();
Expand Down Expand Up @@ -196,6 +201,7 @@ class _CardFormFieldState extends State<CardFormField> {
disabled: widget.disabled,
onFocus: widget.onFocus,
countryCode: widget.countryCode,
preferredNetworks: widget.preferredNetworks,
);
}

Expand All @@ -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)
Expand All @@ -240,6 +247,7 @@ class _MethodChannelCardFormField extends StatefulWidget {
final bool dangerouslyGetFullCardDetails;
final bool dangerouslyUpdateFullCardDetails;
final String? countryCode;
final List<CardBrand>? preferredNetworks;

// This is used in the platform side to register the view.
static const _viewType = 'flutter.stripe/card_form_field';
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion packages/stripe_android/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -20,6 +21,12 @@ public ReadableArray(JSONArray array) {
this.array = array;
}

public ReadableArray(@NotNull List<Object> array) {
this.array = new JSONArray();
array.addAll(array);
}


public String getString(int index) {
try {
return array.getString(index);
Expand Down
Original file line number Diff line number Diff line change
@@ -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.*
Expand All @@ -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,
Expand Down Expand Up @@ -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<Any>))
}
if (creationParams?.containsKey("cardDetails") == true) {
val value = ReadableMap(creationParams["cardDetails"] as Map<String, Any>)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.*
Expand Down Expand Up @@ -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<Any>))
}
if (creationParams?.containsKey("dangerouslyGetFullCardDetails") == true) {
stripeSdkCardViewManager.setDangerouslyGetFullCardDetails(cardView, creationParams["dangerouslyGetFullCardDetails"] as Boolean)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.reactnativestripesdk

import android.annotation.SuppressLint
import android.content.res.ColorStateList
import android.graphics.Color
import android.os.Build
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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
}
}
Expand All @@ -214,10 +216,15 @@ class CardFieldView(context: ThemedReactContext) : FrameLayout(context) {
mCardWidget.isEnabled = !isDisabled
}

fun setPreferredNetworks(preferredNetworks: ArrayList<Int>?) {
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")
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ class CardFieldViewManager : SimpleViewManager<CardFieldView>() {
view.setDisabled(isDisabled)
}

@ReactProp(name = "preferredNetworks")
fun setPreferredNetworks(view: CardFieldView, preferredNetworks: ReadableArray?) {
val networks = preferredNetworks?.toArrayList()?.filterIsInstance<Int>()?.let { ArrayList(it) }
view.setPreferredNetworks(networks)
}

override fun createViewInstance(reactContext: ThemedReactContext): CardFieldView {
val stripeSdkModule: StripeSdkModule? = reactContext.getNativeModule(StripeSdkModule::class.java)
val view = CardFieldView(reactContext)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.reactnativestripesdk

import android.annotation.SuppressLint
import android.content.res.ColorStateList
import android.graphics.Color
import android.os.Build
Expand Down Expand Up @@ -64,6 +65,11 @@ class CardFormView(context: ThemedReactContext) : FrameLayout(context) {
cardForm.isEnabled = !isDisabled
}

fun setPreferredNetworks(preferredNetworks: ArrayList<Int>?) {
cardForm.setPreferredNetworks(mapToPreferredNetworks(preferredNetworks))
}

@SuppressLint("RestrictedApi")
private fun setCountry(countryString: String?) {
if (countryString != null) {
cardFormViewBinding.countryLayout.setSelectedCountryCode(CountryCode(countryString))
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ class CardFormViewManager : SimpleViewManager<CardFormView>() {
view.setDisabled(isDisabled)
}

@ReactProp(name = "preferredNetworks")
fun setPreferredNetworks(view: CardFormView, preferredNetworks: ReadableArray?) {
val networks = preferredNetworks?.toArrayList()?.filterIsInstance<Int>()?.let { ArrayList(it) }
view.setPreferredNetworks(networks)
}

override fun createViewInstance(reactContext: ThemedReactContext): CardFormView {
val stripeSdkModule: StripeSdkModule? = reactContext.getNativeModule(StripeSdkModule::class.java)
val view = CardFormView(reactContext)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.reactnativestripesdk

import android.annotation.SuppressLint
import android.util.Log
import android.view.View
import android.widget.FrameLayout
Expand Down Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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`.")
}
Expand All @@ -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
)
}

Expand Down
Loading
Loading