0.0.6 release
This commit is contained in:
		
							parent
							
								
									d7d27a1cf5
								
							
						
					
					
						commit
						462e40308f
					
				
							
								
								
									
										10
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@ -1,3 +1,13 @@
 | 
				
			|||||||
 | 
					## 0.0.6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Improved assertion and error messaging when missing stripe implements
 | 
				
			||||||
 | 
					- Added better doc comments
 | 
				
			||||||
 | 
					- Fixed `CardTextField.delayToShowLoading`, now it uses it
 | 
				
			||||||
 | 
					- Fixed bad assertion logic when providing stripe keys
 | 
				
			||||||
 | 
					- Added ability to make Stripe call with `GlobalKey`
 | 
				
			||||||
 | 
					- Refactored method `onTokenReceived` to `onStripeResponse` to be clearer
 | 
				
			||||||
 | 
					- Refactored method `onCardDetailsComplete` to `onValidCardDetails` to be clearer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## 0.0.5
 | 
					## 0.0.5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- Fix Web, invalid call to `Platform.isAndroid`
 | 
					- Fix Web, invalid call to `Platform.isAndroid`
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										21
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								README.md
									
									
									
									
									
								
							@ -23,7 +23,7 @@ Got to use emojis and taglines for attention grabbing and algorithm hacking:
 | 
				
			|||||||
- Native Implementation: compiles and loads like the rest of your app, unlike embeded html
 | 
					- Native Implementation: compiles and loads like the rest of your app, unlike embeded html
 | 
				
			||||||
- Automatic validation: no `inputFormatters` or `RegExp` needed on your side
 | 
					- Automatic validation: no `inputFormatters` or `RegExp` needed on your side
 | 
				
			||||||
 | 
					
 | 
				
			||||||
The card data can either be retrieved with the `onCardDetailsComplete` callback, or
 | 
					The card data can either be retrieved with the `onValidCardDetails` callback, or
 | 
				
			||||||
you can have the element automatically create a Stripe card token when the fields
 | 
					you can have the element automatically create a Stripe card token when the fields
 | 
				
			||||||
are filled out, and return the token with the `onTokenReceived` callback.
 | 
					are filled out, and return the token with the `onTokenReceived` callback.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -62,12 +62,13 @@ Include the package in a file:
 | 
				
			|||||||
import 'package:stripe_native_card_field/stripe_native_card_field.dart';
 | 
					import 'package:stripe_native_card_field/stripe_native_card_field.dart';
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### For just Card Data
 | 
					### For Raw Card Data
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Provide a callback for the `CardTextField` to return you the data when its complete.
 | 
				
			||||||
```dart
 | 
					```dart
 | 
				
			||||||
