From 4b0e4a98de1914c8d96c09f4f33a3ed664357f74 Mon Sep 17 00:00:00 2001
From: Nathan Anderson <nathananderson98@gmail.com>
Date: Wed, 22 Nov 2023 10:52:52 -0700
Subject: [PATCH] Added web fix for platform call and static analysis fixes

---
 example/lib/dark_customization.dart     |  11 +-
 example/lib/main.dart                   |   8 +-
 lib/card_details.dart                   |  28 ++-
 lib/card_provider_icon.dart             |  11 +-
 lib/stripe_native_card_field.dart       | 321 ++++++++++++++++--------
 test/stripe_native_card_field_test.dart |  34 ++-
 6 files changed, 278 insertions(+), 135 deletions(-)

diff --git a/example/lib/dark_customization.dart b/example/lib/dark_customization.dart
index 623f3cf..b59975d 100644
--- a/example/lib/dark_customization.dart
+++ b/example/lib/dark_customization.dart
@@ -1,4 +1,3 @@
-
 import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
 import 'package:stripe_native_card_field/card_details.dart';
@@ -19,7 +18,8 @@ class MyApp extends StatelessWidget {
       title: 'Native Stripe Field Demo',
       theme: ThemeData(
         brightness: Brightness.dark,
-        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple, brightness: Brightness.dark),
+        colorScheme: ColorScheme.fromSeed(
+            seedColor: Colors.deepPurple, brightness: Brightness.dark),
         useMaterial3: true,
       ),
       home: const MyHomePage(title: 'Flutter Demo Home Page'),
@@ -66,9 +66,10 @@ class _MyHomePageState extends State<MyHomePage> {
                   print(details);
                 }
               },
-              textStyle: TextStyle(fontFamily: 'Lato', color: Colors.tealAccent),
-              hintTextStyle: TextStyle(fontFamily: 'Lato', color: Colors.teal),
-              errorTextStyle: TextStyle(color: Colors.purpleAccent),
+              textStyle:
+                  const TextStyle(fontFamily: 'Lato', color: Colors.tealAccent),
+              hintTextStyle: const TextStyle(fontFamily: 'Lato', color: Colors.teal),
+              errorTextStyle: const TextStyle(color: Colors.purpleAccent),
               boxDecoration: BoxDecoration(
                 color: Colors.black54,
                 border: Border.all(
diff --git a/example/lib/main.dart b/example/lib/main.dart
index 6fa38c3..20b0c67 100644
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -41,7 +41,7 @@ class _MyHomePageState extends State<MyHomePage> {
   @override
   Widget build(BuildContext context) {
     return Scaffold(
-         body: Center(
+      body: Center(
         child: Column(
           mainAxisAlignment: MainAxisAlignment.center,
           children: <Widget>[
@@ -58,12 +58,6 @@ class _MyHomePageState extends State<MyHomePage> {
                   print(details);
                 }
               },
-              // textStyle: TextStyle(fontSize: 24.0),
-              // cardFieldWidth: 260,
-              // expFieldWidth: 100.0,
-              // securityFieldWidth: 60.0,
-              // postalFieldWidth: 130.0,
-              // iconSize: Size(50.0, 35.0),
               overrideValidState: state,
               errorText: errorText,
             ),
diff --git a/lib/card_details.dart b/lib/card_details.dart
index 7e94af8..f97ef78 100644
--- a/lib/card_details.dart
+++ b/lib/card_details.dart
@@ -18,7 +18,11 @@ class CardDetails {
   /// Sets every field to null, a default
   /// `CardDetails` when nothing has been entered.
   factory CardDetails.blank() {
-    return CardDetails(cardNumber: null, securityCode: null, expirationString: null, postalCode: null);
+    return CardDetails(
+        cardNumber: null,
+        securityCode: null,
+        expirationString: null,
+        postalCode: null);
   }
 
   /// Returns the CardNumber as a `String` with the spaces removed.
@@ -51,8 +55,9 @@ class CardDetails {
   /// Returns true if `_cardNumber` is null, or
   /// if the _cardNumber matches the detected `provider`'s
   /// card lenght, defaulting to 16.
-  bool get cardNumberFilled =>
-      _cardNumber == null ? false : (provider?.cardLength ?? 16) == _cardNumber!.replaceAll(' ', '').length;
+  bool get cardNumberFilled => _cardNumber == null
+      ? false
+      : (provider?.cardLength ?? 16) == _cardNumber!.replaceAll(' ', '').length;
 
   /// Returns true if all details are complete and valid
   /// otherwise, return false.
@@ -78,7 +83,10 @@ class CardDetails {
       }
 
       _lastCheckHash = currentHash;
-      if (_cardNumber == null && expirationString == null && securityCode == null && postalCode == null) {
+      if (_cardNumber == null &&
+          expirationString == null &&
+          securityCode == null &&
+          postalCode == null) {
         _complete = false;
         _validState = CardDetailsValidState.blank;
         return;
@@ -111,7 +119,8 @@ class CardDetails {
         _validState = CardDetailsValidState.missingDate;
         return;
       }
-      final month = int.parse(expSplits.first[0] == '0' ? expSplits.first[1] : expSplits.first);
+      final month = int.parse(
+          expSplits.first[0] == '0' ? expSplits.first[1] : expSplits.first);
       if (month < 1 || month > 12) {
         _complete = false;
         _validState = CardDetailsValidState.invalidMonth;
@@ -123,7 +132,8 @@ class CardDetails {
         _complete = false;
         _validState = CardDetailsValidState.dateTooEarly;
         return;
-      } else if (date.isAfter(DateTime.now().add(const Duration(days: 365 * 50)))) {
+      } else if (date
+          .isAfter(DateTime.now().add(const Duration(days: 365 * 50)))) {
         _complete = false;
         _validState = CardDetailsValidState.dateTooLate;
         return;
@@ -282,7 +292,11 @@ class CardProvider {
   int cvcLength;
 
   CardProvider(
-      {required this.id, required this.cardLength, required this.cvcLength, this.innValidNums, this.innValidRanges}) {
+      {required this.id,
+      required this.cardLength,
+      required this.cvcLength,
+      this.innValidNums,
+      this.innValidRanges}) {
     // Must provide one or the other
     assert(innValidNums != null || innValidRanges != null);
     // Do not provide empty list of valid nums
diff --git a/lib/card_provider_icon.dart b/lib/card_provider_icon.dart
index 98f2e3d..a8a5052 100644
--- a/lib/card_provider_icon.dart
+++ b/lib/card_provider_icon.dart
@@ -7,7 +7,12 @@ import 'package:flutter_svg/flutter_svg.dart';
 ///
 /// To see a list of supported card providers, see `CardDetails.provider`.
 class CardProviderIcon extends StatefulWidget {
-  const CardProviderIcon({required this.cardDetails, this.size, this.defaultCardColor, this.errorCardColor, super.key});
+  const CardProviderIcon(
+      {required this.cardDetails,
+      this.size,
+      this.defaultCardColor,
+      this.errorCardColor,
+      super.key});
 
   final CardDetails? cardDetails;
   final Size? size;
@@ -29,9 +34,9 @@ class _CardProviderIconState extends State<CardProviderIcon> {
 
     cardProviderSvg = {
       'credit-card':
-          '<svg width="24" height="24" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7 15C7.55228 15 8 14.5523 8 14C8 13.4477 7.55228 13 7 13C6.44772 13 6 13.4477 6 14C6 14.5523 6.44772 15 7 15Z" fill="${defaultCardColor}" stroke="${defaultCardColor}" stroke-linecap="round" stroke-linejoin="round"/><path d="M2 9V5.6C2 5.26863 2.26863 5 2.6 5H21.4C21.7314 5 22 5.26863 22 5.6V9M2 9V18.4C2 18.7314 2.26863 19 2.6 19H21.4C21.7314 19 22 18.7314 22 18.4V9M2 9H22" stroke="${defaultCardColor}" stroke-linecap="round" stroke-linejoin="round"/></svg>',
+          '<svg width="24" height="24" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7 15C7.55228 15 8 14.5523 8 14C8 13.4477 7.55228 13 7 13C6.44772 13 6 13.4477 6 14C6 14.5523 6.44772 15 7 15Z" fill="$defaultCardColor" stroke="$defaultCardColor" stroke-linecap="round" stroke-linejoin="round"/><path d="M2 9V5.6C2 5.26863 2.26863 5 2.6 5H21.4C21.7314 5 22 5.26863 22 5.6V9M2 9V18.4C2 18.7314 2.26863 19 2.6 19H21.4C21.7314 19 22 18.7314 22 18.4V9M2 9H22" stroke="$defaultCardColor" stroke-linecap="round" stroke-linejoin="round"/></svg>',
       'error':
-          '<svg width="24" height="24" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M3 3L21 21" stroke="${errorCardColor}" stroke-linecap="round" stroke-linejoin="round"/><path d="M7 15C7.55228 15 8 14.5523 8 14C8 13.4477 7.55228 13 7 13C6.44772 13 6 13.4477 6 14C6 14.5523 6.44772 15 7 15Z" fill="${errorCardColor}" stroke="${errorCardColor}" stroke-linecap="round" stroke-linejoin="round"/><path d="M18.5 19H2.6C2.26863 19 2 18.7314 2 18.4V9H8.5" stroke="${errorCardColor}" stroke-linecap="round" stroke-linejoin="round"/><path d="M2 9V5.6C2 5.26863 2.26863 5 2.6 5H4.5" stroke="${errorCardColor}" stroke-linecap="round" stroke-linejoin="round"/><path d="M14 9H22V17" stroke="${errorCardColor}" stroke-linecap="round" stroke-linejoin="round"/><path d="M22 9V5.6C22 5.26863 21.7314 5 21.4 5H10" stroke="${errorCardColor}" stroke-linecap="round" stroke-linejoin="round"/></svg>',
+          '<svg width="24" height="24" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M3 3L21 21" stroke="$errorCardColor" stroke-linecap="round" stroke-linejoin="round"/><path d="M7 15C7.55228 15 8 14.5523 8 14C8 13.4477 7.55228 13 7 13C6.44772 13 6 13.4477 6 14C6 14.5523 6.44772 15 7 15Z" fill="$errorCardColor" stroke="$errorCardColor" stroke-linecap="round" stroke-linejoin="round"/><path d="M18.5 19H2.6C2.26863 19 2 18.7314 2 18.4V9H8.5" stroke="$errorCardColor" stroke-linecap="round" stroke-linejoin="round"/><path d="M2 9V5.6C2 5.26863 2.26863 5 2.6 5H4.5" stroke="$errorCardColor" stroke-linecap="round" stroke-linejoin="round"/><path d="M14 9H22V17" stroke="$errorCardColor" stroke-linecap="round" stroke-linejoin="round"/><path d="M22 9V5.6C22 5.26863 21.7314 5 21.4 5H10" stroke="$errorCardColor" stroke-linecap="round" stroke-linejoin="round"/></svg>',
       CardProviderID.discoverCard.name:
           '<svg height="500" viewBox="0 0 780 500" width="780" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd"><path d="m54.992 0c-30.365 0-54.992 24.63-54.992 55.004v390.992c0 30.38 24.619 55.004 54.992 55.004h670.016c30.365 0 54.992-24.63 54.992-55.004v-390.992c0-30.38-24.619-55.004-54.992-55.004z" fill="#4d4d4d"/><path d="m327.152 161.893c8.837 0 16.248 1.784 25.268 6.09v22.751c-8.544-7.863-15.955-11.154-25.756-11.154-19.264 0-34.414 15.015-34.414 34.05 0 20.075 14.681 34.196 35.37 34.196 9.312 0 16.586-3.12 24.8-10.857v22.763c-9.341 4.14-16.911 5.776-25.756 5.776-31.278 0-55.582-22.596-55.582-51.737 0-28.826 24.951-51.878 56.07-51.878zm-97.113.627c11.546 0 22.11 3.72 30.943 10.994l-10.748 13.248c-5.35-5.646-10.41-8.028-16.564-8.028-8.853 0-15.3 4.745-15.3 10.989 0 5.354 3.619 8.188 15.944 12.482 23.365 8.044 30.29 15.176 30.29 30.926 0 19.193-14.976 32.553-36.32 32.553-15.63 0-26.994-5.795-36.458-18.872l13.268-12.03c4.73 8.61 12.622 13.222 22.42 13.222 9.163 0 15.947-5.952 15.947-13.984 0-4.164-2.055-7.734-6.158-10.258-2.066-1.195-6.158-2.977-14.2-5.647-19.291-6.538-25.91-13.527-25.91-27.185 0-16.225 14.214-28.41 32.846-28.41zm234.723 1.728h22.437l28.084 66.592 28.446-66.592h22.267l-45.494 101.686h-11.053zm-397.348.152h30.15c33.312 0 56.534 20.382 56.534 49.641 0 14.59-7.104 28.696-19.118 38.057-10.108 7.901-21.626 11.445-37.574 11.445h-29.992zm96.135 0h20.54v99.143h-20.54zm411.734 0h58.252v16.8h-37.725v22.005h36.336v16.791h-36.336v26.762h37.726v16.785h-58.252v-99.143zm71.858 0h30.455c23.69 0 37.265 10.71 37.265 29.272 0 15.18-8.514 25.14-23.986 28.105l33.148 41.766h-25.26l-28.429-39.828h-2.678v39.828h-20.515zm20.515 15.616v30.025h6.002c13.117 0 20.069-5.362 20.069-15.328 0-9.648-6.954-14.697-19.745-14.697zm-579.716 1.183v65.559h5.512c13.273 0 21.656-2.394 28.11-7.88 7.103-5.955 11.376-15.465 11.376-24.98 0-9.499-4.273-18.725-11.376-24.681-6.785-5.78-14.837-8.018-28.11-8.018z" fill="#fff"/><path d="m415.13 161.21c30.941 0 56.022 23.58 56.022 52.709v.033c0 29.13-25.081 52.742-56.021 52.742s-56.022-23.613-56.022-52.742v-.033c0-29.13 25.082-52.71 56.022-52.71zm364.85 127.15c-26.05 18.33-221.08 149.34-558.75 212.62h503.76c30.365 0 54.992-24.63 54.992-55.004v-157.62z" fill="#f47216"/></g></svg>',
       CardProviderID.americanExpress.name:
diff --git a/lib/stripe_native_card_field.dart b/lib/stripe_native_card_field.dart
index e84dce0..551e4a3 100644
--- a/lib/stripe_native_card_field.dart
+++ b/lib/stripe_native_card_field.dart
@@ -59,7 +59,8 @@ class CardTextField extends StatefulWidget {
       assert(stripePublishableKey!.startsWith('pk_'));
       if (kReleaseMode && !stripePublishableKey!.startsWith('pk_live_')) {
         log('StripeNativeCardField: *WARN* You are not using a live publishableKey in production.');
-      } else if ((kDebugMode || kProfileMode) && stripePublishableKey!.startsWith('pk_live_')) {
+      } else if ((kDebugMode || kProfileMode) &&
+          stripePublishableKey!.startsWith('pk_live_')) {
         log('StripeNativeCardField: *WARN* You are using a live stripe key in a debug environment, proceed with caution!');
         log('StripeNativeCardField: *WARN* Ideally you should be using your test keys whenever not in production.');
       }
@@ -198,7 +199,7 @@ class CardTextFieldState extends State<CardTextField> {
 
   String? _validationErrorText;
   bool _showBorderError = false;
-  final _isMobile = Platform.isAndroid || Platform.isIOS;
+  final _isMobile = kIsWeb ? false : Platform.isAndroid || Platform.isIOS;
 
   /// If a request to Stripe is being made
   bool _loading = false;
@@ -220,9 +221,12 @@ class CardTextFieldState extends State<CardTextField> {
 
     // No way to get backspace events on soft keyboards, so add invisible character to detect delete
     _cardNumberController = TextEditingController();
-    _expirationController = TextEditingController(text: _isMobile ? '\u200b' : '');
-    _securityCodeController = TextEditingController(text: _isMobile ? '\u200b' : '');
-    _postalCodeController = TextEditingController(text: _isMobile ? '\u200b' : '');
+    _expirationController =
+        TextEditingController(text: _isMobile ? '\u200b' : '');
+    _securityCodeController =
+        TextEditingController(text: _isMobile ? '\u200b' : '');
+    _postalCodeController =
+        TextEditingController(text: _isMobile ? '\u200b' : '');
 
     // Otherwise, use `RawKeyboard` listener
     if (!_isMobile) {
@@ -234,11 +238,15 @@ class CardTextFieldState extends State<CardTextField> {
     securityCodeFocusNode = FocusNode();
     postalCodeFocusNode = FocusNode();
 
-    _errorTextStyle = const TextStyle(color: Colors.red, fontSize: 14, inherit: true)
-        .merge(widget.errorTextStyle ?? widget.textStyle);
-    _normalTextStyle = const TextStyle(color: Colors.black87, fontSize: 14, inherit: true).merge(widget.textStyle);
-    _hintTextSyle = const TextStyle(color: Colors.black54, fontSize: 14, inherit: true)
-        .merge(widget.hintTextStyle ?? widget.textStyle);
+    _errorTextStyle =
+        const TextStyle(color: Colors.red, fontSize: 14, inherit: true)
+            .merge(widget.errorTextStyle ?? widget.textStyle);
+    _normalTextStyle =
+        const TextStyle(color: Colors.black87, fontSize: 14, inherit: true)
+            .merge(widget.textStyle);
+    _hintTextSyle =
+        const TextStyle(color: Colors.black54, fontSize: 14, inherit: true)
+            .merge(widget.hintTextStyle ?? widget.textStyle);
 
     _normalBoxDecoration = BoxDecoration(
       color: const Color(0xfff6f9fc),
@@ -280,15 +288,31 @@ class CardTextFieldState extends State<CardTextField> {
       _onStepChange,
     );
 
-    isWideFormat =
-        widget.width >= _cardFieldWidth + _expirationFieldWidth + _securityFieldWidth + _postalFieldWidth + 60.0;
+    isWideFormat = widget.width >=
+        _cardFieldWidth +
+            _expirationFieldWidth +
+            _securityFieldWidth +
+            _postalFieldWidth +
+            60.0;
     if (isWideFormat) {
       _internalFieldWidth = widget.width + _postalFieldWidth + 35;
-      _expanderWidthExpanded = widget.width - _cardFieldWidth - _expirationFieldWidth - _securityFieldWidth - 35;
-      _expanderWidthCollapsed =
-          widget.width - _cardFieldWidth - _expirationFieldWidth - _securityFieldWidth - _postalFieldWidth - 70;
+      _expanderWidthExpanded = widget.width -
+          _cardFieldWidth -
+          _expirationFieldWidth -
+          _securityFieldWidth -
+          35;
+      _expanderWidthCollapsed = widget.width -
+          _cardFieldWidth -
+          _expirationFieldWidth -
+          _securityFieldWidth -
+          _postalFieldWidth -
+          70;
     } else {
-      _internalFieldWidth = _cardFieldWidth + _expirationFieldWidth + _securityFieldWidth + _postalFieldWidth + 80;
+      _internalFieldWidth = _cardFieldWidth +
+          _expirationFieldWidth +
+          _securityFieldWidth +
+          _postalFieldWidth +
+          80;
     }
 
     super.initState();
@@ -314,8 +338,10 @@ class CardTextFieldState extends State<CardTextField> {
   @override
   Widget build(BuildContext context) {
     if ((widget.errorText != null || widget.overrideValidState != null) &&
-        Object.hashAll([widget.errorText, widget.overrideValidState]) != _prevErrorOverrideHash) {
-      _prevErrorOverrideHash = Object.hashAll([widget.errorText, widget.overrideValidState]);
+        Object.hashAll([widget.errorText, widget.overrideValidState]) !=
+            _prevErrorOverrideHash) {
+      _prevErrorOverrideHash =
+          Object.hashAll([widget.errorText, widget.overrideValidState]);
       _validateFields();
     }
     return Column(
@@ -332,9 +358,11 @@ class CardTextFieldState extends State<CardTextField> {
             // Enable scrolling on mobile and if its narrow (not all fields visible)
             onHorizontalDragUpdate: (details) {
               const minOffset = 0.0;
-              final maxOffset = _horizontalScrollController.position.maxScrollExtent;
+              final maxOffset =
+                  _horizontalScrollController.position.maxScrollExtent;
               if (!_isMobile || isWideFormat) return;
-              final newOffset = _horizontalScrollController.offset - details.delta.dx;
+              final newOffset =
+                  _horizontalScrollController.offset - details.delta.dx;
 
               if (newOffset < minOffset) {
                 _horizontalScrollController.jumpTo(minOffset);
@@ -345,19 +373,24 @@ class CardTextFieldState extends State<CardTextField> {
               }
             },
             onHorizontalDragEnd: (details) {
-              if (!_isMobile || isWideFormat || details.primaryVelocity == null) return;
+              if (!_isMobile || isWideFormat || details.primaryVelocity == null) {
+                return;
+              }
 
               const dur = Duration(milliseconds: 300);
               const cur = Curves.ease;
 
               // final max = _horizontalScrollController.position.maxScrollExtent;
-              final newOffset = _horizontalScrollController.offset - details.primaryVelocity! * 0.15;
-              _horizontalScrollController.animateTo(newOffset, curve: cur, duration: dur);
+              final newOffset = _horizontalScrollController.offset -
+                  details.primaryVelocity! * 0.15;
+              _horizontalScrollController.animateTo(newOffset,
+                  curve: cur, duration: dur);
             },
             child: Container(
               width: widget.width,
               height: widget.height ?? 60.0,
-              decoration: _showBorderError ? _errorBoxDecoration : _normalBoxDecoration,
+              decoration:
+                  _showBorderError ? _errorBoxDecoration : _normalBoxDecoration,
               child: ClipRect(
                 child: IgnorePointer(
                   child: SingleChildScrollView(
@@ -371,7 +404,8 @@ class CardTextFieldState extends State<CardTextField> {
                         mainAxisAlignment: MainAxisAlignment.start,
                         children: [
                           Padding(
-                            padding: const EdgeInsets.symmetric(horizontal: 6.0),
+                            padding:
+                                const EdgeInsets.symmetric(horizontal: 6.0),
                             child: CardProviderIcon(
                               cardDetails: _cardDetails,
                               size: widget.iconSize,
@@ -398,27 +432,36 @@ class CardTextFieldState extends State<CardTextField> {
                                   return null;
                                 }
                                 _cardDetails.cardNumber = content;
-                                if (_cardDetails.validState == CardDetailsValidState.invalidCard) {
-                                  _setValidationState('Your card number is invalid.');
-                                } else if (_cardDetails.validState == CardDetailsValidState.missingCard) {
-                                  _setValidationState('Your card number is incomplete.');
+                                if (_cardDetails.validState ==
+                                    CardDetailsValidState.invalidCard) {
+                                  _setValidationState(
+                                      'Your card number is invalid.');
+                                } else if (_cardDetails.validState ==
+                                    CardDetailsValidState.missingCard) {
+                                  _setValidationState(
+                                      'Your card number is incomplete.');
                                 }
                                 return null;
                               },
                               onChanged: (str) {
                                 final numbers = str.replaceAll(' ', '');
-                                setState(() => _cardDetails.cardNumber = numbers);
+                                setState(
+                                    () => _cardDetails.cardNumber = numbers);
                                 if (str.length <= _cardDetails.maxINNLength) {
                                   _cardDetails.detectCardProvider();
                                 }
                                 if (numbers.length == 16) {
-                                  _currentCardEntryStepController.add(CardEntryStep.exp);
+                                  _currentCardEntryStepController
+                                      .add(CardEntryStep.exp);
                                 }
                               },
-                              onFieldSubmitted: (_) => _currentCardEntryStepController.add(CardEntryStep.exp),
+                              onFieldSubmitted: (_) =>
+                                  _currentCardEntryStepController
+                                      .add(CardEntryStep.exp),
                               inputFormatters: [
                                 LengthLimitingTextInputFormatter(19),
-                                FilteringTextInputFormatter.allow(RegExp('[0-9 ]')),
+                                FilteringTextInputFormatter.allow(
+                                    RegExp('[0-9 ]')),
                                 CardNumberInputFormatter(),
                               ],
                               decoration: InputDecoration(
@@ -437,13 +480,14 @@ class CardTextFieldState extends State<CardTextField> {
                               child: AnimatedContainer(
                                 curve: Curves.easeInOut,
                                 duration: const Duration(milliseconds: 400),
-                                constraints: _currentStep == CardEntryStep.number
-                                    ? BoxConstraints.loose(
-                                        Size(_expanderWidthExpanded, 0.0),
-                                      )
-                                    : BoxConstraints.tight(
-                                        Size(_expanderWidthCollapsed, 0.0),
-                                      ),
+                                constraints:
+                                    _currentStep == CardEntryStep.number
+                                        ? BoxConstraints.loose(
+                                            Size(_expanderWidthExpanded, 0.0),
+                                          )
+                                        : BoxConstraints.tight(
+                                            Size(_expanderWidthCollapsed, 0.0),
+                                          ),
                               ),
                             ),
 
@@ -454,7 +498,8 @@ class CardTextFieldState extends State<CardTextField> {
                               alignment: Alignment.centerLeft,
                               children: [
                                 // Must manually add hint label because they wont show on mobile with backspace hack
-                                if (_isMobile && _expirationController.text == '\u200b')
+                                if (_isMobile &&
+                                    _expirationController.text == '\u200b')
                                   Text('MM/YY', style: _hintTextSyle),
                                 TextFormField(
                                   key: const Key('expiration_field'),
@@ -470,24 +515,37 @@ class CardTextFieldState extends State<CardTextField> {
                                       ? _errorTextStyle
                                       : _normalTextStyle,
                                   validator: (content) {
-                                    if (content == null || content.isEmpty || _isMobile && content == '\u200b') {
+                                    if (content == null ||
+                                        content.isEmpty ||
+                                        _isMobile && content == '\u200b') {
                                       return null;
                                     }
 
                                     if (_isMobile) {
-                                      setState(() => _cardDetails.expirationString = content.replaceAll('\u200b', ''));
+                                      setState(() =>
+                                          _cardDetails.expirationString =
+                                              content.replaceAll('\u200b', ''));
                                     } else {
-                                      setState(() => _cardDetails.expirationString = content);
+                                      setState(() => _cardDetails
+                                          .expirationString = content);
                                     }
 
-                                    if (_cardDetails.validState == CardDetailsValidState.dateTooEarly) {
-                                      _setValidationState('Your card\'s expiration date is in the past.');
-                                    } else if (_cardDetails.validState == CardDetailsValidState.dateTooLate) {
-                                      _setValidationState('Your card\'s expiration year is invalid.');
-                                    } else if (_cardDetails.validState == CardDetailsValidState.missingDate) {
-                                      _setValidationState('You must include your card\'s expiration date.');
-                                    } else if (_cardDetails.validState == CardDetailsValidState.invalidMonth) {
-                                      _setValidationState('Your card\'s expiration month is invalid.');
+                                    if (_cardDetails.validState ==
+                                        CardDetailsValidState.dateTooEarly) {
+                                      _setValidationState(
+                                          'Your card\'s expiration date is in the past.');
+                                    } else if (_cardDetails.validState ==
+                                        CardDetailsValidState.dateTooLate) {
+                                      _setValidationState(
+                                          'Your card\'s expiration year is invalid.');
+                                    } else if (_cardDetails.validState ==
+                                        CardDetailsValidState.missingDate) {
+                                      _setValidationState(
+                                          'You must include your card\'s expiration date.');
+                                    } else if (_cardDetails.validState ==
+                                        CardDetailsValidState.invalidMonth) {
+                                      _setValidationState(
+                                          'Your card\'s expiration month is invalid.');
                                     }
                                     return null;
                                   },
@@ -496,18 +554,25 @@ class CardTextFieldState extends State<CardTextField> {
                                       if (str.isEmpty) {
                                         _backspacePressed();
                                       }
-                                      setState(() => _cardDetails.expirationString = str.replaceAll('\u200b', ''));
+                                      setState(() =>
+                                          _cardDetails.expirationString =
+                                              str.replaceAll('\u200b', ''));
                                     } else {
-                                      setState(() => _cardDetails.expirationString = str);
+                                      setState(() =>
+                                          _cardDetails.expirationString = str);
                                     }
                                     if (str.length == 5) {
-                                      _currentCardEntryStepController.add(CardEntryStep.cvc);
+                                      _currentCardEntryStepController
+                                          .add(CardEntryStep.cvc);
                                     }
                                   },
-                                  onFieldSubmitted: (_) => _currentCardEntryStepController.add(CardEntryStep.cvc),
+                                  onFieldSubmitted: (_) =>
+                                      _currentCardEntryStepController
+                                          .add(CardEntryStep.cvc),
                                   inputFormatters: [
                                     LengthLimitingTextInputFormatter(5),
-                                    FilteringTextInputFormatter.allow(RegExp('[0-9/]')),
+                                    FilteringTextInputFormatter.allow(
+                                        RegExp('[0-9/]')),
                                     CardExpirationFormatter(),
                                   ],
                                   decoration: InputDecoration(
@@ -526,7 +591,8 @@ class CardTextFieldState extends State<CardTextField> {
                             child: Stack(
                               alignment: Alignment.centerLeft,
                               children: [
-                                if (_isMobile && _securityCodeController.text == '\u200b')
+                                if (_isMobile &&
+                                    _securityCodeController.text == '\u200b')
                                   Text(
                                     'CVC',
                                     style: _hintTextSyle,
@@ -536,47 +602,67 @@ class CardTextFieldState extends State<CardTextField> {
                                   focusNode: securityCodeFocusNode,
                                   controller: _securityCodeController,
                                   keyboardType: TextInputType.number,
-                                  style:
-                                      _isRedText([CardDetailsValidState.invalidCVC, CardDetailsValidState.missingCVC])
-                                          ? _errorTextStyle
-                                          : _normalTextStyle,
+                                  style: _isRedText([
+                                    CardDetailsValidState.invalidCVC,
+                                    CardDetailsValidState.missingCVC
+                                  ])
+                                      ? _errorTextStyle
+                                      : _normalTextStyle,
                                   validator: (content) {
-                                    if (content == null || content.isEmpty || _isMobile && content == '\u200b') {
+                                    if (content == null ||
+                                        content.isEmpty ||
+                                        _isMobile && content == '\u200b') {
                                       return null;
                                     }
 
                                     if (_isMobile) {
-                                      setState(() => _cardDetails.securityCode = content.replaceAll('\u200b', ''));
+                                      setState(() => _cardDetails.securityCode =
+                                          content.replaceAll('\u200b', ''));
                                     } else {
-                                      setState(() => _cardDetails.securityCode = content);
+                                      setState(() =>
+                                          _cardDetails.securityCode = content);
                                     }
 
-                                    if (_cardDetails.validState == CardDetailsValidState.invalidCVC) {
-                                      _setValidationState('Your card\'s security code is invalid.');
-                                    } else if (_cardDetails.validState == CardDetailsValidState.missingCVC) {
-                                      _setValidationState('Your card\'s security code is incomplete.');
+                                    if (_cardDetails.validState ==
+                                        CardDetailsValidState.invalidCVC) {
+                                      _setValidationState(
+                                          'Your card\'s security code is invalid.');
+                                    } else if (_cardDetails.validState ==
+                                        CardDetailsValidState.missingCVC) {
+                                      _setValidationState(
+                                          'Your card\'s security code is incomplete.');
                                     }
                                     return null;
                                   },
-                                  onFieldSubmitted: (_) => _currentCardEntryStepController.add(CardEntryStep.postal),
+                                  onFieldSubmitted: (_) =>
+                                      _currentCardEntryStepController
+                                          .add(CardEntryStep.postal),
                                   onChanged: (str) {
                                     if (_isMobile) {
                                       if (str.isEmpty) {
                                         _backspacePressed();
                                       }
-                                      setState(() => _cardDetails.expirationString = str.replaceAll('\u200b', ''));
+                                      setState(() =>
+                                          _cardDetails.expirationString =
+                                              str.replaceAll('\u200b', ''));
                                     } else {
-                                      setState(() => _cardDetails.expirationString = str);
+                                      setState(() =>
+                                          _cardDetails.expirationString = str);
                                     }
 
-                                    if (str.length == _cardDetails.provider?.cvcLength) {
-                                      _currentCardEntryStepController.add(CardEntryStep.postal);
+                                    if (str.length ==
+                                        _cardDetails.provider?.cvcLength) {
+                                      _currentCardEntryStepController
+                                          .add(CardEntryStep.postal);
                                     }
                                   },
                                   inputFormatters: [
                                     LengthLimitingTextInputFormatter(
-                                        _cardDetails.provider == null ? 4 : _cardDetails.provider!.cvcLength),
-                                    FilteringTextInputFormatter.allow(RegExp('[0-9]')),
+                                        _cardDetails.provider == null
+                                            ? 4
+                                            : _cardDetails.provider!.cvcLength),
+                                    FilteringTextInputFormatter.allow(
+                                        RegExp('[0-9]')),
                                   ],
                                   decoration: InputDecoration(
                                     contentPadding: EdgeInsets.zero,
@@ -594,7 +680,8 @@ class CardTextFieldState extends State<CardTextField> {
                             child: Stack(
                               alignment: Alignment.centerLeft,
                               children: [
-                                if (_isMobile && _postalCodeController.text == '\u200b')
+                                if (_isMobile &&
+                                    _postalCodeController.text == '\u200b')
                                   Text(
                                     'Postal Code',
                                     style: _hintTextSyle,
@@ -604,25 +691,35 @@ class CardTextFieldState extends State<CardTextField> {
                                   focusNode: postalCodeFocusNode,
                                   controller: _postalCodeController,
                                   keyboardType: TextInputType.number,
-                                  style:
-                                      _isRedText([CardDetailsValidState.invalidZip, CardDetailsValidState.missingZip])
-                                          ? _errorTextStyle
-                                          : _normalTextStyle,
+                                  style: _isRedText([
+                                    CardDetailsValidState.invalidZip,
+                                    CardDetailsValidState.missingZip
+                                  ])
+                                      ? _errorTextStyle
+                                      : _normalTextStyle,
                                   validator: (content) {
-                                    if (content == null || content.isEmpty || _isMobile && content == '\u200b') {
+                                    if (content == null ||
+                                        content.isEmpty ||
+                                        _isMobile && content == '\u200b') {
                                       return null;
                                     }
 
                                     if (_isMobile) {
-                                      setState(() => _cardDetails.postalCode = content.replaceAll('\u200b', ''));
+                                      setState(() => _cardDetails.postalCode =
+                                          content.replaceAll('\u200b', ''));
                                     } else {
-                                      setState(() => _cardDetails.postalCode = content);
+                                      setState(() =>
+                                          _cardDetails.postalCode = content);
                                     }
 
-                                    if (_cardDetails.validState == CardDetailsValidState.invalidZip) {
-                                      _setValidationState('The postal code you entered is not correct.');
-                                    } else if (_cardDetails.validState == CardDetailsValidState.missingZip) {
-                                      _setValidationState('You must enter your card\'s postal code.');
+                                    if (_cardDetails.validState ==
+                                        CardDetailsValidState.invalidZip) {
+                                      _setValidationState(
+                                          'The postal code you entered is not correct.');
+                                    } else if (_cardDetails.validState ==
+                                        CardDetailsValidState.missingZip) {
+                                      _setValidationState(
+                                          'You must enter your card\'s postal code.');
                                     }
                                     return null;
                                   },
@@ -631,9 +728,11 @@ class CardTextFieldState extends State<CardTextField> {
                                       if (str.isEmpty) {
                                         _backspacePressed();
                                       }
-                                      setState(() => _cardDetails.postalCode = str.replaceAll('\u200b', ''));
+                                      setState(() => _cardDetails.postalCode =
+                                          str.replaceAll('\u200b', ''));
                                     } else {
-                                      setState(() => _cardDetails.postalCode = str);
+                                      setState(
+                                          () => _cardDetails.postalCode = str);
                                     }
                                   },
                                   textInputAction: TextInputAction.done,
@@ -653,8 +752,12 @@ class CardTextFieldState extends State<CardTextField> {
                           ),
                           AnimatedOpacity(
                             duration: const Duration(milliseconds: 300),
-                            opacity: _loading && widget.showInternalLoadingWidget ? 1.0 : 0.0,
-                            child: widget.loadingWidget ?? const CircularProgressIndicator(),
+                            opacity:
+                                _loading && widget.showInternalLoadingWidget
+                                    ? 1.0
+                                    : 0.0,
+                            child: widget.loadingWidget ??
+                                const CircularProgressIndicator(),
                           ),
                         ],
                       ),
@@ -762,14 +865,20 @@ class CardTextFieldState extends State<CardTextField> {
         _horizontalScrollController.animateTo(0.0, duration: dur, curve: cur);
         break;
       case CardEntryStep.exp:
-        _horizontalScrollController.animateTo(_cardFieldWidth / 2, duration: dur, curve: cur);
+        _horizontalScrollController.animateTo(_cardFieldWidth / 2,
+            duration: dur, curve: cur);
         break;
       case CardEntryStep.cvc:
-        _horizontalScrollController.animateTo(_cardFieldWidth / 2 + _expirationFieldWidth, duration: dur, curve: cur);
+        _horizontalScrollController.animateTo(
+            _cardFieldWidth / 2 + _expirationFieldWidth,
+            duration: dur,
+            curve: cur);
         break;
       case CardEntryStep.postal:
-        _horizontalScrollController.animateTo(_cardFieldWidth / 2 + _expirationFieldWidth + _securityFieldWidth,
-            duration: dur, curve: cur);
+        _horizontalScrollController.animateTo(
+            _cardFieldWidth / 2 + _expirationFieldWidth + _securityFieldWidth,
+            duration: dur,
+            curve: cur);
         break;
     }
   }
@@ -842,11 +951,11 @@ class CardTextFieldState extends State<CardTextField> {
       case CardEntryStep.number:
         break;
       case CardEntryStep.exp:
-        if (_expirationController.text.isNotEmpty) break;
+        if (_expirationController.text.isNotEmpty) return;
       case CardEntryStep.cvc:
-        if (_securityCodeController.text.isNotEmpty) break;
+        if (_securityCodeController.text.isNotEmpty) return;
       case CardEntryStep.postal:
-        if (_postalCodeController.text.isNotEmpty) break;
+        if (_postalCodeController.text.isNotEmpty) return;
     }
     _transitionStepFocus();
   }
@@ -893,7 +1002,8 @@ class CardTextFieldState extends State<CardTextField> {
 /// to make the card number display cleanly.
 class CardNumberInputFormatter implements TextInputFormatter {
   @override
-  TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
+  TextEditingValue formatEditUpdate(
+      TextEditingValue oldValue, TextEditingValue newValue) {
     String cardNum = newValue.text;
     if (cardNum.length <= 4) return newValue;
 
@@ -908,7 +1018,9 @@ class CardNumberInputFormatter implements TextInputFormatter {
       }
     }
 
-    return newValue.copyWith(text: buffer.toString(), selection: TextSelection.collapsed(offset: buffer.length));
+    return newValue.copyWith(
+        text: buffer.toString(),
+        selection: TextSelection.collapsed(offset: buffer.length));
   }
 }
 
@@ -916,7 +1028,8 @@ class CardNumberInputFormatter implements TextInputFormatter {
 /// the month and the year for the expiration date.
 class CardExpirationFormatter implements TextInputFormatter {
   @override
-  TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
+  TextEditingValue formatEditUpdate(
+      TextEditingValue oldValue, TextEditingValue newValue) {
     String cardExp = newValue.text;
     if (cardExp.length == 1) {
       if (cardExp[0] == '0' || cardExp[0] == '1') {
@@ -937,6 +1050,8 @@ class CardExpirationFormatter implements TextInputFormatter {
         buffer.write('/');
       }
     }
-    return newValue.copyWith(text: buffer.toString(), selection: TextSelection.collapsed(offset: buffer.length));
+    return newValue.copyWith(
+        text: buffer.toString(),
+        selection: TextSelection.collapsed(offset: buffer.length));
   }
 }
diff --git a/test/stripe_native_card_field_test.dart b/test/stripe_native_card_field_test.dart
index 1dcd74d..0e451dc 100644
--- a/test/stripe_native_card_field_test.dart
+++ b/test/stripe_native_card_field_test.dart
@@ -24,7 +24,8 @@ void main() {
 
       final input = TestTextInput();
 
-      final cardState = tester.state(find.byType(CardTextField)) as CardTextFieldState;
+      final cardState =
+          tester.state(find.byType(CardTextField)) as CardTextFieldState;
 
       assertEmptyTextFields(tester, cardState.isWideFormat);
 
@@ -47,7 +48,8 @@ void main() {
       await tester.pump();
 
       expect(getTextFormField(expirationFieldKey).controller?.text, '');
-      expect(getTextFormField(cardFieldKey).controller?.text, '4242 4242 4242 424');
+      expect(getTextFormField(cardFieldKey).controller?.text,
+          '4242 4242 4242 424');
       expect(cardState.cardNumberFocusNode.hasFocus, true);
       expect(cardState.expirationFocusNode.hasFocus, false);
       // Postal code should now be gone
@@ -58,7 +60,8 @@ void main() {
       input.enterText("4242424242424242");
       await tester.pump();
 
-      expect(getTextFormField(cardFieldKey).controller?.text, '4242 4242 4242 4242');
+      expect(getTextFormField(cardFieldKey).controller?.text,
+          '4242 4242 4242 4242');
       expect(cardState.cardNumberFocusNode.hasFocus, false);
       expect(cardState.expirationFocusNode.hasFocus, true);
       // Postal code should move back into view
@@ -90,7 +93,10 @@ void main() {
       await tester.pump();
 
       final expectedCardDetails = CardDetails(
-          cardNumber: '4242 4242 4242 4242', securityCode: '333', expirationString: '10/28', postalCode: '91555');
+          cardNumber: '4242 4242 4242 4242',
+          securityCode: '333',
+          expirationString: '10/28',
+          postalCode: '91555');
       // print('${expectedCardDetails.toString()}\n${details?.toString()}');
       expect(details?.hash, expectedCardDetails.hash);
     },
@@ -110,7 +116,8 @@ void main() {
 
     final input = TestTextInput();
 
-    final cardState = tester.state(find.byType(CardTextField)) as CardTextFieldState;
+    final cardState =
+        tester.state(find.byType(CardTextField)) as CardTextFieldState;
 
     assertEmptyTextFields(tester, cardState.isWideFormat);
 
@@ -135,7 +142,8 @@ void main() {
     input.enterText('0055');
     await tester.pump();
 
-    expect(find.text("Your card's expiration month is invalid."), findsOneWidget);
+    expect(
+        find.text("Your card's expiration month is invalid."), findsOneWidget);
 
     await tester.sendKeyDownEvent(LogicalKeyboardKey.backspace);
     await tester.pump();
@@ -145,7 +153,8 @@ void main() {
     input.enterText('1099');
     await tester.pump();
 
-    expect(find.text("Your card's expiration year is invalid."), findsOneWidget);
+    expect(
+        find.text("Your card's expiration year is invalid."), findsOneWidget);
 
     await tester.sendKeyDownEvent(LogicalKeyboardKey.backspace);
     await tester.pump();
@@ -169,7 +178,8 @@ void main() {
     await input.receiveAction(TextInputAction.done);
     await tester.pump();
 
-    expect(find.text("The postal code you entered is not correct."), findsOneWidget);
+    expect(find.text("The postal code you entered is not correct."),
+        findsOneWidget);
 
     await tester.tap(find.byType(CardTextField));
 
@@ -182,7 +192,10 @@ void main() {
     await tester.pump();
 
     final expectedCardDetails = CardDetails(
-        cardNumber: '4242 4242 4242 4242', expirationString: '02/28', securityCode: '123', postalCode: '12345');
+        cardNumber: '4242 4242 4242 4242',
+        expirationString: '02/28',
+        securityCode: '123',
+        postalCode: '12345');
 
     expect(details?.hash, expectedCardDetails.hash);
   });
@@ -209,7 +222,8 @@ void assertEmptyTextFields(WidgetTester tester, bool isWideFormat) {
   // expect(find.text("Postal Code"), findsNothing);
 }
 
-Future<void> enterTextByKey(WidgetTester tester, {required String key, required String text}) async {
+Future<void> enterTextByKey(WidgetTester tester,
+    {required String key, required String text}) async {
   await tester.enterText(find.byKey(ValueKey(key)), text);
 }