CardTextField(
 | 
					CardTextField(
 | 
				
			||||||
  width: 500,
 | 
					  width: 500,
 | 
				
			||||||
  onCardDetailsComplete: (details) {
 | 
					  onValidCardDetails: (details) {
 | 
				
			||||||
    // Save the card details to use with your call to Stripe, or whoever
 | 
					    // Save the card details to use with your call to Stripe, or whoever
 | 
				
			||||||
    setState(() => _cardDetails = details);
 | 
					    setState(() => _cardDetails = details);
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
@ -76,17 +77,27 @@ CardTextField(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
### For Stripe Token
 | 
					### For Stripe Token
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Simply provide a function for the `onStripeResponse` callback!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```dart
 | 
					```dart
 | 
				
			||||||
CardTextField(
 | 
					CardTextField(
 | 
				
			||||||
  width: 500,
 | 
					  width: 500,
 | 
				
			||||||
  stripePublishableKey: 'pk_test_abc123', // Your stripe key here
 | 
					  stripePublishableKey: 'pk_test_abc123', // Your stripe key here
 | 
				
			||||||
  onTokenReceived: (token) {
 | 
					  onStripeResponse: (Map<String, dynamic> data) {
 | 
				
			||||||
    // Save the stripe token to send to your backend
 | 
					    // Save the stripe token to send to your backend
 | 
				
			||||||
    setState(() => _token = token);
 | 
					    setState(() => _tokenData = data);
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
);
 | 
					);
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you want more fine-grained control of when the stripe call is made, you
 | 
				
			||||||
 | 
					can create a `GlobalKey` and access the `CardTextFieldState`, calling the
 | 
				
			||||||
 | 
					`getStripeResponse()` function yourself. See the provided [example](https://pub.dev/packages/stripe_native_card_field/example)
 | 
				
			||||||
 | 
					for details. If you choose this route, do not provide an `onStripeResponse` callback, or you will end up
 | 
				
			||||||
 | 
					making two calls to stripe!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Additional information
 | 
					# Additional information
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Repository located [here](https://git.fosscat.com/n8r/stripe_native_card_field)
 | 
					Repository located [here](https://git.fosscat.com/n8r/stripe_native_card_field)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Please email me at n8r@fosscat.com for any issues or PRs.
 | 
				
			||||||
 | 
				
			|||||||
@ -61,14 +61,15 @@ class _MyHomePageState extends State<MyHomePage> {
 | 
				
			|||||||
            ),
 | 
					            ),
 | 
				
			||||||
            CardTextField(
 | 
					            CardTextField(
 | 
				
			||||||
              width: 300,
 | 
					              width: 300,
 | 
				
			||||||
              onCardDetailsComplete: (details) {
 | 
					              onValidCardDetails: (details) {
 | 
				
			||||||
                if (kDebugMode) {
 | 
					                if (kDebugMode) {
 | 
				
			||||||
                  print(details);
 | 
					                  print(details);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
              },
 | 
					              },
 | 
				
			||||||
              textStyle:
 | 
					              textStyle:
 | 
				
			||||||
                  const TextStyle(fontFamily: 'Lato', color: Colors.tealAccent),
 | 
					                  const TextStyle(fontFamily: 'Lato', color: Colors.tealAccent),
 | 
				
			||||||
              hintTextStyle: const TextStyle(fontFamily: 'Lato', color: Colors.teal),
 | 
					              hintTextStyle:
 | 
				
			||||||
 | 
					                  const TextStyle(fontFamily: 'Lato', color: Colors.teal),
 | 
				
			||||||
              errorTextStyle: const TextStyle(color: Colors.purpleAccent),
 | 
					              errorTextStyle: const TextStyle(color: Colors.purpleAccent),
 | 
				
			||||||
              boxDecoration: BoxDecoration(
 | 
					              boxDecoration: BoxDecoration(
 | 
				
			||||||
                color: Colors.black54,
 | 
					                color: Colors.black54,
 | 
				
			||||||
 | 
				
			|||||||
@ -38,8 +38,26 @@ class _MyHomePageState extends State<MyHomePage> {
 | 
				
			|||||||
  CardDetailsValidState? state;
 | 
					  CardDetailsValidState? state;
 | 
				
			||||||
  String? errorText;
 | 
					  String? errorText;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Creating a global key here allows us to call the `getStripeResponse()`
 | 
				
			||||||
 | 
					  // inside the CardTextFieldState widget in our build method. See below
 | 
				
			||||||
 | 
					  final _key = GlobalKey<CardTextFieldState>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
 | 
					    final cardField = CardTextField(
 | 
				
			||||||
 | 
					      key: _key,
 | 
				
			||||||
 | 
					      loadingWidgetLocation: LoadingLocation.above,
 | 
				
			||||||
 | 
					      stripePublishableKey: 'pk_test_abc123testmykey',
 | 
				
			||||||
 | 
					      width: 600,
 | 
				
			||||||
 | 
					      onValidCardDetails: (details) {
 | 
				
			||||||
 | 
					        if (kDebugMode) {
 | 
				
			||||||
 | 
					          print(details);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      overrideValidState: state,
 | 
				
			||||||
 | 
					      errorText: errorText,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return Scaffold(
 | 
					    return Scaffold(
 | 
				
			||||||
      body: Center(
 | 
					      body: Center(
 | 
				
			||||||
        child: Column(
 | 
					        child: Column(
 | 
				
			||||||
@ -51,22 +69,23 @@ class _MyHomePageState extends State<MyHomePage> {
 | 
				
			|||||||
                'Enter your card details below:',
 | 
					                'Enter your card details below:',
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            CardTextField(
 | 
					            cardField,
 | 
				
			||||||
              width: 300,
 | 
					 | 
				
			||||||
              onCardDetailsComplete: (details) {
 | 
					 | 
				
			||||||
                if (kDebugMode) {
 | 
					 | 
				
			||||||
                  print(details);
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
              },
 | 
					 | 
				
			||||||
              overrideValidState: state,
 | 
					 | 
				
			||||||
              errorText: errorText,
 | 
					 | 
				
			||||||
            ),
 | 
					 | 
				
			||||||
            ElevatedButton(
 | 
					            ElevatedButton(
 | 
				
			||||||
              child: const Text('Set manual error'),
 | 
					              child: const Text('Set manual error'),
 | 
				
			||||||
              onPressed: () => setState(() {
 | 
					              onPressed: () => setState(() {
 | 
				
			||||||
                errorText = 'There is a problem';
 | 
					                errorText = 'There is a problem';
 | 
				
			||||||
                state = CardDetailsValidState.invalidCard;
 | 
					                state = CardDetailsValidState.invalidCard;
 | 
				
			||||||
              }),
 | 
					              }),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            const SizedBox(height: 12),
 | 
				
			||||||
 | 
					            ElevatedButton(
 | 
				
			||||||
 | 
					              child: const Text('Get Stripe token'),
 | 
				
			||||||
 | 
					              onPressed: () async {
 | 
				
			||||||
 | 
					                // Here we use the global key to get the stripe data, rather than
 | 
				
			||||||
 | 
					                // using the `onStripeResponse` callback in the widget
 | 
				
			||||||
 | 
					                final tok = await _key.currentState?.getStripeResponse();
 | 
				
			||||||
 | 
					                if (kDebugMode) print(tok);
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
          ],
 | 
					          ],
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
 | 
				
			|||||||
@ -206,7 +206,7 @@ packages:
 | 
				
			|||||||
      path: ".."
 | 
					      path: ".."
 | 
				
			||||||
      relative: true
 | 
					      relative: true
 | 
				
			||||||
    source: path
 | 
					    source: path
 | 
				
			||||||
    version: "0.0.3"
 | 
					    version: "0.0.5"
 | 
				
			||||||
  term_glyph:
 | 
					  term_glyph:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										19
									
								
								lib/card_text_field_error.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								lib/card_text_field_error.dart
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					/// Error class that `CardTextField` throws if any errors are encountered
 | 
				
			||||||
 | 
					class CardTextFieldError extends Error {
 | 
				
			||||||
 | 
					  /// Details provided for the error
 | 
				
			||||||
 | 
					  String? details;
 | 
				
			||||||
 | 
					  CardTextFieldErrorType type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  CardTextFieldError(this.type, {this.details});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  String toString() {
 | 
				
			||||||
 | 
					    return 'CardTextFieldError-${type.name}: $details';
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Enum to add typing to the `CardTextFieldErrorType`
 | 
				
			||||||
 | 
					enum CardTextFieldErrorType {
 | 
				
			||||||
 | 
					  stripeImplementation,
 | 
				
			||||||
 | 
					  unknown,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -2,13 +2,13 @@ library stripe_native_card_field;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import 'dart:async';
 | 
					import 'dart:async';
 | 
				
			||||||
import 'dart:convert';
 | 
					import 'dart:convert';
 | 
				
			||||||
import 'dart:developer';
 | 
					 | 
				
			||||||
import 'dart:io';
 | 
					import 'dart:io';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:flutter/foundation.dart';
 | 
					import 'package:flutter/foundation.dart';
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:flutter/services.dart';
 | 
					import 'package:flutter/services.dart';
 | 
				
			||||||
import 'package:http/http.dart' as http;
 | 
					import 'package:http/http.dart' as http;
 | 
				
			||||||
 | 
					import 'package:stripe_native_card_field/card_text_field_error.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'card_details.dart';
 | 
					import 'card_details.dart';
 | 
				
			||||||
import 'card_provider_icon.dart';
 | 
					import 'card_provider_icon.dart';
 | 
				
			||||||
@ -17,13 +17,23 @@ import 'card_provider_icon.dart';
 | 
				
			|||||||
/// entry process.
 | 
					/// entry process.
 | 
				
			||||||
enum CardEntryStep { number, exp, cvc, postal }
 | 
					enum CardEntryStep { number, exp, cvc, postal }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// enum LoadingLocation { ontop, rightInside }
 | 
					enum LoadingLocation { above, below }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// A uniform text field for entering card details, based
 | 
					/// A uniform text field for entering card details, based
 | 
				
			||||||
/// on the behavior of Stripe's various html elements.
 | 
					/// on the behavior of Stripe's various html elements.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
/// Required `width`.
 | 
					/// Required `width`.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
 | 
					/// To get the card data or stripe token, provide callbacks
 | 
				
			||||||
 | 
					/// for either `onValidCardDetails`, which will return a
 | 
				
			||||||
 | 
					/// `CardDetails` object, or `onStripeResponse`, which will
 | 
				
			||||||
 | 
					/// return a Map<String, dynamic> response from the Stripe Api.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					/// If stripe integration is desired, you must provide both
 | 
				
			||||||
 | 
					/// `stripePublishableKey` and `onStripeResponse`, otherwise
 | 
				
			||||||
 | 
					/// `CardTextField` will `assert(false)` in debug mode or
 | 
				
			||||||
 | 
					/// throw a `CardTextFieldError` in profile or release mode
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
/// If the provided `width < 450.0`, the `CardTextField`
 | 
					/// If the provided `width < 450.0`, the `CardTextField`
 | 
				
			||||||
/// will scroll its content horizontally with the cursor
 | 
					/// will scroll its content horizontally with the cursor
 | 
				
			||||||
/// to compensate.
 | 
					/// to compensate.
 | 
				
			||||||
@ -32,7 +42,7 @@ class CardTextField extends StatefulWidget {
 | 
				
			|||||||
    Key? key,
 | 
					    Key? key,
 | 
				
			||||||
    required this.width,
 | 
					    required this.width,
 | 
				
			||||||
    this.onStripeResponse,
 | 
					    this.onStripeResponse,
 | 
				
			||||||
    this.onCardDetailsComplete,
 | 
					    this.onValidCardDetails,
 | 
				
			||||||
    this.stripePublishableKey,
 | 
					    this.stripePublishableKey,
 | 
				
			||||||
    this.height,
 | 
					    this.height,
 | 
				
			||||||
    this.textStyle,
 | 
					    this.textStyle,
 | 
				
			||||||
@ -41,8 +51,9 @@ class CardTextField extends StatefulWidget {
 | 
				
			|||||||
    this.boxDecoration,
 | 
					    this.boxDecoration,
 | 
				
			||||||
    this.errorBoxDecoration,
 | 
					    this.errorBoxDecoration,
 | 
				
			||||||
    this.loadingWidget,
 | 
					    this.loadingWidget,
 | 
				
			||||||
 | 
					    this.loadingWidgetLocation = LoadingLocation.below,
 | 
				
			||||||
    this.showInternalLoadingWidget = true,
 | 
					    this.showInternalLoadingWidget = true,
 | 
				
			||||||
    this.delayToShowLoading = const Duration(milliseconds: 750),
 | 
					    this.delayToShowLoading = const Duration(milliseconds: 0),
 | 
				
			||||||
    this.onCallToStripe,
 | 
					    this.onCallToStripe,
 | 
				
			||||||
    this.overrideValidState,
 | 
					    this.overrideValidState,
 | 
				
			||||||
    this.errorText,
 | 
					    this.errorText,
 | 
				
			||||||
@ -53,21 +64,17 @@ class CardTextField extends StatefulWidget {
 | 
				
			|||||||
    this.iconSize,
 | 
					    this.iconSize,
 | 
				
			||||||
    this.cardIconColor,
 | 
					    this.cardIconColor,
 | 
				
			||||||
    this.cardIconErrorColor,
 | 
					    this.cardIconErrorColor,
 | 
				
			||||||
    // this.loadingWidgetLocation = LoadingLocation.rightInside,
 | 
					 | 
				
			||||||
  }) : super(key: key) {
 | 
					  }) : super(key: key) {
 | 
				
			||||||
 | 
					    // Setup logic for the CardTextField
 | 
				
			||||||
 | 
					    // Will assert in debug mode, otherwise will throw `CardTextFieldError` in profile or release
 | 
				
			||||||
    if (stripePublishableKey != null) {
 | 
					    if (stripePublishableKey != null) {
 | 
				
			||||||
      assert(stripePublishableKey!.startsWith('pk_'));
 | 
					      if (!stripePublishableKey!.startsWith('pk_')) {
 | 
				
			||||||
      if (kReleaseMode && !stripePublishableKey!.startsWith('pk_live_')) {
 | 
					        const msg = 'Invalid stripe key, doesn\'t start with "pk_"';
 | 
				
			||||||
        log('StripeNativeCardField: *WARN* You are not using a live publishableKey in production.');
 | 
					        if (kDebugMode) assert(false, msg);
 | 
				
			||||||
      } else if ((kDebugMode || kProfileMode) &&
 | 
					        if (kReleaseMode || kProfileMode) {
 | 
				
			||||||
          stripePublishableKey!.startsWith('pk_live_')) {
 | 
					          throw CardTextFieldError(CardTextFieldErrorType.stripeImplementation,
 | 
				
			||||||
        log('StripeNativeCardField: *WARN* You are using a live stripe key in a debug environment, proceed with caution!');
 | 
					              details: msg);
 | 
				
			||||||
        log('StripeNativeCardField: *WARN* Ideally you should be using your test keys whenever not in production.');
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
      if (onStripeResponse != null) {
 | 
					 | 
				
			||||||
        log('StripeNativeCardField: *ERROR* You provided the onTokenReceived callback, but did not provide a stripePublishableKey.');
 | 
					 | 
				
			||||||
        assert(false);
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -96,7 +103,8 @@ class CardTextField extends StatefulWidget {
 | 
				
			|||||||
  /// Overrides the default box decoration of the text field when there is a validation error
 | 
					  /// Overrides the default box decoration of the text field when there is a validation error
 | 
				
			||||||
  final BoxDecoration? errorBoxDecoration;
 | 
					  final BoxDecoration? errorBoxDecoration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Shown and overrides CircularProgressIndicator() if the request to stripe takes longer than `delayToShowLoading`
 | 
					  /// Shown and overrides `LinearProgressIndicator` if the request to stripe takes longer than `delayToShowLoading`
 | 
				
			||||||
 | 
					  /// Recommended to only override with a `LinearProgressIndicator` or similar widget, or spacing will be messed up
 | 
				
			||||||
  final Widget? loadingWidget;
 | 
					  final Widget? loadingWidget;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Overrides default icon size of the card provider, defaults to `Size(30.0, 20.0)`
 | 
					  /// Overrides default icon size of the card provider, defaults to `Size(30.0, 20.0)`
 | 
				
			||||||
@ -109,7 +117,7 @@ class CardTextField extends StatefulWidget {
 | 
				
			|||||||
  final String? cardIconErrorColor;
 | 
					  final String? cardIconErrorColor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Determines where the loading indicator appears when contacting stripe
 | 
					  /// Determines where the loading indicator appears when contacting stripe
 | 
				
			||||||
  // final LoadingLocation loadingWidgetLocation;
 | 
					  final LoadingLocation loadingWidgetLocation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Default TextStyle
 | 
					  /// Default TextStyle
 | 
				
			||||||
  final TextStyle? textStyle;
 | 
					  final TextStyle? textStyle;
 | 
				
			||||||
@ -122,7 +130,7 @@ class CardTextField extends StatefulWidget {
 | 
				
			|||||||
  /// If null, inherits from the `textStyle`.
 | 
					  /// If null, inherits from the `textStyle`.
 | 
				
			||||||
  final TextStyle? errorTextStyle;
 | 
					  final TextStyle? errorTextStyle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Time to wait until showing the loading indicator when retrieving Stripe token
 | 
					  /// Time to wait until showing the loading indicator when retrieving Stripe token, defaults to 0 milliseconds.
 | 
				
			||||||
  final Duration delayToShowLoading;
 | 
					  final Duration delayToShowLoading;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Whether to show the internal loading widget on calls to Stripe
 | 
					  /// Whether to show the internal loading widget on calls to Stripe
 | 
				
			||||||
@ -138,7 +146,7 @@ class CardTextField extends StatefulWidget {
 | 
				
			|||||||
  final void Function(Map<String, dynamic>)? onStripeResponse;
 | 
					  final void Function(Map<String, dynamic>)? onStripeResponse;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Callback that returns the completed CardDetails object
 | 
					  /// Callback that returns the completed CardDetails object
 | 
				
			||||||
  final void Function(CardDetails)? onCardDetailsComplete;
 | 
					  final void Function(CardDetails)? onValidCardDetails;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Can manually override the ValidState to surface errors returned from Stripe
 | 
					  /// Can manually override the ValidState to surface errors returned from Stripe
 | 
				
			||||||
  final CardDetailsValidState? overrideValidState;
 | 
					  final CardDetailsValidState? overrideValidState;
 | 
				
			||||||
@ -146,14 +154,31 @@ class CardTextField extends StatefulWidget {
 | 
				
			|||||||
  /// Can manually override the errorText displayed to surface errors returned from Stripe
 | 
					  /// Can manually override the errorText displayed to surface errors returned from Stripe
 | 
				
			||||||
  final String? errorText;
 | 
					  final String? errorText;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// GlobalKey used for calling `getStripeToken` in the `CardTextFieldState`
 | 
				
			||||||
 | 
					  // final GlobalKey<CardTextFieldState> _key = GlobalKey<CardTextFieldState>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // CardTextFieldState? get state => _key.currentState;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// Validates the current fields and makes an http request to get the stripe
 | 
				
			||||||
 | 
					  /// token for the `CardDetails` provided. Will return null if the data is not
 | 
				
			||||||
 | 
					  /// complete or does not validate properly.
 | 
				
			||||||
 | 
					  // Future<Map<String, dynamic>?> fetchStripeResponse() async {
 | 
				
			||||||
 | 
					  //   if (kDebugMode && _key.currentState == null) print('Could not fetch Stripe Response, currentState == null');
 | 
				
			||||||
 | 
					  //   return _key.currentState?.getStripeResponse();
 | 
				
			||||||
 | 
					  // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  State<CardTextField> createState() => CardTextFieldState();
 | 
					  State<CardTextField> createState() => CardTextFieldState();
 | 
				
			||||||
 | 
					  // {
 | 
				
			||||||
 | 
					  //   _state = CardTextFieldState();
 | 
				
			||||||
 | 
					  //   return _state;
 | 
				
			||||||
 | 
					  // }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// State Widget for CardTextField
 | 
					/// State Widget for CardTextField
 | 
				
			||||||
/// Should not be used directly, create a
 | 
					/// Should not be used directly, except to
 | 
				
			||||||
/// `CardTextField()` instead.
 | 
					/// create a GlobalKey for directly accessing
 | 
				
			||||||
@visibleForTesting
 | 
					/// the `getStripeResponse` function
 | 
				
			||||||
class CardTextFieldState extends State<CardTextField> {
 | 
					class CardTextFieldState extends State<CardTextField> {
 | 
				
			||||||
  late TextEditingController _cardNumberController;
 | 
					  late TextEditingController _cardNumberController;
 | 
				
			||||||
  late TextEditingController _expirationController;
 | 
					  late TextEditingController _expirationController;
 | 
				
			||||||
@ -373,7 +398,9 @@ class CardTextFieldState extends State<CardTextField> {
 | 
				
			|||||||
              }
 | 
					              }
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            onHorizontalDragEnd: (details) {
 | 
					            onHorizontalDragEnd: (details) {
 | 
				
			||||||
              if (!_isMobile || isWideFormat || details.primaryVelocity == null) {
 | 
					              if (!_isMobile ||
 | 
				
			||||||
 | 
					                  isWideFormat ||
 | 
				
			||||||
 | 
					                  details.primaryVelocity == null) {
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
              }
 | 
					              }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -399,13 +426,33 @@ class CardTextFieldState extends State<CardTextField> {
 | 
				
			|||||||
                    child: SizedBox(
 | 
					                    child: SizedBox(
 | 
				
			||||||
                      width: _internalFieldWidth,
 | 
					                      width: _internalFieldWidth,
 | 
				
			||||||
                      height: widget.height ?? 60.0,
 | 
					                      height: widget.height ?? 60.0,
 | 
				
			||||||
 | 
					                      child: Column(
 | 
				
			||||||
 | 
					                        children: [
 | 
				
			||||||
 | 
					                          if (widget.loadingWidgetLocation ==
 | 
				
			||||||
 | 
					                              LoadingLocation.above)
 | 
				
			||||||
 | 
					                            AnimatedOpacity(
 | 
				
			||||||
 | 
					                              duration: const Duration(milliseconds: 300),
 | 
				
			||||||
 | 
					                              opacity:
 | 
				
			||||||
 | 
					                                  _loading && widget.showInternalLoadingWidget
 | 
				
			||||||
 | 
					                                      ? 1.0
 | 
				
			||||||
 | 
					                                      : 0.0,
 | 
				
			||||||
 | 
					                              child: widget.loadingWidget ??
 | 
				
			||||||
 | 
					                                  const LinearProgressIndicator(),
 | 
				
			||||||
 | 
					                            ),
 | 
				
			||||||
 | 
					                          Padding(
 | 
				
			||||||
 | 
					                            padding: switch (widget.loadingWidgetLocation) {
 | 
				
			||||||
 | 
					                              LoadingLocation.above =>
 | 
				
			||||||
 | 
					                                const EdgeInsets.only(top: 0, bottom: 4.0),
 | 
				
			||||||
 | 
					                              LoadingLocation.below =>
 | 
				
			||||||
 | 
					                                const EdgeInsets.only(top: 4.0, bottom: 0),
 | 
				
			||||||
 | 
					                            },
 | 
				
			||||||
                            child: Row(
 | 
					                            child: Row(
 | 
				
			||||||
                              crossAxisAlignment: CrossAxisAlignment.center,
 | 
					                              crossAxisAlignment: CrossAxisAlignment.center,
 | 
				
			||||||
                              mainAxisAlignment: MainAxisAlignment.start,
 | 
					                              mainAxisAlignment: MainAxisAlignment.start,
 | 
				
			||||||
                              children: [
 | 
					                              children: [
 | 
				
			||||||
                                Padding(
 | 
					                                Padding(
 | 
				
			||||||
                            padding:
 | 
					                                  padding: const EdgeInsets.symmetric(
 | 
				
			||||||
                                const EdgeInsets.symmetric(horizontal: 6.0),
 | 
					                                      horizontal: 6.0),
 | 
				
			||||||
                                  child: CardProviderIcon(
 | 
					                                  child: CardProviderIcon(
 | 
				
			||||||
                                    cardDetails: _cardDetails,
 | 
					                                    cardDetails: _cardDetails,
 | 
				
			||||||
                                    size: widget.iconSize,
 | 
					                                    size: widget.iconSize,
 | 
				
			||||||
@ -445,9 +492,10 @@ class CardTextFieldState extends State<CardTextField> {
 | 
				
			|||||||
                                    },
 | 
					                                    },
 | 
				
			||||||
                                    onChanged: (str) {
 | 
					                                    onChanged: (str) {
 | 
				
			||||||
                                      final numbers = str.replaceAll(' ', '');
 | 
					                                      final numbers = str.replaceAll(' ', '');
 | 
				
			||||||
                                setState(
 | 
					                                      setState(() =>
 | 
				
			||||||
                                    () => _cardDetails.cardNumber = numbers);
 | 
					                                          _cardDetails.cardNumber = numbers);
 | 
				
			||||||
                                if (str.length <= _cardDetails.maxINNLength) {
 | 
					                                      if (str.length <=
 | 
				
			||||||
 | 
					                                          _cardDetails.maxINNLength) {
 | 
				
			||||||
                                        _cardDetails.detectCardProvider();
 | 
					                                        _cardDetails.detectCardProvider();
 | 
				
			||||||
                                      }
 | 
					                                      }
 | 
				
			||||||
                                      if (numbers.length == 16) {
 | 
					                                      if (numbers.length == 16) {
 | 
				
			||||||
@ -479,14 +527,16 @@ class CardTextFieldState extends State<CardTextField> {
 | 
				
			|||||||
                                    // fit: _currentStep == CardEntryStep.number ? FlexFit.loose : FlexFit.tight,
 | 
					                                    // fit: _currentStep == CardEntryStep.number ? FlexFit.loose : FlexFit.tight,
 | 
				
			||||||
                                    child: AnimatedContainer(
 | 
					                                    child: AnimatedContainer(
 | 
				
			||||||
                                      curve: Curves.easeInOut,
 | 
					                                      curve: Curves.easeInOut,
 | 
				
			||||||
                                duration: const Duration(milliseconds: 400),
 | 
					                                      duration:
 | 
				
			||||||
                                constraints:
 | 
					                                          const Duration(milliseconds: 400),
 | 
				
			||||||
                                    _currentStep == CardEntryStep.number
 | 
					                                      constraints: _currentStep ==
 | 
				
			||||||
 | 
					                                              CardEntryStep.number
 | 
				
			||||||
                                          ? BoxConstraints.loose(
 | 
					                                          ? BoxConstraints.loose(
 | 
				
			||||||
                                              Size(_expanderWidthExpanded, 0.0),
 | 
					                                              Size(_expanderWidthExpanded, 0.0),
 | 
				
			||||||
                                            )
 | 
					                                            )
 | 
				
			||||||
                                          : BoxConstraints.tight(
 | 
					                                          : BoxConstraints.tight(
 | 
				
			||||||
                                            Size(_expanderWidthCollapsed, 0.0),
 | 
					                                              Size(
 | 
				
			||||||
 | 
					                                                  _expanderWidthCollapsed, 0.0),
 | 
				
			||||||
                                            ),
 | 
					                                            ),
 | 
				
			||||||
                                    ),
 | 
					                                    ),
 | 
				
			||||||
                                  ),
 | 
					                                  ),
 | 
				
			||||||
@ -499,7 +549,8 @@ class CardTextFieldState extends State<CardTextField> {
 | 
				
			|||||||
                                    children: [
 | 
					                                    children: [
 | 
				
			||||||
                                      // Must manually add hint label because they wont show on mobile with backspace hack
 | 
					                                      // Must manually add hint label because they wont show on mobile with backspace hack
 | 
				
			||||||
                                      if (_isMobile &&
 | 
					                                      if (_isMobile &&
 | 
				
			||||||
                                    _expirationController.text == '\u200b')
 | 
					                                          _expirationController.text ==
 | 
				
			||||||
 | 
					                                              '\u200b')
 | 
				
			||||||
                                        Text('MM/YY', style: _hintTextSyle),
 | 
					                                        Text('MM/YY', style: _hintTextSyle),
 | 
				
			||||||
                                      TextFormField(
 | 
					                                      TextFormField(
 | 
				
			||||||
                                        key: const Key('expiration_field'),
 | 
					                                        key: const Key('expiration_field'),
 | 
				
			||||||
@ -517,33 +568,39 @@ class CardTextFieldState extends State<CardTextField> {
 | 
				
			|||||||
                                        validator: (content) {
 | 
					                                        validator: (content) {
 | 
				
			||||||
                                          if (content == null ||
 | 
					                                          if (content == null ||
 | 
				
			||||||
                                              content.isEmpty ||
 | 
					                                              content.isEmpty ||
 | 
				
			||||||
                                        _isMobile && content == '\u200b') {
 | 
					                                              _isMobile &&
 | 
				
			||||||
 | 
					                                                  content == '\u200b') {
 | 
				
			||||||
                                            return null;
 | 
					                                            return null;
 | 
				
			||||||
                                          }
 | 
					                                          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                          if (_isMobile) {
 | 
					                                          if (_isMobile) {
 | 
				
			||||||
                                            setState(() =>
 | 
					                                            setState(() =>
 | 
				
			||||||
                                                _cardDetails.expirationString =
 | 
					                                                _cardDetails.expirationString =
 | 
				
			||||||
                                              content.replaceAll('\u200b', ''));
 | 
					                                                    content.replaceAll(
 | 
				
			||||||
 | 
					                                                        '\u200b', ''));
 | 
				
			||||||
                                          } else {
 | 
					                                          } else {
 | 
				
			||||||
                                            setState(() => _cardDetails
 | 
					                                            setState(() => _cardDetails
 | 
				
			||||||
                                                .expirationString = content);
 | 
					                                                .expirationString = content);
 | 
				
			||||||
                                          }
 | 
					                                          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                          if (_cardDetails.validState ==
 | 
					                                          if (_cardDetails.validState ==
 | 
				
			||||||
                                        CardDetailsValidState.dateTooEarly) {
 | 
					                                              CardDetailsValidState
 | 
				
			||||||
 | 
					                                                  .dateTooEarly) {
 | 
				
			||||||
                                            _setValidationState(
 | 
					                                            _setValidationState(
 | 
				
			||||||
                                                'Your card\'s expiration date is in the past.');
 | 
					                                                'Your card\'s expiration date is in the past.');
 | 
				
			||||||
                                          } else if (_cardDetails.validState ==
 | 
					                                          } else if (_cardDetails.validState ==
 | 
				
			||||||
                                        CardDetailsValidState.dateTooLate) {
 | 
					                                              CardDetailsValidState
 | 
				
			||||||
 | 
					                                                  .dateTooLate) {
 | 
				
			||||||
                                            _setValidationState(
 | 
					                                            _setValidationState(
 | 
				
			||||||
                                                'Your card\'s expiration year is invalid.');
 | 
					                                                'Your card\'s expiration year is invalid.');
 | 
				
			||||||
                                          } else if (_cardDetails.validState ==
 | 
					                                          } else if (_cardDetails.validState ==
 | 
				
			||||||
                                        CardDetailsValidState.missingDate) {
 | 
					                                              CardDetailsValidState
 | 
				
			||||||
 | 
					                                                  .missingDate) {
 | 
				
			||||||
                                            _setValidationState(
 | 
					                                            _setValidationState(
 | 
				
			||||||
                                                'You must include your card\'s expiration date.');
 | 
					                                                'You must include your card\'s expiration date.');
 | 
				
			||||||
                                          } else if (_cardDetails.validState ==
 | 
					                                          } else if (_cardDetails.validState ==
 | 
				
			||||||
                                        CardDetailsValidState.invalidMonth) {
 | 
					                                              CardDetailsValidState
 | 
				
			||||||
 | 
					                                                  .invalidMonth) {
 | 
				
			||||||
                                            _setValidationState(
 | 
					                                            _setValidationState(
 | 
				
			||||||
                                                'Your card\'s expiration month is invalid.');
 | 
					                                                'Your card\'s expiration month is invalid.');
 | 
				
			||||||
                                          }
 | 
					                                          }
 | 
				
			||||||
@ -554,12 +611,12 @@ class CardTextFieldState extends State<CardTextField> {
 | 
				
			|||||||
                                            if (str.isEmpty) {
 | 
					                                            if (str.isEmpty) {
 | 
				
			||||||
                                              _backspacePressed();
 | 
					                                              _backspacePressed();
 | 
				
			||||||
                                            }
 | 
					                                            }
 | 
				
			||||||
                                      setState(() =>
 | 
					                                            setState(() => _cardDetails
 | 
				
			||||||
                                          _cardDetails.expirationString =
 | 
					                                                    .expirationString =
 | 
				
			||||||
                                                str.replaceAll('\u200b', ''));
 | 
					                                                str.replaceAll('\u200b', ''));
 | 
				
			||||||
                                          } else {
 | 
					                                          } else {
 | 
				
			||||||
                                      setState(() =>
 | 
					                                            setState(() => _cardDetails
 | 
				
			||||||
                                          _cardDetails.expirationString = str);
 | 
					                                                .expirationString = str);
 | 
				
			||||||
                                          }
 | 
					                                          }
 | 
				
			||||||
                                          if (str.length == 5) {
 | 
					                                          if (str.length == 5) {
 | 
				
			||||||
                                            _currentCardEntryStepController
 | 
					                                            _currentCardEntryStepController
 | 
				
			||||||
@ -592,7 +649,8 @@ class CardTextFieldState extends State<CardTextField> {
 | 
				
			|||||||
                                    alignment: Alignment.centerLeft,
 | 
					                                    alignment: Alignment.centerLeft,
 | 
				
			||||||
                                    children: [
 | 
					                                    children: [
 | 
				
			||||||
                                      if (_isMobile &&
 | 
					                                      if (_isMobile &&
 | 
				
			||||||
                                    _securityCodeController.text == '\u200b')
 | 
					                                          _securityCodeController.text ==
 | 
				
			||||||
 | 
					                                              '\u200b')
 | 
				
			||||||
                                        Text(
 | 
					                                        Text(
 | 
				
			||||||
                                          'CVC',
 | 
					                                          'CVC',
 | 
				
			||||||
                                          style: _hintTextSyle,
 | 
					                                          style: _hintTextSyle,
 | 
				
			||||||
@ -611,24 +669,29 @@ class CardTextFieldState extends State<CardTextField> {
 | 
				
			|||||||
                                        validator: (content) {
 | 
					                                        validator: (content) {
 | 
				
			||||||
                                          if (content == null ||
 | 
					                                          if (content == null ||
 | 
				
			||||||
                                              content.isEmpty ||
 | 
					                                              content.isEmpty ||
 | 
				
			||||||
                                        _isMobile && content == '\u200b') {
 | 
					                                              _isMobile &&
 | 
				
			||||||
 | 
					                                                  content == '\u200b') {
 | 
				
			||||||
                                            return null;
 | 
					                                            return null;
 | 
				
			||||||
                                          }
 | 
					                                          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                          if (_isMobile) {
 | 
					                                          if (_isMobile) {
 | 
				
			||||||
                                      setState(() => _cardDetails.securityCode =
 | 
					 | 
				
			||||||
                                          content.replaceAll('\u200b', ''));
 | 
					 | 
				
			||||||
                                    } else {
 | 
					 | 
				
			||||||
                                            setState(() =>
 | 
					                                            setState(() =>
 | 
				
			||||||
                                          _cardDetails.securityCode = content);
 | 
					                                                _cardDetails.securityCode =
 | 
				
			||||||
 | 
					                                                    content.replaceAll(
 | 
				
			||||||
 | 
					                                                        '\u200b', ''));
 | 
				
			||||||
 | 
					                                          } else {
 | 
				
			||||||
 | 
					                                            setState(() => _cardDetails
 | 
				
			||||||
 | 
					                                                .securityCode = content);
 | 
				
			||||||
                                          }
 | 
					                                          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                          if (_cardDetails.validState ==
 | 
					                                          if (_cardDetails.validState ==
 | 
				
			||||||
                                        CardDetailsValidState.invalidCVC) {
 | 
					                                              CardDetailsValidState
 | 
				
			||||||
 | 
					                                                  .invalidCVC) {
 | 
				
			||||||
                                            _setValidationState(
 | 
					                                            _setValidationState(
 | 
				
			||||||
                                                'Your card\'s security code is invalid.');
 | 
					                                                'Your card\'s security code is invalid.');
 | 
				
			||||||
                                          } else if (_cardDetails.validState ==
 | 
					                                          } else if (_cardDetails.validState ==
 | 
				
			||||||
                                        CardDetailsValidState.missingCVC) {
 | 
					                                              CardDetailsValidState
 | 
				
			||||||
 | 
					                                                  .missingCVC) {
 | 
				
			||||||
                                            _setValidationState(
 | 
					                                            _setValidationState(
 | 
				
			||||||
                                                'Your card\'s security code is incomplete.');
 | 
					                                                'Your card\'s security code is incomplete.');
 | 
				
			||||||
                                          }
 | 
					                                          }
 | 
				
			||||||
@ -642,16 +705,17 @@ class CardTextFieldState extends State<CardTextField> {
 | 
				
			|||||||
                                            if (str.isEmpty) {
 | 
					                                            if (str.isEmpty) {
 | 
				
			||||||
                                              _backspacePressed();
 | 
					                                              _backspacePressed();
 | 
				
			||||||
                                            }
 | 
					                                            }
 | 
				
			||||||
                                      setState(() =>
 | 
					                                            setState(() => _cardDetails
 | 
				
			||||||
                                          _cardDetails.expirationString =
 | 
					                                                    .expirationString =
 | 
				
			||||||
                                                str.replaceAll('\u200b', ''));
 | 
					                                                str.replaceAll('\u200b', ''));
 | 
				
			||||||
                                          } else {
 | 
					                                          } else {
 | 
				
			||||||
                                      setState(() =>
 | 
					                                            setState(() => _cardDetails
 | 
				
			||||||
                                          _cardDetails.expirationString = str);
 | 
					                                                .expirationString = str);
 | 
				
			||||||
                                          }
 | 
					                                          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                          if (str.length ==
 | 
					                                          if (str.length ==
 | 
				
			||||||
                                        _cardDetails.provider?.cvcLength) {
 | 
					                                              _cardDetails
 | 
				
			||||||
 | 
					                                                  .provider?.cvcLength) {
 | 
				
			||||||
                                            _currentCardEntryStepController
 | 
					                                            _currentCardEntryStepController
 | 
				
			||||||
                                                .add(CardEntryStep.postal);
 | 
					                                                .add(CardEntryStep.postal);
 | 
				
			||||||
                                          }
 | 
					                                          }
 | 
				
			||||||
@ -660,7 +724,8 @@ class CardTextFieldState extends State<CardTextField> {
 | 
				
			|||||||
                                          LengthLimitingTextInputFormatter(
 | 
					                                          LengthLimitingTextInputFormatter(
 | 
				
			||||||
                                              _cardDetails.provider == null
 | 
					                                              _cardDetails.provider == null
 | 
				
			||||||
                                                  ? 4
 | 
					                                                  ? 4
 | 
				
			||||||
                                            : _cardDetails.provider!.cvcLength),
 | 
					                                                  : _cardDetails
 | 
				
			||||||
 | 
					                                                      .provider!.cvcLength),
 | 
				
			||||||
                                          FilteringTextInputFormatter.allow(
 | 
					                                          FilteringTextInputFormatter.allow(
 | 
				
			||||||
                                              RegExp('[0-9]')),
 | 
					                                              RegExp('[0-9]')),
 | 
				
			||||||
                                        ],
 | 
					                                        ],
 | 
				
			||||||
@ -681,7 +746,8 @@ class CardTextFieldState extends State<CardTextField> {
 | 
				
			|||||||
                                    alignment: Alignment.centerLeft,
 | 
					                                    alignment: Alignment.centerLeft,
 | 
				
			||||||
                                    children: [
 | 
					                                    children: [
 | 
				
			||||||
                                      if (_isMobile &&
 | 
					                                      if (_isMobile &&
 | 
				
			||||||
                                    _postalCodeController.text == '\u200b')
 | 
					                                          _postalCodeController.text ==
 | 
				
			||||||
 | 
					                                              '\u200b')
 | 
				
			||||||
                                        Text(
 | 
					                                        Text(
 | 
				
			||||||
                                          'Postal Code',
 | 
					                                          'Postal Code',
 | 
				
			||||||
                                          style: _hintTextSyle,
 | 
					                                          style: _hintTextSyle,
 | 
				
			||||||
@ -700,24 +766,29 @@ class CardTextFieldState extends State<CardTextField> {
 | 
				
			|||||||
                                        validator: (content) {
 | 
					                                        validator: (content) {
 | 
				
			||||||
                                          if (content == null ||
 | 
					                                          if (content == null ||
 | 
				
			||||||
                                              content.isEmpty ||
 | 
					                                              content.isEmpty ||
 | 
				
			||||||
                                        _isMobile && content == '\u200b') {
 | 
					                                              _isMobile &&
 | 
				
			||||||
 | 
					                                                  content == '\u200b') {
 | 
				
			||||||
                                            return null;
 | 
					                                            return null;
 | 
				
			||||||
                                          }
 | 
					                                          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                          if (_isMobile) {
 | 
					                                          if (_isMobile) {
 | 
				
			||||||
                                      setState(() => _cardDetails.postalCode =
 | 
					 | 
				
			||||||
                                          content.replaceAll('\u200b', ''));
 | 
					 | 
				
			||||||
                                    } else {
 | 
					 | 
				
			||||||
                                            setState(() =>
 | 
					                                            setState(() =>
 | 
				
			||||||
                                          _cardDetails.postalCode = content);
 | 
					                                                _cardDetails.postalCode =
 | 
				
			||||||
 | 
					                                                    content.replaceAll(
 | 
				
			||||||
 | 
					                                                        '\u200b', ''));
 | 
				
			||||||
 | 
					                                          } else {
 | 
				
			||||||
 | 
					                                            setState(() => _cardDetails
 | 
				
			||||||
 | 
					                                                .postalCode = content);
 | 
				
			||||||
                                          }
 | 
					                                          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                                          if (_cardDetails.validState ==
 | 
					                                          if (_cardDetails.validState ==
 | 
				
			||||||
                                        CardDetailsValidState.invalidZip) {
 | 
					                                              CardDetailsValidState
 | 
				
			||||||
 | 
					                                                  .invalidZip) {
 | 
				
			||||||
                                            _setValidationState(
 | 
					                                            _setValidationState(
 | 
				
			||||||
                                                'The postal code you entered is not correct.');
 | 
					                                                'The postal code you entered is not correct.');
 | 
				
			||||||
                                          } else if (_cardDetails.validState ==
 | 
					                                          } else if (_cardDetails.validState ==
 | 
				
			||||||
                                        CardDetailsValidState.missingZip) {
 | 
					                                              CardDetailsValidState
 | 
				
			||||||
 | 
					                                                  .missingZip) {
 | 
				
			||||||
                                            _setValidationState(
 | 
					                                            _setValidationState(
 | 
				
			||||||
                                                'You must enter your card\'s postal code.');
 | 
					                                                'You must enter your card\'s postal code.');
 | 
				
			||||||
                                          }
 | 
					                                          }
 | 
				
			||||||
@ -728,11 +799,12 @@ class CardTextFieldState extends State<CardTextField> {
 | 
				
			|||||||
                                            if (str.isEmpty) {
 | 
					                                            if (str.isEmpty) {
 | 
				
			||||||
                                              _backspacePressed();
 | 
					                                              _backspacePressed();
 | 
				
			||||||
                                            }
 | 
					                                            }
 | 
				
			||||||
                                      setState(() => _cardDetails.postalCode =
 | 
					                                            setState(() => _cardDetails
 | 
				
			||||||
 | 
					                                                    .postalCode =
 | 
				
			||||||
                                                str.replaceAll('\u200b', ''));
 | 
					                                                str.replaceAll('\u200b', ''));
 | 
				
			||||||
                                          } else {
 | 
					                                          } else {
 | 
				
			||||||
                                      setState(
 | 
					                                            setState(() =>
 | 
				
			||||||
                                          () => _cardDetails.postalCode = str);
 | 
					                                                _cardDetails.postalCode = str);
 | 
				
			||||||
                                          }
 | 
					                                          }
 | 
				
			||||||
                                        },
 | 
					                                        },
 | 
				
			||||||
                                        textInputAction: TextInputAction.done,
 | 
					                                        textInputAction: TextInputAction.done,
 | 
				
			||||||
@ -741,7 +813,8 @@ class CardTextFieldState extends State<CardTextField> {
 | 
				
			|||||||
                                        },
 | 
					                                        },
 | 
				
			||||||
                                        decoration: InputDecoration(
 | 
					                                        decoration: InputDecoration(
 | 
				
			||||||
                                          contentPadding: EdgeInsets.zero,
 | 
					                                          contentPadding: EdgeInsets.zero,
 | 
				
			||||||
                                    hintText: _isMobile ? '' : 'Postal Code',
 | 
					                                          hintText:
 | 
				
			||||||
 | 
					                                              _isMobile ? '' : 'Postal Code',
 | 
				
			||||||
                                          hintStyle: _hintTextSyle,
 | 
					                                          hintStyle: _hintTextSyle,
 | 
				
			||||||
                                          fillColor: Colors.transparent,
 | 
					                                          fillColor: Colors.transparent,
 | 
				
			||||||
                                          border: InputBorder.none,
 | 
					                                          border: InputBorder.none,
 | 
				
			||||||
@ -750,6 +823,11 @@ class CardTextFieldState extends State<CardTextField> {
 | 
				
			|||||||
                                    ],
 | 
					                                    ],
 | 
				
			||||||
                                  ),
 | 
					                                  ),
 | 
				
			||||||
                                ),
 | 
					                                ),
 | 
				
			||||||
 | 
					                              ],
 | 
				
			||||||
 | 
					                            ),
 | 
				
			||||||
 | 
					                          ),
 | 
				
			||||||
 | 
					                          if (widget.loadingWidgetLocation ==
 | 
				
			||||||
 | 
					                              LoadingLocation.below)
 | 
				
			||||||
                            AnimatedOpacity(
 | 
					                            AnimatedOpacity(
 | 
				
			||||||
                              duration: const Duration(milliseconds: 300),
 | 
					                              duration: const Duration(milliseconds: 300),
 | 
				
			||||||
                              opacity:
 | 
					                              opacity:
 | 
				
			||||||
@ -757,7 +835,7 @@ class CardTextFieldState extends State<CardTextField> {
 | 
				
			|||||||
                                      ? 1.0
 | 
					                                      ? 1.0
 | 
				
			||||||
                                      : 0.0,
 | 
					                                      : 0.0,
 | 
				
			||||||
                              child: widget.loadingWidget ??
 | 
					                              child: widget.loadingWidget ??
 | 
				
			||||||
                                const CircularProgressIndicator(),
 | 
					                                  const LinearProgressIndicator(),
 | 
				
			||||||
                            ),
 | 
					                            ),
 | 
				
			||||||
                        ],
 | 
					                        ],
 | 
				
			||||||
                      ),
 | 
					                      ),
 | 
				
			||||||
@ -784,22 +862,31 @@ class CardTextFieldState extends State<CardTextField> {
 | 
				
			|||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<void> _postalFieldSubmitted() async {
 | 
					  // Makes an http call to stripe API with provided card credentials and returns the result
 | 
				
			||||||
 | 
					  Future<Map<String, dynamic>?> getStripeResponse() async {
 | 
				
			||||||
    _validateFields();
 | 
					    _validateFields();
 | 
				
			||||||
    if (_cardDetails.isComplete) {
 | 
					 | 
				
			||||||
      if (widget.onCardDetailsComplete != null) {
 | 
					 | 
				
			||||||
        widget.onCardDetailsComplete!(_cardDetails);
 | 
					 | 
				
			||||||
      } else if (widget.onStripeResponse != null) {
 | 
					 | 
				
			||||||
        bool returned = false;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!_cardDetails.isComplete) {
 | 
				
			||||||
 | 
					      if (kDebugMode)
 | 
				
			||||||
 | 
					        print(
 | 
				
			||||||
 | 
					            'Could not get stripe response, card details not complete: $_cardDetails');
 | 
				
			||||||
 | 
					      return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (widget.onCallToStripe != null) widget.onCallToStripe!();
 | 
				
			||||||
 | 
					    if (widget.stripePublishableKey == null) {
 | 
				
			||||||
 | 
					      if (kDebugMode)
 | 
				
			||||||
 | 
					        print(
 | 
				
			||||||
 | 
					            '***ERROR tried calling `getStripeToken()` but no stripe key provided');
 | 
				
			||||||
 | 
					      return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool returned = false;
 | 
				
			||||||
    Future.delayed(
 | 
					    Future.delayed(
 | 
				
			||||||
          const Duration(milliseconds: 750),
 | 
					      widget.delayToShowLoading,
 | 
				
			||||||
      () => returned ? null : setState(() => _loading = true),
 | 
					      () => returned ? null : setState(() => _loading = true),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const stripeCardUrl = 'https://api.stripe.com/v1/tokens';
 | 
					    const stripeCardUrl = 'https://api.stripe.com/v1/tokens';
 | 
				
			||||||
        // Callback that stripe call is being made
 | 
					 | 
				
			||||||
        if (widget.onCallToStripe != null) widget.onCallToStripe!();
 | 
					 | 
				
			||||||
    final response = await http.post(
 | 
					    final response = await http.post(
 | 
				
			||||||
      Uri.parse(stripeCardUrl),
 | 
					      Uri.parse(stripeCardUrl),
 | 
				
			||||||
      body: {
 | 
					      body: {
 | 
				
			||||||
@ -814,9 +901,22 @@ class CardTextFieldState extends State<CardTextField> {
 | 
				
			|||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    returned = true;
 | 
					    returned = true;
 | 
				
			||||||
        final jsonBody = jsonDecode(response.body);
 | 
					    final Map<String, dynamic> jsonBody = jsonDecode(response.body);
 | 
				
			||||||
 | 
					    if (_loading) setState(() => _loading = false);
 | 
				
			||||||
 | 
					    return jsonBody;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        widget.onStripeResponse!(jsonBody);
 | 
					  Future<void> _postalFieldSubmitted() async {
 | 
				
			||||||
 | 
					    _validateFields();
 | 
				
			||||||
 | 
					    if (_cardDetails.isComplete) {
 | 
				
			||||||
 | 
					      if (widget.onValidCardDetails != null) {
 | 
				
			||||||
 | 
					        widget.onValidCardDetails!(_cardDetails);
 | 
				
			||||||
 | 
					      } else if (widget.onStripeResponse != null) {
 | 
				
			||||||
 | 
					        // Callback that stripe call is being made
 | 
				
			||||||
 | 
					        if (widget.onCallToStripe != null) widget.onCallToStripe!();
 | 
				
			||||||
 | 
					        final jsonBody = await getStripeResponse();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (jsonBody != null) widget.onStripeResponse!(jsonBody);
 | 
				
			||||||
        if (_loading) setState(() => _loading = false);
 | 
					        if (_loading) setState(() => _loading = false);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,6 @@
 | 
				
			|||||||
name: stripe_native_card_field
 | 
					name: stripe_native_card_field
 | 
				
			||||||
description: A native flutter implementation of the elegant Stripe Card Field.
 | 
					description: A native flutter implementation of the elegant Stripe Card Field.
 | 
				
			||||||
version: 0.0.5
 | 
					version: 0.0.6
 | 
				
			||||||
repository: https://git.fosscat.com/n8r/stripe_native_card_field
 | 
					repository: https://git.fosscat.com/n8r/stripe_native_card_field
 | 
				
			||||||
 | 
					
 | 
				
			||||||
environment:
 | 
					environment:
 | 
				
			||||||
 | 
				
			|||||||
@ -18,7 +18,7 @@ void main() {
 | 
				
			|||||||
      CardDetails? details;
 | 
					      CardDetails? details;
 | 
				
			||||||
      final cardField = CardTextField(
 | 
					      final cardField = CardTextField(
 | 
				
			||||||
        width: width,
 | 
					        width: width,
 | 
				
			||||||
        onCardDetailsComplete: (cd) => details = cd,
 | 
					        onValidCardDetails: (cd) => details = cd,
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
      await tester.pumpWidget(baseCardFieldWidget(cardField));
 | 
					      await tester.pumpWidget(baseCardFieldWidget(cardField));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -110,7 +110,7 @@ void main() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    final cardField = CardTextField(
 | 
					    final cardField = CardTextField(
 | 
				
			||||||
      width: width,
 | 
					      width: width,
 | 
				
			||||||
      onCardDetailsComplete: (cd) => details = cd,
 | 
					      onValidCardDetails: (cd) => details = cd,
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    await tester.pumpWidget(baseCardFieldWidget(cardField));
 | 
					    await tester.pumpWidget(baseCardFieldWidget(cardField));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user